[UCRT] Import Microsoft.Windows.SDK.CRTSource version 10.0.22621.3

Imported from https://www.nuget.org/packages/Microsoft.Windows.SDK.CRTSource/10.0.22621.3
License: MIT
This commit is contained in:
Timo Kreuzer 2024-05-11 07:03:12 +02:00
parent f1b60c66f0
commit 04e0dc4a7a
568 changed files with 115483 additions and 0 deletions

View file

@ -0,0 +1,79 @@
//
// CreateProcessA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_CreateProcessA.
//
#include <corecrt_internal_win32_buffer.h>
BOOL __cdecl __acrt_CreateProcessA(
LPCSTR const lpApplicationName,
LPSTR const lpCommandLine,
LPSECURITY_ATTRIBUTES const lpProcessAttributes,
LPSECURITY_ATTRIBUTES const lpThreadAttributes,
BOOL const bInheritHandles,
DWORD const dwCreationFlags,
LPVOID const lpEnvironment,
LPCSTR const lpCurrentDirectory,
LPSTARTUPINFOW const lpStartupInfo,
LPPROCESS_INFORMATION const lpProcessInformation
)
{
__crt_internal_win32_buffer<wchar_t> wide_application_name;
__crt_internal_win32_buffer<wchar_t> wide_command_line;
__crt_internal_win32_buffer<wchar_t> wide_current_directory;
errno_t const cvt1 = __acrt_mbs_to_wcs_cp(
lpApplicationName,
wide_application_name,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt1 != 0) {
return FALSE;
}
errno_t const cvt2 = __acrt_mbs_to_wcs_cp(
lpCommandLine,
wide_command_line,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt2 != 0) {
return FALSE;
}
LPWSTR wide_current_directory_ptr = nullptr;
if (lpCurrentDirectory != nullptr) {
errno_t const cvt3 = __acrt_mbs_to_wcs_cp(
lpCurrentDirectory,
wide_current_directory,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt3 != 0) {
return FALSE;
}
wide_current_directory_ptr = wide_current_directory.data();
}
// converted_command_line is an out parameter, but is not reconverted to utf8 string,
// since it is only written to in the Wide version. CreateProcessA does not expect it
// to have changed.
return ::CreateProcessW(
wide_application_name.data(),
wide_command_line.data(),
lpProcessAttributes,
lpThreadAttributes,
bInheritHandles,
dwCreationFlags,
lpEnvironment,
wide_current_directory_ptr,
lpStartupInfo,
lpProcessInformation
);
}

View file

@ -0,0 +1,40 @@
//
// GetModuleFileNameA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_GetModuleFileNameA.
//
#include <corecrt_internal_win32_buffer.h>
DWORD __cdecl __acrt_GetModuleFileNameA(
HMODULE const hModule,
char * const lpFilename,
DWORD const nSize
)
{
size_t const wide_buffer_size = MAX_PATH + 1;
wchar_t wide_buffer[wide_buffer_size];
DWORD const amount_copied = GetModuleFileNameW(
hModule,
wide_buffer,
wide_buffer_size
);
if (amount_copied == 0) {
__acrt_errno_map_os_error(GetLastError());
return 0;
}
__crt_no_alloc_win32_buffer<char> filename_buffer(lpFilename, static_cast<size_t>(nSize));
errno_t const cvt = __acrt_wcs_to_mbs_cp(
wide_buffer,
filename_buffer,
__acrt_get_utf8_acp_compatibility_codepage()
);
return static_cast<DWORD>(filename_buffer.size());
}

View file

@ -0,0 +1,34 @@
//
// LoadLibraryExA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_LoadLibraryExA.
//
#include <corecrt_internal_win32_buffer.h>
HMODULE __cdecl __acrt_LoadLibraryExA(
LPCSTR const lpFilename,
HANDLE const hFile,
DWORD const dwFlags
)
{
__crt_internal_win32_buffer<wchar_t> wide_file_name;
errno_t const cvt1 = __acrt_mbs_to_wcs_cp(
lpFilename,
wide_file_name,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt1 != 0) {
return nullptr;
}
return ::LoadLibraryExW(
wide_file_name.data(),
hFile,
dwFlags
);
}

View file

@ -0,0 +1,31 @@
//
// OutputDebugStringA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_OutputDebugStringA.
//
#include <corecrt_internal_win32_buffer.h>
void WINAPI __acrt_OutputDebugStringA(
LPCSTR const text
)
{
if (text == nullptr)
{
return;
}
size_t const text_size = strlen(text) + 1;
if (text_size == 0)
{
return;
}
// Use alloca instead of heap, since this code is executed during asserts
auto text_wide = (wchar_t*)_alloca(text_size * sizeof(wchar_t));
size_t converted;
if (mbstowcs_s(&converted, text_wide, text_size, text, text_size - 1) == 0)
{
OutputDebugStringW(text_wide);
}
}

View file

@ -0,0 +1,28 @@
//
// SetCurrentDirectoryA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_SetCurrentDirectoryA.
//
#include <corecrt_internal_win32_buffer.h>
BOOL __cdecl __acrt_SetCurrentDirectoryA(
LPCSTR const lpPathName
)
{
__crt_internal_win32_buffer<wchar_t> wide_path_name;
errno_t const cvt1 = __acrt_mbs_to_wcs_cp(
lpPathName,
wide_path_name,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt1 != 0) {
return FALSE;
}
return ::SetCurrentDirectoryW(wide_path_name.data());
}

View file

@ -0,0 +1,40 @@
//
// SetEnvironmentVariableA.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definition of __acrt_SetEnvironmentVariableA.
//
#include <corecrt_internal_win32_buffer.h>
BOOL __cdecl __acrt_SetEnvironmentVariableA(
LPCSTR const lpName,
LPCSTR const lpValue
)
{
__crt_internal_win32_buffer<wchar_t> wide_name;
__crt_internal_win32_buffer<wchar_t> wide_value;
errno_t const cvt1 = __acrt_mbs_to_wcs_cp(
lpName,
wide_name,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt1 != 0) {
return FALSE;
}
errno_t const cvt2 = __acrt_mbs_to_wcs_cp(
lpValue,
wide_value,
__acrt_get_utf8_acp_compatibility_codepage()
);
if (cvt2 != 0) {
return FALSE;
}
return ::SetEnvironmentVariableW(wide_name.data(), wide_value.data());
}

View file

