2024-05-11 07:03:12 +02:00
|
|
|
//
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
2024-10-16 13:02:08 +03:00
|
|
|
#ifdef __clang__
|
|
|
|
static LOCALE_ENUMPROCEX static_enum_proc;
|
|
|
|
static BOOL CALLBACK LocaleEnumProcW(LPWSTR locale_string)
|
|
|
|
{
|
|
|
|
return __crt_fast_decode_pointer(static_enum_proc)(locale_string, 0, 0);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-05-11 07:03:12 +02:00
|
|
|
// 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()
|
|
|
|
{
|
2024-10-16 13:02:08 +03:00
|
|
|
#ifndef __clang__
|
2024-05-11 07:03:12 +02:00
|
|
|
static LOCALE_ENUMPROCEX static_enum_proc;
|
2024-10-16 13:02:08 +03:00
|
|
|
#endif
|
2024-05-11 07:03:12 +02:00
|
|
|
|
|
|
|
static_enum_proc = __crt_fast_encode_pointer(enum_proc);
|
2024-10-16 13:02:08 +03:00
|
|
|
BOOL const result = EnumSystemLocalesW((LOCALE_ENUMPROCW)
|
|
|
|
#ifdef __clang__
|
|
|
|
LocaleEnumProcW,
|
|
|
|
#else
|
|
|
|
[](LPWSTR locale_string)
|
|
|
|
#if defined(__GNUC__) && !defined(__clang__)
|
|
|
|
__stdcall
|
|
|
|
#endif // __GNUC__
|
|
|
|
{ return __crt_fast_decode_pointer(static_enum_proc)(locale_string, 0, 0); },
|
|
|
|
#endif
|
2024-05-11 07:03:12 +02:00
|
|
|
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;
|
|
|
|
}
|