1 //
2 // winapi_thunks.cpp
3 //
4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //
6 // Definitions of wrappers for Windows API functions that cannot be called
7 // directly because they are not available on all supported operating systems.
8 //
9
10 #include <nt.h>
11 #include <ntrtl.h>
12 #include <nturtl.h>
13 #include <ntsecapi.h>
14 #include <corecrt_internal.h>
15 #include <appmodel.h>
16 #include <roapi.h>
17
18 // This is simlar to msvcrt.
19 #if _M_AMD64 || _M_ARM || _M_ARM64 || _M_HYBRID
20 #define FLS_ALWAYS_AVAILABLE 1
21 #endif
22
23 WINBASEAPI
24 _Success_(return > 0 && return < BufferLength)
25 DWORD
26 WINAPI
27 GetTempPath2W(
28 _In_ DWORD BufferLength,
29 _Out_writes_to_opt_(BufferLength,return + 1) LPWSTR Buffer
30 );
31
32 // The XState APIs are declared by the Windows headers only when building for
33 // x86 and x64. We declare them here unconditionally so that we can share the
34 // same code for all architectures (we simply avoid use of these functions on
35 // other architectures).
36 extern "C" WINBASEAPI DWORD64 WINAPI GetEnabledXStateFeatures();
37
38 _Must_inspect_result_
39 extern "C" WINBASEAPI BOOL WINAPI GetXStateFeaturesMask(
40 _In_ PCONTEXT context,
41 _Out_ PDWORD64 feature_mask
42 );
43
44 _Success_(return != NULL)
45 extern "C" WINBASEAPI PVOID WINAPI LocateXStateFeature(
46 _In_ PCONTEXT context,
47 _In_ DWORD feature_id,
48 _Out_opt_ PDWORD length
49 );
50
51 #define _ACRT_APPLY_TO_LATE_BOUND_MODULES_0 \
52 _APPLY(api_ms_win_core_datetime_l1_1_1, "api-ms-win-core-datetime-l1-1-1" ) \
53 _APPLY(api_ms_win_core_file_l1_2_4, "api-ms-win-core-file-l1-2-4" ) \
54 _APPLY(api_ms_win_core_file_l1_2_2, "api-ms-win-core-file-l1-2-2" ) \
55 _APPLY(api_ms_win_core_localization_l1_2_1, "api-ms-win-core-localization-l1-2-1" ) \
56 _APPLY(api_ms_win_core_localization_obsolete_l1_2_0, "api-ms-win-core-localization-obsolete-l1-2-0") \
57 _APPLY(api_ms_win_core_processthreads_l1_1_2, "api-ms-win-core-processthreads-l1-1-2" ) \
58 _APPLY(api_ms_win_core_string_l1_1_0, "api-ms-win-core-string-l1-1-0" ) \
59 _APPLY(api_ms_win_core_synch_l1_2_0, "api-ms-win-core-synch-l1-2-0" ) \
60 _APPLY(api_ms_win_core_sysinfo_l1_2_1, "api-ms-win-core-sysinfo-l1-2-1" ) \
61 _APPLY(api_ms_win_core_winrt_l1_1_0, "api-ms-win-core-winrt-l1-1-0" ) \
62 _APPLY(api_ms_win_core_xstate_l2_1_0, "api-ms-win-core-xstate-l2-1-0" ) \
63 _APPLY(api_ms_win_rtcore_ntuser_window_l1_1_0, "api-ms-win-rtcore-ntuser-window-l1-1-0" ) \
64 _APPLY(api_ms_win_security_systemfunctions_l1_1_0, "api-ms-win-security-systemfunctions-l1-1-0" ) \
65 _APPLY(ext_ms_win_ntuser_dialogbox_l1_1_0, "ext-ms-win-ntuser-dialogbox-l1-1-0" ) \
66 _APPLY(ext_ms_win_ntuser_windowstation_l1_1_0, "ext-ms-win-ntuser-windowstation-l1-1-0" ) \
67 _APPLY(advapi32, "advapi32" ) \
68 _APPLY(kernel32, "kernel32" ) \
69 _APPLY(kernelbase, "kernelbase" ) \
70 _APPLY(ntdll, "ntdll" ) \
71 _APPLY(api_ms_win_appmodel_runtime_l1_1_2, "api-ms-win-appmodel-runtime-l1-1-2" ) \
72 _APPLY(user32, "user32" )
73
74 #if FLS_ALWAYS_AVAILABLE
75
76 #define _ACRT_APPLY_TO_LATE_BOUND_MODULES_1 /* nothing */
77
78 #else
79
80 #define _ACRT_APPLY_TO_LATE_BOUND_MODULES_1 \
81 _APPLY(api_ms_win_core_fibers_l1_1_0, "api-ms-win-core-fibers-l1-1-0" )
82
83 #endif
84
85 #define _ACRT_APPLY_TO_LATE_BOUND_MODULES \
86 _ACRT_APPLY_TO_LATE_BOUND_MODULES_0 \
87 _ACRT_APPLY_TO_LATE_BOUND_MODULES_1 \
88
89 #define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_0 \
90 _APPLY(AreFileApisANSI, ({ /* api_ms_win_core_file_l1_2_2, */ kernel32 })) \
91 _APPLY(CompareStringEx, ({ api_ms_win_core_string_l1_1_0, kernel32 })) \
92 _APPLY(EnumSystemLocalesEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
93 _APPLY(GetActiveWindow, ({ api_ms_win_rtcore_ntuser_window_l1_1_0, user32 })) \
94 _APPLY(GetDateFormatEx, ({ api_ms_win_core_datetime_l1_1_1, kernel32 })) \
95 _APPLY(GetTempPath2W, ({ api_ms_win_core_file_l1_2_4, kernelbase })) \
96 _APPLY(GetEnabledXStateFeatures, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
97 _APPLY(GetLastActivePopup, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
98 _APPLY(GetLocaleInfoEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
99 _APPLY(GetProcessWindowStation, ({ ext_ms_win_ntuser_windowstation_l1_1_0, user32 })) \
100 _APPLY(GetSystemTimePreciseAsFileTime, ({ api_ms_win_core_sysinfo_l1_2_1 })) \
101 _APPLY(GetTimeFormatEx, ({ api_ms_win_core_datetime_l1_1_1, kernel32 })) \
102 _APPLY(GetUserDefaultLocaleName, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
103 _APPLY(GetUserObjectInformationW, ({ ext_ms_win_ntuser_windowstation_l1_1_0, user32 })) \
104 _APPLY(GetXStateFeaturesMask, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
105 _APPLY(InitializeCriticalSectionEx, ({ api_ms_win_core_synch_l1_2_0, kernel32 })) \
106 _APPLY(IsValidLocaleName, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
107 _APPLY(LCMapStringEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
108 _APPLY(LCIDToLocaleName, ({ api_ms_win_core_localization_obsolete_l1_2_0, kernel32 })) \
109 _APPLY(LocaleNameToLCID, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
110 _APPLY(LocateXStateFeature, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
111 _APPLY(MessageBoxA, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
112 _APPLY(MessageBoxW, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
113 _APPLY(RoInitialize, ({ api_ms_win_core_winrt_l1_1_0 })) \
114 _APPLY(RoUninitialize, ({ api_ms_win_core_winrt_l1_1_0 })) \
115 _APPLY(AppPolicyGetProcessTerminationMethod, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
116 _APPLY(AppPolicyGetThreadInitializationType, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
117 _APPLY(AppPolicyGetShowDeveloperDiagnostic, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
118 _APPLY(AppPolicyGetWindowingModel, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
119 _APPLY(SetThreadStackGuarantee, ({ api_ms_win_core_processthreads_l1_1_2, kernel32 })) \
120 _APPLY(SystemFunction036, ({ api_ms_win_security_systemfunctions_l1_1_0, advapi32 }))
121
122 #if FLS_ALWAYS_AVAILABLE
123
124 #define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 /* nothing */
125
126 #else
127
128 #define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 \
129 _APPLY(FlsAlloc, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
130 _APPLY(FlsFree, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
131 _APPLY(FlsGetValue, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
132 _APPLY(FlsSetValue, ({ api_ms_win_core_fibers_l1_1_0, kernel32 }))
133
134 #endif
135
136 #define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS \
137 _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_0 \
138 _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 \
139
140 namespace
141 {
142 // Generate enumerators for each of the modules:
143 enum module_id : unsigned
144 {
145 #define _APPLY(_SYMBOL, _NAME) _SYMBOL,
146 _ACRT_APPLY_TO_LATE_BOUND_MODULES
147 #undef _APPLY
148
149 module_id_count
150 };
151
152 // Generate a table of module names that can be indexed by the module_id
153 // enumerators:
154 static wchar_t const* const module_names[module_id_count] =
155 {
156 #define _APPLY(_SYMBOL, _NAME) _CRT_WIDE(_NAME),
157 _ACRT_APPLY_TO_LATE_BOUND_MODULES
158 #undef _APPLY
159 };
160
161 // Generate enumerators for each of the functions:
162 enum function_id : unsigned
163 {
164 #define _APPLY(_FUNCTION, _MODULES) _CRT_CONCATENATE(_FUNCTION, _id),
165 _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
166 #undef _APPLY
167
168 function_id_count
169 };
170
171 // Generate a typedef for each function of the form function_pft.
172 #define _APPLY(_FUNCTION, _MODULES) \
173 using _CRT_CONCATENATE(_FUNCTION, _pft) = decltype(_FUNCTION)*;
174 _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
175 #undef _APPLY
176 }
177
178 // This table stores the module handles that we have obtained via LoadLibrary.
179 // If a handle is null, we have not yet attempted to load that module. If a
180 // handle is -1 (INVALID_HANDLE_VALUE), we have attempted to load the module
181 // but the attempt failed.
182 static HMODULE module_handles[module_id_count];
183
184 // This table stores the function pointers that we have loaded dynamically. The
185 // function pointers are stored in encoded form via __crt_fast_encode_ponter. If
186 // a function pointer is an encoded null pointer, we have not yet attempted to
187 // get that function pointer. If a function pointer is an encoded -1, we have
188 // attempted to get that function pointer but the attempt failed.
189 static void* encoded_function_pointers[function_id_count];
190
__acrt_initialize_winapi_thunks()191 extern "C" bool __cdecl __acrt_initialize_winapi_thunks()
192 {
193 void* const encoded_nullptr = __crt_fast_encode_pointer(nullptr);
194
195 for (void*& p : encoded_function_pointers)
196 {
197 p = encoded_nullptr;
198 }
199
200 return true;
201 }
202
__acrt_uninitialize_winapi_thunks(bool const terminating)203 extern "C" bool __cdecl __acrt_uninitialize_winapi_thunks(bool const terminating)
204 {
205 // If the process is terminating, there's no need to free any module handles
206 if (terminating)
207 {
208 return true;
209 }
210
211 for (HMODULE& module : module_handles)
212 {
213 if (module)
214 {
215 if (module != INVALID_HANDLE_VALUE)
216 {
217 FreeLibrary(module);
218 }
219
220 module = nullptr;
221 }
222 }
223
224 return true;
225 }
226
invalid_function_sentinel()227 static __forceinline void* __cdecl invalid_function_sentinel() throw()
228 {
229 return reinterpret_cast<void*>(static_cast<uintptr_t>(-1));
230 }
231
try_load_library_from_system_directory(wchar_t const * const name)232 static HMODULE __cdecl try_load_library_from_system_directory(wchar_t const* const name) throw()
233 {
234 HMODULE const handle = LoadLibraryExW(name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
235 if (handle)
236 {
237 return handle;
238 }
239
240 // LOAD_LIBRARY_SEARCH_SYSTEM32 is only supported by Windows 7 and above; if
241 // the OS does not support this flag, try again without it. On these OSes,
242 // all APISets will be forwarders. To prevent DLL hijacking, do not attempt
243 // to load the APISet forwarders dynamically. This will cause our caller to
244 // fall back to the real DLL (e.g. kernel32). All of those are known DLLs.
245 if (GetLastError() == ERROR_INVALID_PARAMETER &&
246 wcsncmp(name, L"api-ms-", 7) != 0 &&
247 wcsncmp(name, L"ext-ms-", 7) != 0)
248 {
249 return LoadLibraryExW(name, nullptr, 0);
250 }
251
252 return nullptr;
253 }
254
try_get_module(module_id const id)255 static HMODULE __cdecl try_get_module(module_id const id) throw()
256 {
257 // First check to see if we've cached the module handle:
258 if (HMODULE const cached_handle = __crt_interlocked_read_pointer(module_handles + id))
259 {
260 if (cached_handle == INVALID_HANDLE_VALUE)
261 {
262 return nullptr;
263 }
264
265 return cached_handle;
266 }
267
268 // If we haven't yet cached the module handle, try to load the library. If
269 // this fails, cache the sentinel handle value INVALID_HANDLE_VALUE so that
270 // we don't attempt to load the module again:
271 HMODULE const new_handle = try_load_library_from_system_directory(module_names[id]);
272 if (!new_handle)
273 {
274 if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(module_handles + id, INVALID_HANDLE_VALUE))
275 {
276 _ASSERTE(cached_handle == INVALID_HANDLE_VALUE);
277 }
278
279 return nullptr;
280 }
281
282 // Swap the new handle into the cache. If the cache no longer contained a
283 // null handle, then some other thread loaded the module and cached the
284 // handle while we were doing the same. In that case, we free the handle
285 // once to maintain the reference count:
286 if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(module_handles + id, new_handle))
287 {
288 _ASSERTE(cached_handle == new_handle);
289 FreeLibrary(new_handle);
290 }
291
292 return new_handle;
293 }
294
try_get_first_available_module(module_id const * const first,module_id const * const last)295 static HMODULE __cdecl try_get_first_available_module(
296 module_id const* const first,
297 module_id const* const last
298 ) throw()
299 {
300 for (module_id const* it = first; it != last; ++it)
301 {
302 HMODULE const handle = try_get_module(*it);
303 if (handle)
304 {
305 return handle;
306 }
307 }
308
309 return nullptr;
310 }
311
try_get_proc_address_from_first_available_module(char const * const name,module_id const * const first_module_id,module_id const * const last_module_id)312 static __forceinline void* __cdecl try_get_proc_address_from_first_available_module(
313 char const* const name,
314 module_id const* const first_module_id,
315 module_id const* const last_module_id
316 ) throw()
317 {
318 HMODULE const module_handle = try_get_first_available_module(first_module_id, last_module_id);
319 if (!module_handle)
320 {
321 return nullptr;
322 }
323
324 return reinterpret_cast<void*>(GetProcAddress(module_handle, name));
325 }
326
try_get_function(function_id const id,char const * const name,module_id const * const first_module_id,module_id const * const last_module_id)327 static void* __cdecl try_get_function(
328 function_id const id,
329 char const* const name,
330 module_id const* const first_module_id,
331 module_id const* const last_module_id
332 ) throw()
333 {
334 // First check to see if we've cached the function pointer:
335 {
336 void* const cached_fp = __crt_fast_decode_pointer(
337 __crt_interlocked_read_pointer(encoded_function_pointers + id));
338
339 if (cached_fp == invalid_function_sentinel())
340 {
341 return nullptr;
342 }
343
344 if (cached_fp)
345 {
346 return cached_fp;
347 }
348 }
349
350 // If we haven't yet cached the function pointer, try to import it from any
351 // of the modules in which it might be defined. If this fails, cache the
352 // sentinel pointer so that we don't attempt to load this function again:
353 void* const new_fp = try_get_proc_address_from_first_available_module(name, first_module_id, last_module_id);
354 if (!new_fp)
355 {
356 void* const cached_fp = __crt_fast_decode_pointer(
357 __crt_interlocked_exchange_pointer(
358 encoded_function_pointers + id,
359 __crt_fast_encode_pointer(invalid_function_sentinel())));
360
361 if (cached_fp)
362 {
363 _ASSERTE(cached_fp == invalid_function_sentinel());
364 }
365
366 return nullptr;
367 }
368
369 // Swap the newly obtained function pointer into the cache. The cache may
370 // no longer contain an encoded null pointer if another thread obtained the
371 // function address while we were doing the same (both threads should have
372 // gotten the same function pointer):
373 {
374 void* const cached_fp = __crt_fast_decode_pointer(
375 __crt_interlocked_exchange_pointer(
376 encoded_function_pointers + id,
377 __crt_fast_encode_pointer(new_fp)));
378
379 if (cached_fp)
380 {
381 _ASSERTE(cached_fp == new_fp);
382 }
383 }
384
385 return new_fp;
386 }
387
388 // Generate accessors that wrap the general try_get_function for each function,
389 // passing the correct set of candidate modules and returning a function pointer
390 // of the correct type:
391 #define _APPLY(_FUNCTION, _MODULES) \
392 static _CRT_CONCATENATE(_FUNCTION, _pft) __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() throw() \
393 { \
394 static module_id const candidate_modules[] = _CRT_UNPARENTHESIZE(_MODULES); \
395 \
396 return reinterpret_cast<_CRT_CONCATENATE(_FUNCTION, _pft)>(try_get_function( \
397 _CRT_CONCATENATE(_FUNCTION, _id), \
398 _CRT_STRINGIZE(_FUNCTION), \
399 candidate_modules, \
400 candidate_modules + _countof(candidate_modules))); \
401 }
402 _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
403 #undef _APPLY
404
__acrt_AreFileApisANSI()405 extern "C" BOOL WINAPI __acrt_AreFileApisANSI()
406 {
407 if (auto const are_file_apis_ansi = try_get_AreFileApisANSI())
408 {
409 return are_file_apis_ansi();
410 }
411
412 // If we were unable to get the AreFileApisANSI function, we can safely
413 // assume that the file APIs are, in fact, ANSI:
414 return TRUE;
415 }
416
__acrt_CompareStringEx(LPCWSTR const locale_name,DWORD const flags,LPCWCH const string1,int const string1_count,LPCWCH const string2,int const string2_count,LPNLSVERSIONINFO const version,LPVOID const reserved,LPARAM const param)417 extern "C" int WINAPI __acrt_CompareStringEx(
418 LPCWSTR const locale_name,
419 DWORD const flags,
420 LPCWCH const string1,
421 int const string1_count,
422 LPCWCH const string2,
423 int const string2_count,
424 LPNLSVERSIONINFO const version,
425 LPVOID const reserved,
426 LPARAM const param
427 )
428 {
429 if (auto const compare_string_ex = try_get_CompareStringEx())
430 {
431 // On WCOS devices, CompareStringEx may calls into icu.dll which is an OS component using the UCRT.
432 // If icu.dll calls any UCRT export under OS mode (ex: malloc), then CompareStringEx will return under Prog Mode even if
433 // we started in OS mode. To prevent this, an OS mode guard is in place.
434 __crt_state_management::scoped_global_state_reset os_mode_guard;
435 return compare_string_ex(locale_name, flags, string1, string1_count, string2, string2_count, version, reserved, param);
436 }
437
438 return CompareStringW(__acrt_LocaleNameToLCID(locale_name, 0), flags, string1, string1_count, string2, string2_count);
439 }
440
441 #ifdef __clang__
442 static LOCALE_ENUMPROCEX static_enum_proc;
LocaleEnumProcW(LPWSTR locale_string)443 static BOOL CALLBACK LocaleEnumProcW(LPWSTR locale_string)
444 {
445 return __crt_fast_decode_pointer(static_enum_proc)(locale_string, 0, 0);
446 }
447 #endif
448
449 // This has been split into its own function to work around a bug in the Dev12
450 // C++ compiler where nested captureless lambdas are not convertible to the
451 // required function pointer type.
enum_system_locales_ex_nolock(LOCALE_ENUMPROCEX const enum_proc)452 static BOOL enum_system_locales_ex_nolock(
453 LOCALE_ENUMPROCEX const enum_proc
454 ) throw()
455 {
456 #ifndef __clang__
457 static LOCALE_ENUMPROCEX static_enum_proc;
458 #endif
459
460 static_enum_proc = __crt_fast_encode_pointer(enum_proc);
461 BOOL const result = EnumSystemLocalesW((LOCALE_ENUMPROCW)
462 #ifdef __clang__
463 LocaleEnumProcW,
464 #else
465 [](LPWSTR locale_string)
466 #if defined(__GNUC__) && !defined(__clang__)
467 __stdcall
468 #endif // __GNUC__
469 { return __crt_fast_decode_pointer(static_enum_proc)(locale_string, 0, 0); },
470 #endif
471 LCID_INSTALLED);
472 static_enum_proc = __crt_fast_encode_pointer(nullptr);
473
474 return result;
475 }
476
__acrt_EnumSystemLocalesEx(LOCALE_ENUMPROCEX const enum_proc,DWORD const flags,LPARAM const param,LPVOID const reserved)477 extern "C" BOOL WINAPI __acrt_EnumSystemLocalesEx(
478 LOCALE_ENUMPROCEX const enum_proc,
479 DWORD const flags,
480 LPARAM const param,
481 LPVOID const reserved
482 )
483 {
484 if (auto const enum_system_locales_ex = try_get_EnumSystemLocalesEx())
485 {
486 return enum_system_locales_ex(enum_proc, flags, param, reserved);
487 }
488
489 return __acrt_lock_and_call(__acrt_locale_lock, [&]() -> BOOL
490 {
491 return enum_system_locales_ex_nolock(enum_proc);
492 });
493 }
494
__acrt_FlsAlloc(PFLS_CALLBACK_FUNCTION const callback)495 extern "C" DWORD WINAPI __acrt_FlsAlloc(PFLS_CALLBACK_FUNCTION const callback)
496 {
497 #if FLS_ALWAYS_AVAILABLE
498 return FlsAlloc(callback);
499 #else
500 if (auto const fls_alloc = try_get_FlsAlloc())
501 {
502 return fls_alloc(callback);
503 }
504
505 return TlsAlloc();
506 #endif
507 }
508
__acrt_FlsFree(DWORD const fls_index)509 extern "C" BOOL WINAPI __acrt_FlsFree(DWORD const fls_index)
510 {
511 #if FLS_ALWAYS_AVAILABLE
512 return FlsFree(fls_index);
513 #else
514 if (auto const fls_free = try_get_FlsFree())
515 {
516 return fls_free(fls_index);
517 }
518
519 return TlsFree(fls_index);
520 #endif
521 }
522
__acrt_FlsGetValue(DWORD const fls_index)523 extern "C" PVOID WINAPI __acrt_FlsGetValue(DWORD const fls_index)
524 {
525 #if FLS_ALWAYS_AVAILABLE
526 return FlsGetValue(fls_index);
527 #else
528 if (auto const fls_get_value = try_get_FlsGetValue())
529 {
530 return fls_get_value(fls_index);
531 }
532
533 return TlsGetValue(fls_index);
534 #endif
535 }
536
__acrt_FlsSetValue(DWORD const fls_index,PVOID const fls_data)537 extern "C" BOOL WINAPI __acrt_FlsSetValue(DWORD const fls_index, PVOID const fls_data)
538 {
539 #if FLS_ALWAYS_AVAILABLE
540 return FlsSetValue(fls_index, fls_data);
541 #else
542 if (auto const fls_set_value = try_get_FlsSetValue())
543 {
544 return fls_set_value(fls_index, fls_data);
545 }
546
547 return TlsSetValue(fls_index, fls_data);
548 #endif
549 }
550
__acrt_GetDateFormatEx(LPCWSTR const locale_name,DWORD const flags,SYSTEMTIME CONST * const date,LPCWSTR const format,LPWSTR const buffer,int const buffer_count,LPCWSTR const calendar)551 extern "C" int WINAPI __acrt_GetDateFormatEx(
552 LPCWSTR const locale_name,
553 DWORD const flags,
554 SYSTEMTIME CONST* const date,
555 LPCWSTR const format,
556 LPWSTR const buffer,
557 int const buffer_count,
558 LPCWSTR const calendar
559 )
560 {
561 if (auto const get_date_format_ex = try_get_GetDateFormatEx())
562 {
563 return get_date_format_ex(locale_name, flags, date, format, buffer, buffer_count, calendar);
564 }
565
566 return GetDateFormatW(__acrt_LocaleNameToLCID(locale_name, 0), flags, date, format, buffer, buffer_count);
567 }
568
__acrt_GetTempPath2W(DWORD nBufferLength,LPWSTR lpBuffer)569 extern "C" int WINAPI __acrt_GetTempPath2W(
570 DWORD nBufferLength,
571 LPWSTR lpBuffer
572 )
573 {
574 if (auto const get_temp_path2w = try_get_GetTempPath2W())
575 {
576 return get_temp_path2w(nBufferLength, lpBuffer);
577 }
578 return GetTempPathW(nBufferLength, lpBuffer);
579 }
580
__acrt_GetEnabledXStateFeatures()581 extern "C" DWORD64 WINAPI __acrt_GetEnabledXStateFeatures()
582 {
583 if (auto const get_enabled_xstate_features = try_get_GetEnabledXStateFeatures())
584 {
585 return get_enabled_xstate_features();
586 }
587
588 abort(); // No fallback; callers should check availablility before calling
589 }
590
__acrt_GetLocaleInfoEx(LPCWSTR const locale_name,LCTYPE const lc_type,LPWSTR const data,int const data_count)591 extern "C" int WINAPI __acrt_GetLocaleInfoEx(
592 LPCWSTR const locale_name,
593 LCTYPE const lc_type,
594 LPWSTR const data,
595 int const data_count
596 )
597 {
598 if (auto const get_locale_info_ex = try_get_GetLocaleInfoEx())
599 {
600 return get_locale_info_ex(locale_name, lc_type, data, data_count);
601 }
602
603 return GetLocaleInfoW(__acrt_LocaleNameToLCID(locale_name, 0), lc_type, data, data_count);
604 }
605
__acrt_GetSystemTimePreciseAsFileTime(LPFILETIME const system_time)606 extern "C" VOID WINAPI __acrt_GetSystemTimePreciseAsFileTime(LPFILETIME const system_time)
607 {
608 if (auto const get_system_time_precise_as_file_time = try_get_GetSystemTimePreciseAsFileTime())
609 {
610 return get_system_time_precise_as_file_time(system_time);
611 }
612
613 return GetSystemTimeAsFileTime(system_time);
614 }
615
__acrt_GetTimeFormatEx(LPCWSTR const locale_name,DWORD const flags,SYSTEMTIME CONST * const time,LPCWSTR const format,LPWSTR const buffer,int const buffer_count)616 extern "C" int WINAPI __acrt_GetTimeFormatEx(
617 LPCWSTR const locale_name,
618 DWORD const flags,
619 SYSTEMTIME CONST* const time,
620 LPCWSTR const format,
621 LPWSTR const buffer,
622 int const buffer_count
623 )
624 {
625 if (auto const get_time_format_ex = try_get_GetTimeFormatEx())
626 {
627 return get_time_format_ex(locale_name, flags, time, format, buffer, buffer_count);
628 }
629
630 return GetTimeFormatW(__acrt_LocaleNameToLCID(locale_name, 0), flags, time, format, buffer, buffer_count);
631 }
632
__acrt_GetUserDefaultLocaleName(LPWSTR const locale_name,int const locale_name_count)633 extern "C" int WINAPI __acrt_GetUserDefaultLocaleName(
634 LPWSTR const locale_name,
635 int const locale_name_count
636 )
637 {
638 if (auto const get_user_default_locale_name = try_get_GetUserDefaultLocaleName())
639 {
640 return get_user_default_locale_name(locale_name, locale_name_count);
641 }
642
643 return __acrt_LCIDToLocaleName(GetUserDefaultLCID(), locale_name, locale_name_count, 0);
644 }
645
__acrt_GetXStateFeaturesMask(PCONTEXT const context,PDWORD64 const feature_mask)646 extern "C" BOOL WINAPI __acrt_GetXStateFeaturesMask(
647 PCONTEXT const context,
648 PDWORD64 const feature_mask
649 )
650 {
651 if (auto const get_xstate_features_mask = try_get_GetXStateFeaturesMask())
652 {
653 return get_xstate_features_mask(context, feature_mask);
654 }
655
656 abort(); // No fallback; callers should check availablility before calling
657 }
658
__acrt_InitializeCriticalSectionEx(LPCRITICAL_SECTION const critical_section,DWORD const spin_count,DWORD const flags)659 extern "C" BOOL WINAPI __acrt_InitializeCriticalSectionEx(
660 LPCRITICAL_SECTION const critical_section,
661 DWORD const spin_count,
662 DWORD const flags
663 )
664 {
665 if (auto const initialize_critical_section_ex = try_get_InitializeCriticalSectionEx())
666 {
667 return initialize_critical_section_ex(critical_section, spin_count, flags);
668 }
669
670 return InitializeCriticalSectionAndSpinCount(critical_section, spin_count);
671 }
672
__acrt_IsValidLocaleName(LPCWSTR const locale_name)673 extern "C" BOOL WINAPI __acrt_IsValidLocaleName(LPCWSTR const locale_name)
674 {
675 if (auto const is_valid_locale_name = try_get_IsValidLocaleName())
676 {
677 return is_valid_locale_name(locale_name);
678 }
679
680 return IsValidLocale(__acrt_LocaleNameToLCID(locale_name, 0), LCID_INSTALLED);
681 }
682
__acrt_LCMapStringEx(LPCWSTR const locale_name,DWORD const flags,LPCWSTR const source,int const source_count,LPWSTR const destination,int const destination_count,LPNLSVERSIONINFO const version,LPVOID const reserved,LPARAM const sort_handle)683 extern "C" int WINAPI __acrt_LCMapStringEx(
684 LPCWSTR const locale_name,
685 DWORD const flags,
686 LPCWSTR const source,
687 int const source_count,
688 LPWSTR const destination,
689 int const destination_count,
690 LPNLSVERSIONINFO const version,
691 LPVOID const reserved,
692 LPARAM const sort_handle
693 )
694 {
695 if (auto const lc_map_string_ex = try_get_LCMapStringEx())
696 {
697 return lc_map_string_ex(locale_name, flags, source, source_count, destination, destination_count, version, reserved, sort_handle);
698 }
699 #pragma warning(disable:__WARNING_PRECONDITION_NULLTERMINATION_VIOLATION) // 26035 LCMapStringW annotation is presently incorrect 11/26/2014 Jaykrell
700 return LCMapStringW(__acrt_LocaleNameToLCID(locale_name, 0), flags, source, source_count, destination, destination_count);
701 }
702
__acrt_LCIDToLocaleName(LCID const locale,LPWSTR const name,int const name_count,DWORD const flags)703 extern "C" int WINAPI __acrt_LCIDToLocaleName(
704 LCID const locale,
705 LPWSTR const name,
706 int const name_count,
707 DWORD const flags
708 )
709 {
710 if (auto const lcid_to_locale_name = try_get_LCIDToLocaleName())
711 {
712 return lcid_to_locale_name(locale, name, name_count, flags);
713 }
714
715 return __acrt_DownlevelLCIDToLocaleName(locale, name, name_count);
716 }
717
__acrt_LocaleNameToLCID(LPCWSTR const name,DWORD const flags)718 extern "C" LCID WINAPI __acrt_LocaleNameToLCID(
719 LPCWSTR const name,
720 DWORD const flags
721 )
722 {
723 if (auto const locale_name_to_lcid = try_get_LocaleNameToLCID())
724 {
725 return locale_name_to_lcid(name, flags);
726 }
727
728 return __acrt_DownlevelLocaleNameToLCID(name);
729 }
730
__acrt_LocateXStateFeature(PCONTEXT const content,DWORD const feature_id,PDWORD const length)731 extern "C" PVOID WINAPI __acrt_LocateXStateFeature(
732 PCONTEXT const content,
733 DWORD const feature_id,
734 PDWORD const length
735 )
736 {
737 if (auto const locate_xstate_feature = try_get_LocateXStateFeature())
738 {
739 return locate_xstate_feature(content, feature_id, length);
740 }
741
742 abort(); // No fallback; callers should check availablility before calling
743 }
744
__acrt_MessageBoxA(HWND const hwnd,LPCSTR const text,LPCSTR const caption,UINT const type)745 extern "C" int WINAPI __acrt_MessageBoxA(
746 HWND const hwnd,
747 LPCSTR const text,
748 LPCSTR const caption,
749 UINT const type
750 )
751 {
752 if (auto const message_box_a = try_get_MessageBoxA())
753 {
754 return message_box_a(hwnd, text, caption, type);
755 }
756
757 abort(); // No fallback; callers should check availablility before calling
758 }
759
__acrt_MessageBoxW(HWND const hwnd,LPCWSTR const text,LPCWSTR const caption,UINT const type)760 extern "C" int WINAPI __acrt_MessageBoxW(
761 HWND const hwnd,
762 LPCWSTR const text,
763 LPCWSTR const caption,
764 UINT const type
765 )
766 {
767 if (auto const message_box_w = try_get_MessageBoxW())
768 {
769 return message_box_w(hwnd, text, caption, type);
770 }
771
772 abort(); // No fallback; callers should check availablility before calling
773 }
774
__acrt_RtlGenRandom(PVOID const buffer,ULONG const buffer_count)775 extern "C" BOOLEAN WINAPI __acrt_RtlGenRandom(
776 PVOID const buffer,
777 ULONG const buffer_count
778 )
779 {
780 if (auto const rtl_gen_random = try_get_SystemFunction036())
781 {
782 return rtl_gen_random(buffer, buffer_count);
783 }
784
785 abort(); // No fallback (this function should exist)
786 }
787
__acrt_RoInitialize(RO_INIT_TYPE const init_type)788 extern "C" HRESULT WINAPI __acrt_RoInitialize(RO_INIT_TYPE const init_type)
789 {
790 if (auto const ro_initialize = try_get_RoInitialize())
791 {
792 return ro_initialize(init_type);
793 }
794
795 return S_OK; // No fallback (this is a best-effort wrapper)
796 }
797
__acrt_RoUninitialize()798 extern "C" void WINAPI __acrt_RoUninitialize()
799 {
800 if (auto const ro_uninitialize = try_get_RoUninitialize())
801 {
802 return ro_uninitialize();
803 }
804
805 // No fallback (this is a best-effort wrapper)
806 }
807
__acrt_AppPolicyGetProcessTerminationMethodInternal(_Out_ AppPolicyProcessTerminationMethod * policy)808 LONG WINAPI __acrt_AppPolicyGetProcessTerminationMethodInternal(_Out_ AppPolicyProcessTerminationMethod* policy)
809 {
810 if (auto const app_policy_get_process_terminaton_method_claims = try_get_AppPolicyGetProcessTerminationMethod())
811 {
812 return app_policy_get_process_terminaton_method_claims(GetCurrentThreadEffectiveToken(), policy);
813 }
814
815 return STATUS_NOT_FOUND;
816 }
817
__acrt_AppPolicyGetThreadInitializationTypeInternal(_Out_ AppPolicyThreadInitializationType * policy)818 LONG WINAPI __acrt_AppPolicyGetThreadInitializationTypeInternal(_Out_ AppPolicyThreadInitializationType* policy)
819 {
820 if (auto const app_policy_get_thread_initialization_type_claims = try_get_AppPolicyGetThreadInitializationType())
821 {
822 return app_policy_get_thread_initialization_type_claims(GetCurrentThreadEffectiveToken(), policy);
823 }
824
825 return STATUS_NOT_FOUND;
826 }
827
__acrt_AppPolicyGetShowDeveloperDiagnosticInternal(_Out_ AppPolicyShowDeveloperDiagnostic * policy)828 LONG WINAPI __acrt_AppPolicyGetShowDeveloperDiagnosticInternal(_Out_ AppPolicyShowDeveloperDiagnostic* policy)
829 {
830 if (auto const app_policy_get_show_developer_diagnostic_claims = try_get_AppPolicyGetShowDeveloperDiagnostic())
831 {
832 return app_policy_get_show_developer_diagnostic_claims(GetCurrentThreadEffectiveToken(), policy);
833 }
834
835 return STATUS_NOT_FOUND;
836 }
837
__acrt_AppPolicyGetWindowingModelInternal(_Out_ AppPolicyWindowingModel * policy)838 LONG WINAPI __acrt_AppPolicyGetWindowingModelInternal(_Out_ AppPolicyWindowingModel* policy)
839 {
840 if (auto const app_policy_get_windowing_model_claims = try_get_AppPolicyGetWindowingModel())
841 {
842 return app_policy_get_windowing_model_claims(GetCurrentThreadEffectiveToken(), policy);
843 }
844
845 return STATUS_NOT_FOUND;
846 }
847
__acrt_SetThreadStackGuarantee(PULONG const stack_size_in_bytes)848 extern "C" BOOL WINAPI __acrt_SetThreadStackGuarantee(PULONG const stack_size_in_bytes)
849 {
850 if (auto const set_thread_stack_guarantee = try_get_SetThreadStackGuarantee())
851 {
852 return set_thread_stack_guarantee(stack_size_in_bytes);
853 }
854
855 return FALSE;
856 }
857
__acrt_can_show_message_box()858 extern "C" bool __cdecl __acrt_can_show_message_box()
859 {
860 bool can_show_message_box = false;
861 if (__acrt_get_windowing_model_policy() == windowing_model_policy_hwnd
862 && try_get_MessageBoxA() != nullptr
863 && try_get_MessageBoxW() != nullptr)
864 {
865 can_show_message_box = true;
866 }
867 return can_show_message_box;
868 }
869
__acrt_can_use_vista_locale_apis()870 extern "C" bool __cdecl __acrt_can_use_vista_locale_apis()
871 {
872 return try_get_CompareStringEx() != nullptr;
873 }
874
875 // This function simply attempts to get each of the locale-related APIs. This
876 // allows a caller to "pre-load" the modules in which these APIs are hosted. We
877 // use this in the _wsetlocale implementation to avoid calls to LoadLibrary while
878 // the locale lock is held.
__acrt_eagerly_load_locale_apis()879 extern "C" void __cdecl __acrt_eagerly_load_locale_apis()
880 {
881 try_get_AreFileApisANSI();
882 try_get_CompareStringEx();
883 try_get_EnumSystemLocalesEx();
884 try_get_GetDateFormatEx();
885 try_get_GetLocaleInfoEx();
886 try_get_GetTimeFormatEx();
887 try_get_GetUserDefaultLocaleName();
888 try_get_IsValidLocaleName();
889 try_get_LCMapStringEx();
890 try_get_LCIDToLocaleName();
891 try_get_LocaleNameToLCID();
892 }
893
__acrt_can_use_xstate_apis()894 extern "C" bool __cdecl __acrt_can_use_xstate_apis()
895 {
896 return try_get_LocateXStateFeature() != nullptr;
897 }
898
__acrt_get_parent_window()899 extern "C" HWND __cdecl __acrt_get_parent_window()
900 {
901 auto const get_active_window = try_get_GetActiveWindow();
902 if (!get_active_window)
903 {
904 return nullptr;
905 }
906
907 HWND const active_window = get_active_window();
908 if (!active_window)
909 {
910 return nullptr;
911 }
912
913 auto const get_last_active_popup = try_get_GetLastActivePopup();
914 if (!get_last_active_popup)
915 {
916 return active_window;
917 }
918
919 return get_last_active_popup(active_window);
920 }
921
__acrt_is_interactive()922 extern "C" bool __cdecl __acrt_is_interactive()
923 {
924 auto const get_process_window_station = try_get_GetProcessWindowStation();
925 if (!get_process_window_station)
926 {
927 return true;
928 }
929
930 auto const get_user_object_information = try_get_GetUserObjectInformationW();
931 if (!get_user_object_information)
932 {
933 return true;
934 }
935
936 HWINSTA const hwinsta = get_process_window_station();
937 if (!hwinsta)
938 {
939 return false;
940 }
941
942 USEROBJECTFLAGS uof{};
943 if (!get_user_object_information(hwinsta, UOI_FLAGS, &uof, sizeof(uof), nullptr))
944 {
945 return false;
946 }
947
948 if ((uof.dwFlags & WSF_VISIBLE) == 0)
949 {
950 return false;
951 }
952
953 return true;
954 }
955