@ -0,0 +1,345 @@
//
// initialization.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This file defines the main initialization and uninitialization routines for
// the AppCRT, shared by both the static and dynamic AppCRT libraries. In the
// dynamic AppCRT library, these are called by DllMain. In the static AppCRT
// library, these are called by the initialization code.
//
#include <corecrt_internal.h>
#include <corecrt_internal_stdio.h>
#include <stdlib.h>
#include <stdio.h>
extern "C" {
extern _onexit_table_t __acrt_atexit_table;
extern _onexit_table_t __acrt_at_quick_exit_table;
extern void* __acrt_stdout_buffer;
extern void* __acrt_stderr_buffer;
static bool __cdecl initialize_global_variables()
{
__acrt_current_locale_data.initialize(&__acrt_initial_locale_data);
return true;
}
#ifdef CRTDLL
static bool __cdecl initialize_c()
{
_initialize_onexit_table(&__acrt_atexit_table);
_initialize_onexit_table(&__acrt_at_quick_exit_table);
// Do C initialization:
if (_initterm_e(__xi_a, __xi_z) != 0)
{
return false;
}
// Do C++ initialization:
_initterm(__xc_a, __xc_z);
return true;
}
static bool __cdecl uninitialize_c(bool)
{
// Do pre-termination:
_initterm(__xp_a, __xp_z);
// Do termination:
_initterm(__xt_a, __xt_z);
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl initialize_environment()
{
if (_initialize_narrow_environment() < 0)
{
return false;
}
if (!_get_initial_narrow_environment())
{
return false;
}
return true;
}
#else
static bool __cdecl initialize_c()
{
_initialize_onexit_table(&__acrt_atexit_table);
_initialize_onexit_table(&__acrt_at_quick_exit_table);
return true;
}
static bool __cdecl uninitialize_c(bool)
{
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl initialize_environment()
{
return true;
}
#endif
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl uninitialize_environment(bool const terminating)
{
UNREFERENCED_PARAMETER(terminating);
#ifdef _DEBUG
if (terminating)
{
return true;
}
#endif
__dcrt_uninitialize_environments_nolock();
return true;
}
#ifdef _CRT_GLOBAL_STATE_ISOLATION
static bool __cdecl initialize_global_state_isolation()
{
// Configure CRT's per-thread global state mode data
return __crt_state_management::initialize_global_state_isolation();
}
static bool __cdecl uninitialize_global_state_isolation(bool const terminating)
{
// Configure CRT's per-thread global state mode data
__crt_state_management::uninitialize_global_state_isolation(terminating);
return true;
}
#else
static bool __cdecl initialize_global_state_isolation()
{
return true;
}
static bool __cdecl uninitialize_global_state_isolation(bool const /* terminating */)
{
return true;
}
#endif
static bool __cdecl initialize_pointers()
{
void* const encoded_null = __crt_fast_encode_pointer(nullptr);
__acrt_initialize_invalid_parameter_handler(encoded_null);
__acrt_initialize_new_handler(encoded_null);
__acrt_initialize_signal_handlers(encoded_null);
__acrt_initialize_user_matherr(encoded_null);
__acrt_initialize_thread_local_exit_callback(encoded_null);
return true;
}
static bool __cdecl uninitialize_vcruntime(const bool /* terminating */)
{
return __vcrt_uninitialize(false);
}
static bool __cdecl uninitialize_allocated_memory(bool const /* terminating */)
{
__acrt_current_multibyte_data.uninitialize([](__crt_multibyte_data*& multibyte_data)
{
if (_InterlockedDecrement(&multibyte_data->refcount) == 0 &&
multibyte_data != &__acrt_initial_multibyte_data)
{
_free_crt(multibyte_data);
multibyte_data = &__acrt_initial_multibyte_data;
}
});
return true;
}
// C4505: unreferenced local function
#pragma warning( suppress: 4505 )
static bool __cdecl uninitialize_allocated_io_buffers(bool const /* terminating */)
{
_free_crt(__acrt_stdout_buffer);
__acrt_stdout_buffer = nullptr;
_free_crt(__acrt_stderr_buffer);
__acrt_stderr_buffer = nullptr;
_free_crt(__argv);
__argv = nullptr;
_free_crt(__wargv);
__wargv = nullptr;
return true;
}
static bool __cdecl report_memory_leaks(bool const /* terminating */)
{
#ifdef _DEBUG
if (_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) & _CRTDBG_LEAK_CHECK_DF)
{
_CrtSetDumpClient(nullptr);
_CrtDumpMemoryLeaks();
}
#endif
return true;
}
// This is the table of initializer/uninitializer pairs that is used to perform
// AppCRT initialization. Initializers are run first-to-last during AppCRT
// initialization, and uninitializers are run last-to-first during termination.
static __acrt_initializer const __acrt_initializers[] =
{
// Init globals that can't be set at compile time because they have c'tors
{ initialize_global_variables, nullptr },
// Global pointers are stored in encoded form; they must be dynamically
// initialized to the encoded nullptr value before they are used by the CRT.
{ initialize_pointers, nullptr },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ __acrt_initialize_winapi_thunks, __acrt_uninitialize_winapi_thunks },
#endif
// Configure CRT's global state isolation system. This system calls FlsAlloc
// and thus must occur after the initialize_pointers initialization, otherwise
// it will fall back to call TlsAlloc, then try to use the allocated TLS slot
// with the FLS functions. This does not turn out well. By running this
// initialization after the initialize_pointers step, we ensure that it can
// call FlsAlloc.
{ initialize_global_state_isolation, uninitialize_global_state_isolation },
// The heap and locks must be initialized before most other initialization
// takes place, as other initialization steps rely on the heap and locks:
{ __acrt_initialize_locks, __acrt_uninitialize_locks },
{ __acrt_initialize_heap, __acrt_uninitialize_heap },
// During uninitialization, before the heap is uninitialized, the AppCRT
// needs to notify all VCRuntime instances in the process to allow them to
// release any memory that they allocated via the AppCRT heap.
//
// First, we notify all modules that registered for shutdown notification.
// This only occurs in the AppCRT DLL, because the static CRT is only ever
// used by a single module, so this notification is never required.
//
// Then, we notify our own VCRuntime instance. Note that after this point
// during uninitialization, no exception handling may take place in any
// CRT module.
{ nullptr, uninitialize_vcruntime },
{ __acrt_initialize_ptd, __acrt_uninitialize_ptd },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ __acrt_initialize_lowio, __acrt_uninitialize_lowio },
{ __acrt_initialize_command_line, __acrt_uninitialize_command_line },
#endif
{ __acrt_initialize_multibyte, nullptr },
{ nullptr, report_memory_leaks },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ nullptr, uninitialize_allocated_io_buffers },
#endif
{ nullptr, uninitialize_allocated_memory },
// Enclaves only require initializers for supported features.
#ifndef _UCRT_ENCLAVE_BUILD
{ initialize_environment, uninitialize_environment },
#endif
{ initialize_c, uninitialize_c },
};
__crt_bool __cdecl __acrt_initialize()
{
#if defined CRTDLL
__isa_available_init();
#endif
return __acrt_execute_initializers(
__acrt_initializers,
__acrt_initializers + _countof(__acrt_initializers)
);
}
__crt_bool __cdecl __acrt_uninitialize(__crt_bool const terminating)
{
UNREFERENCED_PARAMETER(terminating);
// If the process is terminating, there's no point in cleaning up, except
// in debug builds.
#ifndef _DEBUG
if (terminating) {
#ifndef _UCRT_ENCLAVE_BUILD
if (__acrt_stdio_is_initialized()) {
_flushall();
}
#endif
return TRUE;
}
#endif
return __acrt_execute_uninitializers(
__acrt_initializers,
__acrt_initializers + _countof(__acrt_initializers)
);
}
__crt_bool __cdecl __acrt_uninitialize_critical(__crt_bool const terminating)
{
__acrt_uninitialize_ptd(terminating);
#ifdef _CRT_GLOBAL_STATE_ISOLATION
uninitialize_global_state_isolation(terminating);
#endif
return true;
}
__crt_bool __cdecl __acrt_thread_attach()
{
// Create a per-thread data structure for this thread (getptd will attempt
// to create a new per-thread data structure if one does not already exist
// for this thread):
if (__acrt_getptd_noexit() == nullptr)
return false;
return true;
}
__crt_bool __cdecl __acrt_thread_detach()
{
// Free the per-thread data structure for this thread:
__acrt_freeptd();
return true;
}
}

View file

@ -0,0 +1,71 @@
//
// locks.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Critical sections used for synchronization in the CoreCRT.
//
#include <corecrt_internal.h>
// This table holds the locks used by the CoreCRT. It is indexed using the
// enumerators of the __acrt_lock_id enumeration.
static CRITICAL_SECTION __acrt_lock_table[__acrt_lock_count];
// This variable stores the number of locks that have been successfully
// initialized. Locks are initialized in order and are destroyed in reverse
// order. The startup and exit code must ensure that initialization and
// destruction is synchronized: these functions should never be executed
// concurrently.
static unsigned __acrt_locks_initialized;
extern "C" bool __cdecl __acrt_initialize_locks()
{
for (unsigned i = 0; i < __acrt_lock_count; ++i)
{
if (!__acrt_InitializeCriticalSectionEx(&__acrt_lock_table[i], _CORECRT_SPINCOUNT, 0))
{
__acrt_uninitialize_locks(false);
return false;
}
++__acrt_locks_initialized;
}
return true;
}
extern "C" bool __cdecl __acrt_uninitialize_locks(bool const /* terminating */)
{
for (unsigned i = __acrt_locks_initialized; i > 0; --i)
{
DeleteCriticalSection(&__acrt_lock_table[i - 1]);
--__acrt_locks_initialized;
}
return true;
}
extern "C" void __cdecl __acrt_lock(_In_ __acrt_lock_id _Lock)
{
EnterCriticalSection(&__acrt_lock_table[_Lock]);
}
extern "C" void __cdecl __acrt_unlock(_In_ __acrt_lock_id _Lock)
{
LeaveCriticalSection(&__acrt_lock_table[_Lock]);
}
extern "C" void __cdecl _lock_locales()
{
__acrt_eagerly_load_locale_apis();
__acrt_lock(__acrt_locale_lock);
}
extern "C" void __cdecl _unlock_locales()
{
__acrt_unlock(__acrt_locale_lock);
}

View file

@ -0,0 +1,22 @@
//
// peb_access.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Wrapper functions to access fields in the PEB.
//
// Using internal headers for definitions. Only call publicly available functions.
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
extern "C" bool __cdecl __acrt_app_verifier_enabled()
{
return (NtCurrentTeb()->ProcessEnvironmentBlock->NtGlobalFlag & FLG_APPLICATION_VERIFIER) != 0;
}
extern "C" bool __cdecl __acrt_is_secure_process()
{
return (NtCurrentTeb()->ProcessEnvironmentBlock->ProcessParameters->Flags & RTL_USER_PROC_SECURE_PROCESS) != 0;
}

View file

@ -0,0 +1,345 @@
//
// per_thread_data.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Per-Thread Data (PTD) used by the AppCRT.
//
#include <corecrt_internal.h>
#include <corecrt_internal_ptd_propagation.h>
#include <stddef.h>
#ifdef _CRT_GLOBAL_STATE_ISOLATION
extern "C" DWORD __crt_global_state_mode_flsindex = FLS_OUT_OF_INDEXES;
#endif
static void WINAPI destroy_fls(void*) throw();
static unsigned long __acrt_flsindex = FLS_OUT_OF_INDEXES;
extern "C" bool __cdecl __acrt_initialize_ptd()
{
__acrt_flsindex = __acrt_FlsAlloc(destroy_fls);
if (__acrt_flsindex == FLS_OUT_OF_INDEXES)
{
return false;
}
if (__acrt_getptd_noexit() == nullptr)
{
__acrt_uninitialize_ptd(false);
return false;
}
return true;
}
extern "C" bool __cdecl __acrt_uninitialize_ptd(bool)
{
if (__acrt_flsindex != FLS_OUT_OF_INDEXES)
{
__acrt_FlsFree(__acrt_flsindex);
__acrt_flsindex = FLS_OUT_OF_INDEXES;
}
return true;
}
static void __cdecl replace_current_thread_locale_nolock(
__acrt_ptd* const ptd,
__crt_locale_data* const new_locale_info
) throw()
{
if (ptd->_locale_info)
{
__acrt_release_locale_ref(ptd->_locale_info);
if (ptd->_locale_info != __acrt_current_locale_data.value() &&
ptd->_locale_info != &__acrt_initial_locale_data &&
ptd->_locale_info->refcount == 0)
{
__acrt_free_locale(ptd->_locale_info);
}
}
ptd->_locale_info = new_locale_info;
if (ptd->_locale_info)
{
__acrt_add_locale_ref(ptd->_locale_info);
}
}
// Constructs a single PTD object, copying the given 'locale_data' if provided.
static void __cdecl construct_ptd(
__acrt_ptd* const ptd,
__crt_locale_data** const locale_data
) throw()
{
ptd->_rand_state = 1;
ptd->_pxcptacttab = const_cast<__crt_signal_action_t*>(__acrt_exception_action_table);
// It is necessary to always have GLOBAL_LOCALE_BIT set in perthread data
// because when doing bitwise or, we won't get __UPDATE_LOCALE to work when
// global per thread locale is set.
// See _configthreadlocale() and __acrt_should_sync_with_global_locale().
ptd->_own_locale = _GLOBAL_LOCALE_BIT;
ptd->_multibyte_info = &__acrt_initial_multibyte_data;
// Initialize _setloc_data. These are the only valuse that need to be
// initialized.
ptd->_setloc_data._cachein[0] = L'C';
ptd->_setloc_data._cacheout[0] = L'C';
// Downlevel data is not initially used
ptd->_setloc_downlevel_data = nullptr;
__acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
{
_InterlockedIncrement(&ptd->_multibyte_info->refcount);
});
// We need to make sure that ptd->ptlocinfo in never nullptr, this saves us
// perf counts when UPDATING locale.
__acrt_lock_and_call(__acrt_locale_lock, [&]
{
replace_current_thread_locale_nolock(ptd, *locale_data);
});
}
// Constructs each of the 'state_index_count' PTD objects in the array of PTD
// objects pointed to by 'ptd'.
static void __cdecl construct_ptd_array(__acrt_ptd* const ptd) throw()
{
for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
{
construct_ptd(&ptd[i], &__acrt_current_locale_data.dangerous_get_state_array()[i]);
}
}
// Cleans up all resources used by a single PTD; does not free the PTD structure
// itself.
static void __cdecl destroy_ptd(__acrt_ptd* const ptd) throw()
{
if (ptd->_pxcptacttab != __acrt_exception_action_table)
{
_free_crt(ptd->_pxcptacttab);
}
_free_crt(ptd->_cvtbuf);
_free_crt(ptd->_asctime_buffer);
_free_crt(ptd->_wasctime_buffer);
_free_crt(ptd->_gmtime_buffer);
_free_crt(ptd->_tmpnam_narrow_buffer);
_free_crt(ptd->_tmpnam_wide_buffer);
_free_crt(ptd->_strerror_buffer);
_free_crt(ptd->_wcserror_buffer);
_free_crt(ptd->_beginthread_context);
__acrt_lock_and_call(__acrt_multibyte_cp_lock, [&]
{
__crt_multibyte_data* const multibyte_data = ptd->_multibyte_info;
if (!multibyte_data)
{
return;
}
if (_InterlockedDecrement(&multibyte_data->refcount) != 0)
{
return;
}
if (multibyte_data == &__acrt_initial_multibyte_data)
{
return;
}
_free_crt(multibyte_data);
});
__acrt_lock_and_call(__acrt_locale_lock, [&]
{
replace_current_thread_locale_nolock(ptd, nullptr);
});
}
// Destroys each of the 'state_index_count' PTD objects in the array of PTD
// objects pointed to by 'ptd'.
static void __cdecl destroy_ptd_array(__acrt_ptd* const ptd) throw()
{
for (size_t i = 0; i != __crt_state_management::state_index_count; ++i)
{
destroy_ptd(&ptd[i]);
}
}
// This function is called by the operating system when a thread is being
// destroyed, to allow us the opportunity to clean up.
static void WINAPI destroy_fls(void* const pfd) throw()
{
if (!pfd)
{
return;
}
destroy_ptd_array(static_cast<__acrt_ptd*>(pfd));
_free_crt(pfd);
}
static __forceinline __acrt_ptd* try_get_ptd_head() throw()
{
// If we haven't allocated per-thread data for this module, return failure:
if (__acrt_flsindex == FLS_OUT_OF_INDEXES)
{
return nullptr;
}
__acrt_ptd* const ptd_head = static_cast<__acrt_ptd*>(__acrt_FlsGetValue(__acrt_flsindex));
if (!ptd_head)
{
return nullptr;
}
return ptd_head;
}
_Success_(return != nullptr)
static __forceinline __acrt_ptd* internal_get_ptd_head() throw()
{
// We use the CRT heap to allocate the PTD. If the CRT heap fails to
// allocate the requested memory, it will attempt to set errno to ENOMEM,
// which will in turn attempt to acquire the PTD, resulting in infinite
// recursion that causes a stack overflow.
//
// We set the PTD to this sentinel value for the duration of the allocation
// in order to detect this case.
static void* const reentrancy_sentinel = reinterpret_cast<void*>(SIZE_MAX);
__acrt_ptd* const existing_ptd_head = try_get_ptd_head();
if (existing_ptd_head == reentrancy_sentinel)
{
return nullptr;
}
else if (existing_ptd_head != nullptr)
{
return existing_ptd_head;
}
if (!__acrt_FlsSetValue(__acrt_flsindex, reentrancy_sentinel))
{
return nullptr;
}
__crt_unique_heap_ptr<__acrt_ptd> new_ptd_head(_calloc_crt_t(__acrt_ptd, __crt_state_management::state_index_count));
if (!new_ptd_head)
{
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
return nullptr;
}
if (!__acrt_FlsSetValue(__acrt_flsindex, new_ptd_head.get()))
{
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
return nullptr;
}
construct_ptd_array(new_ptd_head.get());
return new_ptd_head.detach();
}
// This functionality has been split out of __acrt_getptd_noexit so that we can
// force it to be inlined into both __acrt_getptd_noexit and __acrt_getptd. These
// functions are performance critical and this change has substantially improved
// __acrt_getptd performance.
static __forceinline __acrt_ptd* __cdecl internal_getptd_noexit(
__crt_scoped_get_last_error_reset const& last_error_reset,
size_t const global_state_index
) throw()
{
UNREFERENCED_PARAMETER(last_error_reset);
__acrt_ptd* const ptd_head = internal_get_ptd_head();
if (!ptd_head)
{
return nullptr;
}
return ptd_head + global_state_index;
}
static __forceinline __acrt_ptd* __cdecl internal_getptd_noexit() throw()
{
__crt_scoped_get_last_error_reset const last_error_reset;
return internal_getptd_noexit(last_error_reset, __crt_state_management::get_current_state_index(last_error_reset));
}
__acrt_ptd* __cdecl __acrt_getptd_noexit_explicit(__crt_scoped_get_last_error_reset const& last_error_reset, size_t const global_state_index)
{ // An extra function to grab the PTD while a GetLastError() reset guard is already in place
// and the global state index is already known.
return internal_getptd_noexit(last_error_reset, global_state_index);
}
extern "C" __acrt_ptd* __cdecl __acrt_getptd_noexit()
{
return internal_getptd_noexit();
}
extern "C" __acrt_ptd* __cdecl __acrt_getptd()
{
__acrt_ptd* const ptd = internal_getptd_noexit();
if (!ptd)
{
abort();
}
return ptd;
}
extern "C" __acrt_ptd* __cdecl __acrt_getptd_head()
{
__acrt_ptd* const ptd_head = internal_get_ptd_head();
if (!ptd_head)
{
abort();
}
return ptd_head;
}
extern "C" void __cdecl __acrt_freeptd()
{
__acrt_ptd* const ptd_head = try_get_ptd_head();
if (!ptd_head)
{
return;
}
__acrt_FlsSetValue(__acrt_flsindex, nullptr);
destroy_fls(ptd_head);
}
// These functions are simply wrappers around the Windows API functions.
extern "C" unsigned long __cdecl __threadid()
{
return GetCurrentThreadId();
}
extern "C" uintptr_t __cdecl __threadhandle()
{
return reinterpret_cast<uintptr_t>(GetCurrentThread());
}

View file

@ -0,0 +1,200 @@
/***
*report_runtime_error.cpp - startup error messages
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* Prints out banner for runtime error messages.
*
*******************************************************************************/
#include <corecrt_internal.h>
#include <stdlib.h>
// This is used during the expansion of the runtime error text.
#define EOL L"\r\n"
static bool __cdecl issue_debug_notification(wchar_t const* const message) throw()
{
// This is referenced only in the Debug CRT build
UNREFERENCED_PARAMETER(message);
#ifdef _DEBUG
switch (_CrtDbgReportW(_CRT_ERROR, nullptr, 0, nullptr, L"%ls", message))
{
case 1:
_CrtDbgBreak();
return true;
case 0:
return true;
}
#endif // _DEBUG
return false;
}
// Enclaves do not support error messages outside of OutputDebugString.
#ifdef _UCRT_ENCLAVE_BUILD
extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
{
// Report the error using the debug
issue_debug_notification(message);
}
#else /* ^^^ _UCRT_ENCLAVE_BUILD ^^^ // vvv !_UCRT_ENCLAVE_BUILD vvv */
/*
* __acrt_app_type, together with __error_mode, determine how error messages
* are written out.
*/
static _crt_app_type __acrt_app_type = _crt_unknown_app;
/***
*void _set_app_type(int apptype) - interface to change __acrt_app_type
*
*Purpose:
* Set, or change, the value of __acrt_app_type.
*
* Set the default debug lib report destination for console apps.
*
* This function is for INTERNAL USE ONLY.
*
*Entry:
* int modeval = _crt_unknown_app, unknown
* _crt_console_app, console, or command line, application
* _crt_gui_app, GUI, or Windows, application
*
*Exit:
*
*Exceptions:
*
*******************************************************************************/
extern "C" void __cdecl _set_app_type(_crt_app_type const new_app_type)
{
__acrt_app_type = new_app_type;
}
extern "C" _crt_app_type __cdecl _query_app_type()
{
return __acrt_app_type;
}
static bool __cdecl should_write_error_to_console() throw()
{
int const error_mode = _set_error_mode(_REPORT_ERRMODE);
if (error_mode == _OUT_TO_STDERR)
{
return true;
}
if (error_mode == _OUT_TO_DEFAULT && __acrt_app_type == _crt_console_app)
{
return true;
}
return false;
}
static void write_string_to_console(wchar_t const* const wide_string) throw()
{
HANDLE const handle = GetStdHandle(STD_ERROR_HANDLE);
if (handle == nullptr || handle == INVALID_HANDLE_VALUE)
{
return;
}
// We convert the wide string to a narrow string by truncating each character.
// Currently, the text for each runtime error consists only of ASCII, so this
// is acceptable. If the error text is ever localized, this would need to
// change.
size_t const narrow_buffer_count = 500;
char narrow_buffer[narrow_buffer_count];
char* const narrow_first = narrow_buffer;
char* const narrow_last = narrow_first + narrow_buffer_count;
// Note that this loop copies the null terminator if the loop terminates
// befoe running out of buffer space:
char* narrow_it = narrow_first;
wchar_t const* wide_it = wide_string;
do
{
*narrow_it = static_cast<char>(*wide_it);
}
while (++narrow_it != narrow_last && *wide_it++ != '\0');
// If we did run out of buffer space, this will null-terminate the text that
// we were able to copy:
*(narrow_last - 1) = '\0';
DWORD const bytes_to_write = static_cast<DWORD>(narrow_it - narrow_first - 1); // Account for null terminator
DWORD bytes_written = 0;
WriteFile(handle, narrow_buffer, bytes_to_write, &bytes_written, nullptr);
}
extern "C" void __cdecl __acrt_report_runtime_error(wchar_t const* const message)
{
// Before we report the error via the normal path, report the error using
// the debug
if (issue_debug_notification(message))
{
return;
}
if (should_write_error_to_console())
{
write_string_to_console(message);
}
else
{
#define MSGTEXTPREFIX L"Runtime Error!\n\nProgram: "
static wchar_t outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) + _MAX_PATH + 2 + 500];
// runtime error msg + progname + 2 newline + runtime error text.
wchar_t* progname = &outmsg[sizeof(MSGTEXTPREFIX) / sizeof(wchar_t) - 1];
size_t progname_size = _countof(outmsg) - (progname - outmsg);
wchar_t* pch = progname;
_ERRCHECK(wcscpy_s(outmsg, _countof(outmsg), MSGTEXTPREFIX));
progname[MAX_PATH] = L'\0';
if (!GetModuleFileNameW(nullptr, progname, MAX_PATH))
{
_ERRCHECK(wcscpy_s(progname, progname_size, L"<program name unknown>"));
}
#define MAXLINELEN 60
if (wcslen(pch) + 1 > MAXLINELEN)
{
pch += wcslen(progname) + 1 - MAXLINELEN;
_ERRCHECK(wcsncpy_s(pch, progname_size - (pch - progname), L"...", 3));
}
_ERRCHECK(wcscat_s(outmsg, _countof(outmsg), L"\n\n"));
_ERRCHECK(wcscat_s(outmsg, _countof(outmsg), message));
// Okay to ignore return value here, this is just to display the message box.
// Only caller is abort() (so we shouldn't/can't handle IDABORT), so the process
// will end shortly.
__acrt_show_wide_message_box(
outmsg,
L"Microsoft Visual C++ Runtime Library",
MB_OK | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL);
}
}
#endif /* _UCRT_ENCLAVE_BUILD */

View file

@ -0,0 +1,67 @@
//
// shared_initialization.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Shared initialization logic used by both the AppCRT and the DesktopCRT.
//
#include <corecrt_internal.h>
extern "C" bool __cdecl __acrt_execute_initializers(
__acrt_initializer const* const first,
__acrt_initializer const* const last
)
{
if (first == last)
return true;
// Execute the initializers in [first, last), in order:
__acrt_initializer const* it = first;
for (; it != last; ++it)
{
if (it->_initialize == nullptr)
continue;
if (!(it->_initialize)())
break;
}
// If we reached the end, all initializers completed successfully:
if (it == last)
return true;
// Otherwise, the initializer pointed to by it failed. We need to roll back
// the initialization by executing the uninitializers corresponding to each
// of the initializers that completed successfully:
for (; it != first; --it)
{
// During initialization roll back, we do not execute uninitializers
// that have no corresponding initializer:
if ((it - 1)->_initialize == nullptr || (it - 1)->_uninitialize == nullptr)
continue;
(it - 1)->_uninitialize(false);
}
return false;
}
extern "C" bool __cdecl __acrt_execute_uninitializers(
__acrt_initializer const* const first,
__acrt_initializer const* const last
)
{
if (first == last)
return true;
// Execute the uninitializers in [first, last), in reverse order:
for (__acrt_initializer const* it = last; it != first; --it)
{
if ((it - 1)->_uninitialize == nullptr)
continue;
(it - 1)->_uninitialize(false);
}
return true;
}

View file

@ -0,0 +1,182 @@
//
// win_policies.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Wrapper functions that determine what policies should apply for the process in question.
//
#include <corecrt_internal.h>
template<typename TPolicy>
static typename TPolicy::policy_type __cdecl get_win_policy(typename TPolicy::appmodel_policy_type defaultValue)
{
TPolicy::appmodel_policy_type appmodelPolicy = defaultValue;
// Secure processes cannot load the appmodel DLL, so only attempt loading
// policy information if this is not a secure process.
if (!__acrt_is_secure_process())
{
TPolicy::appmodel_get_policy(&appmodelPolicy);
}
return TPolicy::appmodel_policy_to_policy_type(appmodelPolicy);
}
template<typename TPolicy>
static typename TPolicy::policy_type __cdecl get_cached_win_policy(typename TPolicy::appmodel_policy_type defaultValue)
{
static long state_cache = 0;
if (long const cached_state = __crt_interlocked_read(&state_cache))
{
return static_cast<TPolicy::policy_type>(cached_state);
}
TPolicy::appmodel_policy_type appmodelPolicy = defaultValue;
// Secure processes cannot load the appmodel DLL, so only attempt loading
// policy information if this is not a secure process.
if (!__acrt_is_secure_process())
{
TPolicy::appmodel_get_policy(&appmodelPolicy);
}
TPolicy::policy_type const policyValue = TPolicy::appmodel_policy_to_policy_type(appmodelPolicy);
long const cached_state = _InterlockedExchange(&state_cache, static_cast<long>(policyValue));
if (cached_state)
{
_ASSERTE(cached_state == static_cast<long>(policyValue));
}
return policyValue;
}
// Determines whether ExitProcess() or TerminateProcess() should be used to end the process
extern "C" process_end_policy __cdecl __acrt_get_process_end_policy()
{
struct process_end_policy_properties
{
typedef process_end_policy policy_type;
typedef AppPolicyProcessTerminationMethod appmodel_policy_type;
static policy_type appmodel_policy_to_policy_type(appmodel_policy_type const appmodelPolicy) throw()
{
if (appmodelPolicy == AppPolicyProcessTerminationMethod_TerminateProcess)
{
return process_end_policy_terminate_process;
}
else
{
return process_end_policy_exit_process;
}
}
static LONG appmodel_get_policy(appmodel_policy_type* appmodelPolicy)
{
return __acrt_AppPolicyGetProcessTerminationMethodInternal(appmodelPolicy);
}
};
return get_win_policy<process_end_policy_properties>(AppPolicyProcessTerminationMethod_ExitProcess);
}
// Determines whether RoInitialize() should be called when creating a thread
extern "C" begin_thread_init_policy __cdecl __acrt_get_begin_thread_init_policy()
{
struct begin_thread_init_policy_properties
{
typedef begin_thread_init_policy policy_type;
typedef AppPolicyThreadInitializationType appmodel_policy_type;
static_assert(begin_thread_init_policy_unknown == 0, "Default value for cache must be 0");
static policy_type appmodel_policy_to_policy_type(long const appmodelPolicy) throw()
{
if (appmodelPolicy == AppPolicyThreadInitializationType_InitializeWinRT)
{
return begin_thread_init_policy_ro_initialize;
}
else
{
return begin_thread_init_policy_none;
}
}
static LONG appmodel_get_policy(appmodel_policy_type* appmodelPolicy)
{
return __acrt_AppPolicyGetThreadInitializationTypeInternal(appmodelPolicy);
}
};
return get_cached_win_policy<begin_thread_init_policy_properties>(AppPolicyThreadInitializationType_None);
}
// Determines whether we should attempt to display assert dialog
extern "C" developer_information_policy __cdecl __acrt_get_developer_information_policy()
{
struct developer_information_policy_properties
{
typedef developer_information_policy policy_type;
typedef AppPolicyShowDeveloperDiagnostic appmodel_policy_type;
static_assert(developer_information_policy_unknown == 0, "Default value for cache must be 0");
static policy_type appmodel_policy_to_policy_type(long const appmodelPolicy) throw()
{
if (appmodelPolicy == AppPolicyShowDeveloperDiagnostic_ShowUI)
{
return developer_information_policy_ui;
}
else
{
return developer_information_policy_none;
}
}
static LONG appmodel_get_policy(appmodel_policy_type* appmodelPolicy)
{
return __acrt_AppPolicyGetShowDeveloperDiagnosticInternal(appmodelPolicy);
}
};
return get_cached_win_policy<developer_information_policy_properties>(AppPolicyShowDeveloperDiagnostic_ShowUI);
}
// Determines what type of windowing model technology is available
extern "C" windowing_model_policy __cdecl __acrt_get_windowing_model_policy()
{
struct windowing_model_policy_properties
{
typedef windowing_model_policy policy_type;
typedef AppPolicyWindowingModel appmodel_policy_type;
static_assert(windowing_model_policy_unknown == 0, "Default value for cache must be 0");
static policy_type appmodel_policy_to_policy_type(long const appmodelPolicy) throw()
{
switch (appmodelPolicy)
{
case AppPolicyWindowingModel_ClassicDesktop:
return windowing_model_policy_hwnd;
case AppPolicyWindowingModel_Universal:
return windowing_model_policy_corewindow;
case AppPolicyWindowingModel_ClassicPhone:
return windowing_model_policy_legacyphone;
case AppPolicyWindowingModel_None:
default:
return windowing_model_policy_none;
}
}
static LONG appmodel_get_policy(appmodel_policy_type* appmodelPolicy)
{
return __acrt_AppPolicyGetWindowingModelInternal(appmodelPolicy);
}
};
return get_cached_win_policy<windowing_model_policy_properties>(AppPolicyWindowingModel_ClassicDesktop);
}

View file

@ -0,0 +1,936 @@
//
// winapi_thunks.cpp
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// Definitions of wrappers for Windows API functions that cannot be called
// directly because they are not available on all supported operating systems.
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntsecapi.h>
#include <corecrt_internal.h>
#include <appmodel.h>
#include <roapi.h>
// This is simlar to msvcrt.
#if _M_AMD64 || _M_ARM || _M_ARM64 || _M_HYBRID
#define FLS_ALWAYS_AVAILABLE 1
#endif
WINBASEAPI
_Success_(return > 0 && return < BufferLength)
DWORD
WINAPI
GetTempPath2W(
_In_ DWORD BufferLength,
_Out_writes_to_opt_(BufferLength,return + 1) LPWSTR Buffer
);
// The XState APIs are declared by the Windows headers only when building for
// x86 and x64. We declare them here unconditionally so that we can share the
// same code for all architectures (we simply avoid use of these functions on
// other architectures).
extern "C" WINBASEAPI DWORD64 WINAPI GetEnabledXStateFeatures();
_Must_inspect_result_
extern "C" WINBASEAPI BOOL WINAPI GetXStateFeaturesMask(
_In_ PCONTEXT context,
_Out_ PDWORD64 feature_mask
);
_Success_(return != NULL)
extern "C" WINBASEAPI PVOID WINAPI LocateXStateFeature(
_In_ PCONTEXT context,
_In_ DWORD feature_id,
_Out_opt_ PDWORD length
);
#define _ACRT_APPLY_TO_LATE_BOUND_MODULES_0 \
_APPLY(api_ms_win_core_datetime_l1_1_1, "api-ms-win-core-datetime-l1-1-1" ) \
_APPLY(api_ms_win_core_file_l1_2_4, "api-ms-win-core-file-l1-2-4" ) \
_APPLY(api_ms_win_core_file_l1_2_2, "api-ms-win-core-file-l1-2-2" ) \
_APPLY(api_ms_win_core_localization_l1_2_1, "api-ms-win-core-localization-l1-2-1" ) \
_APPLY(api_ms_win_core_localization_obsolete_l1_2_0, "api-ms-win-core-localization-obsolete-l1-2-0") \
_APPLY(api_ms_win_core_processthreads_l1_1_2, "api-ms-win-core-processthreads-l1-1-2" ) \
_APPLY(api_ms_win_core_string_l1_1_0, "api-ms-win-core-string-l1-1-0" ) \
_APPLY(api_ms_win_core_synch_l1_2_0, "api-ms-win-core-synch-l1-2-0" ) \
_APPLY(api_ms_win_core_sysinfo_l1_2_1, "api-ms-win-core-sysinfo-l1-2-1" ) \
_APPLY(api_ms_win_core_winrt_l1_1_0, "api-ms-win-core-winrt-l1-1-0" ) \
_APPLY(api_ms_win_core_xstate_l2_1_0, "api-ms-win-core-xstate-l2-1-0" ) \
_APPLY(api_ms_win_rtcore_ntuser_window_l1_1_0, "api-ms-win-rtcore-ntuser-window-l1-1-0" ) \
_APPLY(api_ms_win_security_systemfunctions_l1_1_0, "api-ms-win-security-systemfunctions-l1-1-0" ) \
_APPLY(ext_ms_win_ntuser_dialogbox_l1_1_0, "ext-ms-win-ntuser-dialogbox-l1-1-0" ) \
_APPLY(ext_ms_win_ntuser_windowstation_l1_1_0, "ext-ms-win-ntuser-windowstation-l1-1-0" ) \
_APPLY(advapi32, "advapi32" ) \
_APPLY(kernel32, "kernel32" ) \
_APPLY(kernelbase, "kernelbase" ) \
_APPLY(ntdll, "ntdll" ) \
_APPLY(api_ms_win_appmodel_runtime_l1_1_2, "api-ms-win-appmodel-runtime-l1-1-2" ) \
_APPLY(user32, "user32" )
#if FLS_ALWAYS_AVAILABLE
#define _ACRT_APPLY_TO_LATE_BOUND_MODULES_1 /* nothing */
#else
#define _ACRT_APPLY_TO_LATE_BOUND_MODULES_1 \
_APPLY(api_ms_win_core_fibers_l1_1_0, "api-ms-win-core-fibers-l1-1-0" )
#endif
#define _ACRT_APPLY_TO_LATE_BOUND_MODULES \
_ACRT_APPLY_TO_LATE_BOUND_MODULES_0 \
_ACRT_APPLY_TO_LATE_BOUND_MODULES_1 \
#define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_0 \
_APPLY(AreFileApisANSI, ({ /* api_ms_win_core_file_l1_2_2, */ kernel32 })) \
_APPLY(CompareStringEx, ({ api_ms_win_core_string_l1_1_0, kernel32 })) \
_APPLY(EnumSystemLocalesEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(GetActiveWindow, ({ api_ms_win_rtcore_ntuser_window_l1_1_0, user32 })) \
_APPLY(GetDateFormatEx, ({ api_ms_win_core_datetime_l1_1_1, kernel32 })) \
_APPLY(GetTempPath2W, ({ api_ms_win_core_file_l1_2_4, kernelbase })) \
_APPLY(GetEnabledXStateFeatures, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
_APPLY(GetLastActivePopup, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
_APPLY(GetLocaleInfoEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(GetProcessWindowStation, ({ ext_ms_win_ntuser_windowstation_l1_1_0, user32 })) \
_APPLY(GetSystemTimePreciseAsFileTime, ({ api_ms_win_core_sysinfo_l1_2_1 })) \
_APPLY(GetTimeFormatEx, ({ api_ms_win_core_datetime_l1_1_1, kernel32 })) \
_APPLY(GetUserDefaultLocaleName, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(GetUserObjectInformationW, ({ ext_ms_win_ntuser_windowstation_l1_1_0, user32 })) \
_APPLY(GetXStateFeaturesMask, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
_APPLY(InitializeCriticalSectionEx, ({ api_ms_win_core_synch_l1_2_0, kernel32 })) \
_APPLY(IsValidLocaleName, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(LCMapStringEx, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(LCIDToLocaleName, ({ api_ms_win_core_localization_obsolete_l1_2_0, kernel32 })) \
_APPLY(LocaleNameToLCID, ({ api_ms_win_core_localization_l1_2_1, kernel32 })) \
_APPLY(LocateXStateFeature, ({ api_ms_win_core_xstate_l2_1_0, kernel32 })) \
_APPLY(MessageBoxA, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
_APPLY(MessageBoxW, ({ ext_ms_win_ntuser_dialogbox_l1_1_0, user32 })) \
_APPLY(RoInitialize, ({ api_ms_win_core_winrt_l1_1_0 })) \
_APPLY(RoUninitialize, ({ api_ms_win_core_winrt_l1_1_0 })) \
_APPLY(AppPolicyGetProcessTerminationMethod, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
_APPLY(AppPolicyGetThreadInitializationType, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
_APPLY(AppPolicyGetShowDeveloperDiagnostic, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
_APPLY(AppPolicyGetWindowingModel, ({ api_ms_win_appmodel_runtime_l1_1_2 })) \
_APPLY(SetThreadStackGuarantee, ({ api_ms_win_core_processthreads_l1_1_2, kernel32 })) \
_APPLY(SystemFunction036, ({ api_ms_win_security_systemfunctions_l1_1_0, advapi32 }))
#if FLS_ALWAYS_AVAILABLE
#define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 /* nothing */
#else
#define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 \
_APPLY(FlsAlloc, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
_APPLY(FlsFree, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
_APPLY(FlsGetValue, ({ api_ms_win_core_fibers_l1_1_0, kernel32 })) \
_APPLY(FlsSetValue, ({ api_ms_win_core_fibers_l1_1_0, kernel32 }))
#endif
#define _ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS \
_ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_0 \
_ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS_1 \
namespace
{
// Generate enumerators for each of the modules:
enum module_id : unsigned
{
#define _APPLY(_SYMBOL, _NAME) _SYMBOL,
_ACRT_APPLY_TO_LATE_BOUND_MODULES
#undef _APPLY
module_id_count
};
// Generate a table of module names that can be indexed by the module_id
// enumerators:
static wchar_t const* const module_names[module_id_count] =
{
#define _APPLY(_SYMBOL, _NAME) _CRT_WIDE(_NAME),
_ACRT_APPLY_TO_LATE_BOUND_MODULES
#undef _APPLY
};
// Generate enumerators for each of the functions:
enum function_id : unsigned
{
#define _APPLY(_FUNCTION, _MODULES) _CRT_CONCATENATE(_FUNCTION, _id),
_ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
#undef _APPLY
function_id_count
};
// Generate a typedef for each function of the form function_pft.
#define _APPLY(_FUNCTION, _MODULES) \
using _CRT_CONCATENATE(_FUNCTION, _pft) = decltype(_FUNCTION)*;
_ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
#undef _APPLY
}
// This table stores the module handles that we have obtained via LoadLibrary.
// If a handle is null, we have not yet attempted to load that module. If a
// handle is -1 (INVALID_HANDLE_VALUE), we have attempted to load the module
// but the attempt failed.
static HMODULE module_handles[module_id_count];
// This table stores the function pointers that we have loaded dynamically. The
// function pointers are stored in encoded form via __crt_fast_encode_ponter. If
// a function pointer is an encoded null pointer, we have not yet attempted to
// get that function pointer. If a function pointer is an encoded -1, we have
// attempted to get that function pointer but the attempt failed.
static void* encoded_function_pointers[function_id_count];
extern "C" bool __cdecl __acrt_initialize_winapi_thunks()
{
void* const encoded_nullptr = __crt_fast_encode_pointer(nullptr);
for (void*& p : encoded_function_pointers)
{
p = encoded_nullptr;
}
return true;
}
extern "C" bool __cdecl __acrt_uninitialize_winapi_thunks(bool const terminating)
{
// If the process is terminating, there's no need to free any module handles
if (terminating)
{
return true;
}
for (HMODULE& module : module_handles)
{
if (module)
{
if (module != INVALID_HANDLE_VALUE)
{
FreeLibrary(module);
}
module = nullptr;
}
}
return true;
}
static __forceinline void* __cdecl invalid_function_sentinel() throw()
{
return reinterpret_cast<void*>(static_cast<uintptr_t>(-1));
}
static HMODULE __cdecl try_load_library_from_system_directory(wchar_t const* const name) throw()
{
HMODULE const handle = LoadLibraryExW(name, nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (handle)
{
return handle;
}
// LOAD_LIBRARY_SEARCH_SYSTEM32 is only supported by Windows 7 and above; if
// the OS does not support this flag, try again without it. On these OSes,
// all APISets will be forwarders. To prevent DLL hijacking, do not attempt
// to load the APISet forwarders dynamically. This will cause our caller to
// fall back to the real DLL (e.g. kernel32). All of those are known DLLs.
if (GetLastError() == ERROR_INVALID_PARAMETER &&
wcsncmp(name, L"api-ms-", 7) != 0 &&
wcsncmp(name, L"ext-ms-", 7) != 0)
{
return LoadLibraryExW(name, nullptr, 0);
}
return nullptr;
}
static HMODULE __cdecl try_get_module(module_id const id) throw()
{
// First check to see if we've cached the module handle:
if (HMODULE const cached_handle = __crt_interlocked_read_pointer(module_handles + id))
{
if (cached_handle == INVALID_HANDLE_VALUE)
{
return nullptr;
}
return cached_handle;
}
// If we haven't yet cached the module handle, try to load the library. If
// this fails, cache the sentinel handle value INVALID_HANDLE_VALUE so that
// we don't attempt to load the module again:
HMODULE const new_handle = try_load_library_from_system_directory(module_names[id]);
if (!new_handle)
{
if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(module_handles + id, INVALID_HANDLE_VALUE))
{
_ASSERTE(cached_handle == INVALID_HANDLE_VALUE);
}
return nullptr;
}
// Swap the new handle into the cache. If the cache no longer contained a
// null handle, then some other thread loaded the module and cached the
// handle while we were doing the same. In that case, we free the handle
// once to maintain the reference count:
if (HMODULE const cached_handle = __crt_interlocked_exchange_pointer(module_handles + id, new_handle))
{
_ASSERTE(cached_handle == new_handle);
FreeLibrary(new_handle);
}
return new_handle;
}
static HMODULE __cdecl try_get_first_available_module(
module_id const* const first,
module_id const* const last
) throw()
{
for (module_id const* it = first; it != last; ++it)
{
HMODULE const handle = try_get_module(*it);
if (handle)
{
return handle;
}
}
return nullptr;
}
static __forceinline void* __cdecl 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
) throw()
{
HMODULE const module_handle = try_get_first_available_module(first_module_id, last_module_id);
if (!module_handle)
{
return nullptr;
}
return reinterpret_cast<void*>(GetProcAddress(module_handle, name));
}
static void* __cdecl 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
) throw()
{
// First check to see if we've cached the function pointer:
{
void* const cached_fp = __crt_fast_decode_pointer(
__crt_interlocked_read_pointer(encoded_function_pointers + id));
if (cached_fp == invalid_function_sentinel())
{
return nullptr;
}
if (cached_fp)
{
return cached_fp;
}
}
// If we haven't yet cached the function pointer, try to import it from any
// of the modules in which it might be defined. If this fails, cache the
// sentinel pointer so that we don't attempt to load this function again:
void* const new_fp = try_get_proc_address_from_first_available_module(name, first_module_id, last_module_id);
if (!new_fp)
{
void* const cached_fp = __crt_fast_decode_pointer(
__crt_interlocked_exchange_pointer(
encoded_function_pointers + id,
__crt_fast_encode_pointer(invalid_function_sentinel())));
if (cached_fp)
{
_ASSERTE(cached_fp == invalid_function_sentinel());
}
return nullptr;
}
// Swap the newly obtained function pointer into the cache. The cache may
// no longer contain an encoded null pointer if another thread obtained the
// function address while we were doing the same (both threads should have
// gotten the same function pointer):
{
void* const cached_fp = __crt_fast_decode_pointer(
__crt_interlocked_exchange_pointer(
encoded_function_pointers + id,
__crt_fast_encode_pointer(new_fp)));
if (cached_fp)
{
_ASSERTE(cached_fp == new_fp);
}
}
return new_fp;
}
// Generate accessors that wrap the general try_get_function for each function,
// passing the correct set of candidate modules and returning a function pointer
// of the correct type:
#define _APPLY(_FUNCTION, _MODULES) \
static _CRT_CONCATENATE(_FUNCTION, _pft) __cdecl _CRT_CONCATENATE(try_get_, _FUNCTION)() throw() \
{ \
static module_id const candidate_modules[] = _CRT_UNPARENTHESIZE(_MODULES); \
\
return reinterpret_cast<_CRT_CONCATENATE(_FUNCTION, _pft)>(try_get_function( \
_CRT_CONCATENATE(_FUNCTION, _id), \
_CRT_STRINGIZE(_FUNCTION), \
candidate_modules, \
candidate_modules + _countof(candidate_modules))); \
}
_ACRT_APPLY_TO_LATE_BOUND_FUNCTIONS
#undef _APPLY
extern "C" BOOL WINAPI __acrt_AreFileApisANSI()
{
if (auto const are_file_apis_ansi = try_get_AreFileApisANSI())
{
return are_file_apis_ansi();
}
// If we were unable to get the AreFileApisANSI function, we can safely
// assume that the file APIs are, in fact, ANSI:
return TRUE;
}
extern "C" int WINAPI __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
)
{
if (auto const compare_string_ex = try_get_CompareStringEx())
{
// On WCOS devices, CompareStringEx may calls into icu.dll which is an OS component using the UCRT.
// If icu.dll calls any UCRT export under OS mode (ex: malloc), then CompareStringEx will return under Prog Mode even if
// we started in OS mode. To prevent this, an OS mode guard is in place.
__crt_state_management::scoped_global_state_reset os_mode_guard;
return compare_string_ex(locale_name, flags, string1, string1_count, string2, string2_count, version, reserved, param);
}
return CompareStringW(__acrt_LocaleNameToLCID(locale_name, 0), flags, string1, string1_count, string2, string2_count);
}
// This has been split into its own function to work around a bug in the Dev12
// C++ compiler where nested captureless lambdas are not convertible to the
// required function pointer type.
static BOOL enum_system_locales_ex_nolock(
LOCALE_ENUMPROCEX const enum_proc
) throw()
{
static LOCALE_ENUMPROCEX static_enum_proc;
static_enum_proc = __crt_fast_encode_pointer(enum_proc);
BOOL const result = EnumSystemLocalesW(
[](LPWSTR locale_string) { return __crt_fast_decode_pointer(static_enum_proc)(locale_string, 0, 0); },
LCID_INSTALLED);
static_enum_proc = __crt_fast_encode_pointer(nullptr);
return result;
}
extern "C" BOOL WINAPI __acrt_EnumSystemLocalesEx(
LOCALE_ENUMPROCEX const enum_proc,
DWORD const flags,
LPARAM const param,
LPVOID const reserved
)
{
if (auto const enum_system_locales_ex = try_get_EnumSystemLocalesEx())
{
return enum_system_locales_ex(enum_proc, flags, param, reserved);
}
return __acrt_lock_and_call(__acrt_locale_lock, [&]() -> BOOL
{
return enum_system_locales_ex_nolock(enum_proc);
});
}
extern "C" DWORD WINAPI __acrt_FlsAlloc(PFLS_CALLBACK_FUNCTION const callback)
{
#if FLS_ALWAYS_AVAILABLE
return FlsAlloc(callback);
#else
if (auto const fls_alloc = try_get_FlsAlloc())
{
return fls_alloc(callback);
}
return TlsAlloc();
#endif
}
extern "C" BOOL WINAPI __acrt_FlsFree(DWORD const fls_index)
{
#if FLS_ALWAYS_AVAILABLE
return FlsFree(fls_index);
#else
if (auto const fls_free = try_get_FlsFree())
{
return fls_free(fls_index);
}
return TlsFree(fls_index);
#endif
}
extern "C" PVOID WINAPI __acrt_FlsGetValue(DWORD const fls_index)
{
#if FLS_ALWAYS_AVAILABLE
return FlsGetValue(fls_index);
#else
if (auto const fls_get_value = try_get_FlsGetValue())
{
return fls_get_value(fls_index);
}
return TlsGetValue(fls_index);
#endif
}
extern "C" BOOL WINAPI __acrt_FlsSetValue(DWORD const fls_index, PVOID const fls_data)
{
#if FLS_ALWAYS_AVAILABLE
return FlsSetValue(fls_index, fls_data);
#else
if (auto const fls_set_value = try_get_FlsSetValue())
{
return fls_set_value(fls_index, fls_data);
}
return TlsSetValue(fls_index, fls_data);
#endif
}
extern "C" int WINAPI __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
)
{
if (auto const get_date_format_ex = try_get_GetDateFormatEx())
{
return get_date_format_ex(locale_name, flags, date, format, buffer, buffer_count, calendar);
}
return GetDateFormatW(__acrt_LocaleNameToLCID(locale_name, 0), flags, date, format, buffer, buffer_count);
}
extern "C" int WINAPI __acrt_GetTempPath2W(
DWORD nBufferLength,
LPWSTR lpBuffer
)
{
if (auto const get_temp_path2w = try_get_GetTempPath2W())
{
return get_temp_path2w(nBufferLength, lpBuffer);
}
return GetTempPathW(nBufferLength, lpBuffer);
}
extern "C" DWORD64 WINAPI __acrt_GetEnabledXStateFeatures()
{
if (auto const get_enabled_xstate_features = try_get_GetEnabledXStateFeatures())
{
return get_enabled_xstate_features();
}
abort(); // No fallback; callers should check availablility before calling
}
extern "C" int WINAPI __acrt_GetLocaleInfoEx(
LPCWSTR const locale_name,
LCTYPE const lc_type,
LPWSTR const data,
int const data_count
)
{
if (auto const get_locale_info_ex = try_get_GetLocaleInfoEx())
{
return get_locale_info_ex(locale_name, lc_type, data, data_count);
}
return GetLocaleInfoW(__acrt_LocaleNameToLCID(locale_name, 0), lc_type, data, data_count);
}
extern "C" VOID WINAPI __acrt_GetSystemTimePreciseAsFileTime(LPFILETIME const system_time)
{
if (auto const get_system_time_precise_as_file_time = try_get_GetSystemTimePreciseAsFileTime())
{
return get_system_time_precise_as_file_time(system_time);
}
return GetSystemTimeAsFileTime(system_time);
}
extern "C" int WINAPI __acrt_GetTimeFormatEx(
LPCWSTR const locale_name,
DWORD const flags,
SYSTEMTIME CONST* const time,
LPCWSTR const format,
LPWSTR const buffer,
int const buffer_count
)
{
if (auto const get_time_format_ex = try_get_GetTimeFormatEx())
{
return get_time_format_ex(locale_name, flags, time, format, buffer, buffer_count);
}
return GetTimeFormatW(__acrt_LocaleNameToLCID(locale_name, 0), flags, time, format, buffer, buffer_count);
}
extern "C" int WINAPI __acrt_GetUserDefaultLocaleName(
LPWSTR const locale_name,
int const locale_name_count
)
{
if (auto const get_user_default_locale_name = try_get_GetUserDefaultLocaleName())
{
return get_user_default_locale_name(locale_name, locale_name_count);
}
return __acrt_LCIDToLocaleName(GetUserDefaultLCID(), locale_name, locale_name_count, 0);
}
extern "C" BOOL WINAPI __acrt_GetXStateFeaturesMask(
PCONTEXT const context,
PDWORD64 const feature_mask
)
{
if (auto const get_xstate_features_mask = try_get_GetXStateFeaturesMask())
{
return get_xstate_features_mask(context, feature_mask);
}
abort(); // No fallback; callers should check availablility before calling
}
extern "C" BOOL WINAPI __acrt_InitializeCriticalSectionEx(
LPCRITICAL_SECTION const critical_section,
DWORD const spin_count,
DWORD const flags
)
{
if (auto const initialize_critical_section_ex = try_get_InitializeCriticalSectionEx())
{
return initialize_critical_section_ex(critical_section, spin_count, flags);
}
return InitializeCriticalSectionAndSpinCount(critical_section, spin_count);
}
extern "C" BOOL WINAPI __acrt_IsValidLocaleName(LPCWSTR const locale_name)
{
if (auto const is_valid_locale_name = try_get_IsValidLocaleName())
{
return is_valid_locale_name(locale_name);
}
return IsValidLocale(__acrt_LocaleNameToLCID(locale_name, 0), LCID_INSTALLED);
}
extern "C" int WINAPI __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
)
{
if (auto const lc_map_string_ex = try_get_LCMapStringEx())
{
return lc_map_string_ex(locale_name, flags, source, source_count, destination, destination_count, version, reserved, sort_handle);
}
#pragma warning(disable:__WARNING_PRECONDITION_NULLTERMINATION_VIOLATION) // 26035 LCMapStringW annotation is presently incorrect 11/26/2014 Jaykrell
return LCMapStringW(__acrt_LocaleNameToLCID(locale_name, 0), flags, source, source_count, destination, destination_count);
}
extern "C" int WINAPI __acrt_LCIDToLocaleName(
LCID const locale,
LPWSTR const name,
int const name_count,
DWORD const flags
)
{
if (auto const lcid_to_locale_name = try_get_LCIDToLocaleName())
{
return lcid_to_locale_name(locale, name, name_count, flags);
}
return __acrt_DownlevelLCIDToLocaleName(locale, name, name_count);
}
extern "C" LCID WINAPI __acrt_LocaleNameToLCID(
LPCWSTR const name,
DWORD const flags
)
{
if (auto const locale_name_to_lcid = try_get_LocaleNameToLCID())
{
return locale_name_to_lcid(name, flags);
}
return __acrt_DownlevelLocaleNameToLCID(name);
}
extern "C" PVOID WINAPI __acrt_LocateXStateFeature(
PCONTEXT const content,
DWORD const feature_id,
PDWORD const length
)
{
if (auto const locate_xstate_feature = try_get_LocateXStateFeature())
{
return locate_xstate_feature(content, feature_id, length);
}
abort(); // No fallback; callers should check availablility before calling
}
extern "C" int WINAPI __acrt_MessageBoxA(
HWND const hwnd,
LPCSTR const text,
LPCSTR const caption,
UINT const type
)
{
if (auto const message_box_a = try_get_MessageBoxA())
{
return message_box_a(hwnd, text, caption, type);
}
abort(); // No fallback; callers should check availablility before calling
}
extern "C" int WINAPI __acrt_MessageBoxW(
HWND const hwnd,
LPCWSTR const text,
LPCWSTR const caption,
UINT const type
)
{
if (auto const message_box_w = try_get_MessageBoxW())
{
return message_box_w(hwnd, text, caption, type);
}
abort(); // No fallback; callers should check availablility before calling
}
extern "C" BOOLEAN WINAPI __acrt_RtlGenRandom(
PVOID const buffer,
ULONG const buffer_count
)
{
if (auto const rtl_gen_random = try_get_SystemFunction036())
{
return rtl_gen_random(buffer, buffer_count);
}
abort(); // No fallback (this function should exist)
}
extern "C" HRESULT WINAPI __acrt_RoInitialize(RO_INIT_TYPE const init_type)
{
if (auto const ro_initialize = try_get_RoInitialize())
{
return ro_initialize(init_type);
}
return S_OK; // No fallback (this is a best-effort wrapper)
}
extern "C" void WINAPI __acrt_RoUninitialize()
{
if (auto const ro_uninitialize = try_get_RoUninitialize())
{
return ro_uninitialize();
}
// No fallback (this is a best-effort wrapper)
}
LONG WINAPI __acrt_AppPolicyGetProcessTerminationMethodInternal(_Out_ AppPolicyProcessTerminationMethod* policy)
{
if (auto const app_policy_get_process_terminaton_method_claims = try_get_AppPolicyGetProcessTerminationMethod())
{
return app_policy_get_process_terminaton_method_claims(GetCurrentThreadEffectiveToken(), policy);
}
return STATUS_NOT_FOUND;
}
LONG WINAPI __acrt_AppPolicyGetThreadInitializationTypeInternal(_Out_ AppPolicyThreadInitializationType* policy)
{
if (auto const app_policy_get_thread_initialization_type_claims = try_get_AppPolicyGetThreadInitializationType())
{
return app_policy_get_thread_initialization_type_claims(GetCurrentThreadEffectiveToken(), policy);
}
return STATUS_NOT_FOUND;
}
LONG WINAPI __acrt_AppPolicyGetShowDeveloperDiagnosticInternal(_Out_ AppPolicyShowDeveloperDiagnostic* policy)
{
if (auto const app_policy_get_show_developer_diagnostic_claims = try_get_AppPolicyGetShowDeveloperDiagnostic())
{
return app_policy_get_show_developer_diagnostic_claims(GetCurrentThreadEffectiveToken(), policy);
}
return STATUS_NOT_FOUND;
}
LONG WINAPI __acrt_AppPolicyGetWindowingModelInternal(_Out_ AppPolicyWindowingModel* policy)
{
if (auto const app_policy_get_windowing_model_claims = try_get_AppPolicyGetWindowingModel())
{
return app_policy_get_windowing_model_claims(GetCurrentThreadEffectiveToken(), policy);
}
return STATUS_NOT_FOUND;
}
extern "C" BOOL WINAPI __acrt_SetThreadStackGuarantee(PULONG const stack_size_in_bytes)
{
if (auto const set_thread_stack_guarantee = try_get_SetThreadStackGuarantee())
{
return set_thread_stack_guarantee(stack_size_in_bytes);
}
return FALSE;
}
extern "C" bool __cdecl __acrt_can_show_message_box()
{
bool can_show_message_box = false;
if (__acrt_get_windowing_model_policy() == windowing_model_policy_hwnd
&& try_get_MessageBoxA() != nullptr
&& try_get_MessageBoxW() != nullptr)
{
can_show_message_box = true;
}
return can_show_message_box;
}
extern "C" bool __cdecl __acrt_can_use_vista_locale_apis()
{
return try_get_CompareStringEx() != nullptr;
}
// This function simply attempts to get each of the locale-related APIs. This
// allows a caller to "pre-load" the modules in which these APIs are hosted. We
// use this in the _wsetlocale implementation to avoid calls to LoadLibrary while
// the locale lock is held.
extern "C" void __cdecl __acrt_eagerly_load_locale_apis()
{
try_get_AreFileApisANSI();
try_get_CompareStringEx();
try_get_EnumSystemLocalesEx();
try_get_GetDateFormatEx();
try_get_GetLocaleInfoEx();
try_get_GetTimeFormatEx();
try_get_GetUserDefaultLocaleName();
try_get_IsValidLocaleName();
try_get_LCMapStringEx();
try_get_LCIDToLocaleName();
try_get_LocaleNameToLCID();
}
extern "C" bool __cdecl __acrt_can_use_xstate_apis()
{
return try_get_LocateXStateFeature() != nullptr;
}
extern "C" HWND __cdecl __acrt_get_parent_window()
{
auto const get_active_window = try_get_GetActiveWindow();
if (!get_active_window)
{
return nullptr;
}
HWND const active_window = get_active_window();
if (!active_window)
{
return nullptr;
}
auto const get_last_active_popup = try_get_GetLastActivePopup();
if (!get_last_active_popup)
{
return active_window;
}
return get_last_active_popup(active_window);
}
extern "C" bool __cdecl __acrt_is_interactive()
{
auto const get_process_window_station = try_get_GetProcessWindowStation();
if (!get_process_window_station)
{
return true;
}
auto const get_user_object_information = try_get_GetUserObjectInformationW();
if (!get_user_object_information)
{
return true;
}
HWINSTA const hwinsta = get_process_window_station();
if (!hwinsta)
{
return false;
}
USEROBJECTFLAGS uof{};
if (!get_user_object_information(hwinsta, UOI_FLAGS, &uof, sizeof(uof), nullptr))
{
return false;
}
if ((uof.dwFlags & WSF_VISIBLE) == 0)
{
return false;
}
return true;
}