Get latest upstream changes from internal project
This commit is contained in:
+183
-91
@@ -5,7 +5,8 @@
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
// NOTE: DN_Mem
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: DN OS layer implementation
|
||||
static DN_U32 DN_OS_MemConvertPageToOSFlags_(DN_U32 protect)
|
||||
{
|
||||
DN_Assert((protect & ~DN_MemPage_All) == 0);
|
||||
@@ -231,6 +232,21 @@ DN_API DN_OSDiskSpace DN_OS_DiskSpace(DN_Str8 path)
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSMemoryInfo DN_OS_MemoryInfo()
|
||||
{
|
||||
DN_OSMemoryInfo result = {};
|
||||
MEMORYSTATUSEX status = {};
|
||||
status.dwLength = sizeof(status);
|
||||
if (GlobalMemoryStatusEx(&status)) {
|
||||
result.success = true;
|
||||
result.total_phys = status.ullTotalPhys;
|
||||
result.avail_phys = status.ullAvailPhys;
|
||||
result.total_virtual = status.ullTotalVirtual;
|
||||
result.avail_virtual = status.ullAvailVirtual;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_SetEnvVar(DN_Str8 name, DN_Str8 value)
|
||||
{
|
||||
DN_TcScratch scratch = DN_TcScratchBeginArena(nullptr, 0);
|
||||
@@ -247,7 +263,7 @@ DN_API DN_Str8 DN_OS_ExePath(DN_Arena *arena)
|
||||
if (!arena)
|
||||
return result;
|
||||
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
|
||||
DN_Str16 exe_dir16 = DN_OS_W32EXEPathW(&scratch.arena);
|
||||
DN_Str16 exe_dir16 = DN_OS_W32ExePathW(&scratch.arena);
|
||||
result = DN_OS_W32Str16ToStr8(arena, exe_dir16);
|
||||
DN_TcScratchEnd(&scratch);
|
||||
return result;
|
||||
@@ -536,6 +552,25 @@ DN_API bool DN_OS_PathDelete(DN_Str8 path)
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSPathResult DN_OS_PathCanonicalise(DN_Arena *arena, DN_Str8 path, DN_ErrSink *error)
|
||||
{
|
||||
DN_OSPathResult result = {};
|
||||
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
|
||||
DN_Str16 path16 = DN_OS_W32Str8ToStr16(&scratch.arena, path);
|
||||
|
||||
wchar_t out_path[1024];
|
||||
HRESULT convert_result = PathCchCanonicalizeEx(out_path, DN_ArrayCountU(out_path), path16.data, PATHCCH_ALLOW_LONG_PATHS);
|
||||
if (convert_result == S_OK) {
|
||||
result.success = true;
|
||||
result.path = DN_OS_W32Str16ToStr8(arena, DN_Str16FromPtr(out_path, DN_CStr16Count(out_path)));
|
||||
} else {
|
||||
DN_OSW32Error win_error = DN_OS_W32LastError(&scratch.arena);
|
||||
DN_ErrSinkAppendF(error, win_error.code, "Failed to canonicalise path. %.*s", DN_Str8PrintFmt(win_error.msg));
|
||||
}
|
||||
DN_TcScratchEnd(&scratch);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_OS_PathIsFile(DN_Str8 path)
|
||||
{
|
||||
bool result = false;
|
||||
@@ -648,9 +683,9 @@ DN_API bool DN_OS_PathIterateDir(DN_Str8 path, DN_OSDirIterator *it)
|
||||
// add those characters in this branch, so overwrite the null
|
||||
// character, add the glob and re-null terminate the buffer.
|
||||
if (needs_asterisks)
|
||||
adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path));
|
||||
adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s*", DN_Str8PrintFmt(path)).value;
|
||||
else
|
||||
adjusted_path = DN_Str8FmtOsPathArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path));
|
||||
adjusted_path = DN_Str8PathFmtOsArena(&scratch.arena, "%.*s/*", DN_Str8PrintFmt(path)).value;
|
||||
}
|
||||
|
||||
path16 = DN_OS_W32Str8ToStr16(&scratch.arena, adjusted_path);
|
||||
@@ -1057,44 +1092,6 @@ DN_API DN_OSExecAsyncHandle DN_OS_ExecAsync(DN_Str8Slice cmd_line, DN_OSExecArgs
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
|
||||
{
|
||||
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
|
||||
QueryPerformanceFrequency(&w32->qpc_frequency);
|
||||
|
||||
// NOTE: DPI
|
||||
HMODULE user32 = LoadLibraryA("user32.dll");
|
||||
if (user32) {
|
||||
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
|
||||
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
|
||||
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
|
||||
FreeLibrary(user32);
|
||||
}
|
||||
|
||||
// NOTE: SetThreadDesc
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32) {
|
||||
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
|
||||
FreeLibrary(kernel32);
|
||||
}
|
||||
|
||||
// NOTE: win32 bcrypt
|
||||
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
|
||||
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
|
||||
if (w32->bcrypt_rng_handle && init_status == 0)
|
||||
w32->bcrypt_init_success = true;
|
||||
else
|
||||
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Core *DN_OS_W32GetCore()
|
||||
{
|
||||
DN_Core *dn = DN_Get();
|
||||
DN_Assert(dn && dn->os_init);
|
||||
DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context;
|
||||
return result;
|
||||
}
|
||||
|
||||
static DN_OSW32SyncPrimitive *DN_OS_U64ToW32SyncPrimitive_(DN_U64 u64)
|
||||
{
|
||||
DN_OSW32SyncPrimitive *result = nullptr;
|
||||
@@ -1140,7 +1137,6 @@ static void DN_OS_W32DeallocSyncPrimitive_(DN_OSW32SyncPrimitive *primitive)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: DN_OSSemaphore
|
||||
DN_API DN_OSSemaphore DN_OS_SemaphoreInit(DN_U32 initial_count)
|
||||
{
|
||||
DN_OSSemaphore result = {};
|
||||
@@ -1189,7 +1185,6 @@ DN_API DN_OSSemaphoreWaitResult DN_OS_SemaphoreWait(DN_OSSemaphore *semaphore, D
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: DN_OSBarrier
|
||||
DN_API DN_OSBarrier DN_OS_BarrierInit(DN_U32 thread_count)
|
||||
{
|
||||
DN_OSBarrier result = {};
|
||||
@@ -1260,7 +1255,6 @@ DN_API void DN_OS_MutexUnlock(DN_OSMutex *mutex)
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: DN_OSConditionVariable ////////////////////////////////////////////////////////////////////
|
||||
DN_API DN_OSConditionVariable DN_OS_ConditionVariableInit()
|
||||
{
|
||||
DN_OSW32SyncPrimitive *primitive = DN_OS_W32AllocSyncPrimitive_();
|
||||
@@ -1444,6 +1438,69 @@ DN_API DN_U32 DN_OS_ThreadID()
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: DN Win32 book-keeping
|
||||
DN_API void DN_OS_W32Init(DN_OSW32Core *w32)
|
||||
{
|
||||
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
|
||||
QueryPerformanceFrequency(&w32->qpc_frequency);
|
||||
|
||||
// NOTE: DPI
|
||||
HMODULE user32 = LoadLibraryA("user32.dll");
|
||||
if (user32) {
|
||||
w32->get_dpi_for_window = (DN_OSW32GetDpiForWindowFunc* )GetProcAddress(user32, "GetDpiForWindow");
|
||||
w32->get_dpi_for_monitor = (DN_OSW32GetDpiForMonitorFunc * )GetProcAddress(user32, "GetDpiForMonitor");
|
||||
w32->get_system_metrics_for_dpi = (DN_OSW32GetSystemMetricsForDpiFunc *)GetProcAddress(user32, "GetSystemMetricsForDpi");
|
||||
FreeLibrary(user32);
|
||||
}
|
||||
|
||||
// NOTE: SetThreadDesc
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32) {
|
||||
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(kernel32, "SetThreadDescription");
|
||||
FreeLibrary(kernel32);
|
||||
}
|
||||
|
||||
// NOTE: win32 bcrypt
|
||||
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
|
||||
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
|
||||
if (w32->bcrypt_rng_handle && init_status == 0)
|
||||
w32->bcrypt_init_success = true;
|
||||
else
|
||||
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Core *DN_OS_W32GetCore()
|
||||
{
|
||||
DN_Core *dn = DN_Get();
|
||||
DN_Assert(dn && dn->os_init);
|
||||
DN_OSW32Core *result = DN_Cast(DN_OSW32Core *)dn->os.platform_context;
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
|
||||
{
|
||||
DN_OSW32Window *result = nullptr;
|
||||
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
|
||||
if (check->hwnd == hwnd)
|
||||
result = check;
|
||||
}
|
||||
|
||||
if (!result && arena) {
|
||||
result = DN_ArenaNewZ(arena, DN_OSW32Window);
|
||||
if (result) {
|
||||
result->hwnd = hwnd;
|
||||
if (w32->windows)
|
||||
w32->windows->next = result;
|
||||
result->next = w32->windows;
|
||||
w32->windows = result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Process management
|
||||
DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
|
||||
{
|
||||
// NOTE: SetThreadDescription is only available in
|
||||
@@ -1475,7 +1532,7 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
|
||||
|
||||
// TODO: Review warning 6320
|
||||
DN_MSVC_WARNING_PUSH
|
||||
DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER. This might mask exceptions that were not intended to be handled
|
||||
DN_MSVC_WARNING_DISABLE(6320) // Exception-filter expression is the constant EXCEPTION_ExeCUTE_HANDLER. This might mask exceptions that were not intended to be handled
|
||||
DN_MSVC_WARNING_DISABLE(6322) // Empty _except block
|
||||
__try {
|
||||
RaiseException(0x406D1388, 0, sizeof(info) / sizeof(void *), (const ULONG_PTR *)&info);
|
||||
@@ -1486,27 +1543,6 @@ DN_API void DN_OS_W32ThreadSetName(DN_Str8 name)
|
||||
DN_TcScratchEnd(&scratch);
|
||||
}
|
||||
|
||||
DN_API DN_OSW32Window* DN_OS_W32WindowFromHwndMaybeAlloc(DN_OSW32Core *w32, HWND hwnd, DN_Arena *arena)
|
||||
{
|
||||
DN_OSW32Window *result = nullptr;
|
||||
for (DN_OSW32Window *check = w32->windows; !result && check; check = check->next) {
|
||||
if (check->hwnd == hwnd)
|
||||
result = check;
|
||||
}
|
||||
|
||||
if (!result && arena) {
|
||||
result = DN_ArenaNewZ(arena, DN_OSW32Window);
|
||||
if (result) {
|
||||
result->hwnd = hwnd;
|
||||
if (w32->windows)
|
||||
w32->windows->next = result;
|
||||
result->next = w32->windows;
|
||||
w32->windows = result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg, WPARAM w_param, LPARAM l_param)
|
||||
{
|
||||
DN_OSW32Core *w32 = DN_OS_W32GetCore();
|
||||
@@ -1640,6 +1676,81 @@ DN_API LRESULT __stdcall DN_OS_W32WindowProcCustomTitlebar(HWND hwnd, UINT msg,
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_OS_W32MakeProcessDPIAware()
|
||||
{
|
||||
typedef bool SetProcessDpiAwareProc(void);
|
||||
typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS);
|
||||
typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/);
|
||||
|
||||
// NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It
|
||||
// appears we can make this robust by just loading user32.dll and using
|
||||
// GetProcAddress on the DPI function. If it's not there, we're on an old
|
||||
// version of windows, so we can call an older version of the API.
|
||||
void *lib_handle = LoadLibraryA("user32.dll");
|
||||
if (!lib_handle)
|
||||
return;
|
||||
|
||||
if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext"))
|
||||
set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness"))
|
||||
set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE);
|
||||
else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware"))
|
||||
set_process_dpi_aware();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: DLL
|
||||
DN_API void DN_OS_W32DllUnload(DN_OSW32DllCore *dll)
|
||||
{
|
||||
if (dll) {
|
||||
if (dll->handle) {
|
||||
FreeLibrary(DN_Cast(HMODULE) dll->handle);
|
||||
dll->handle = nullptr;
|
||||
}
|
||||
|
||||
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count))
|
||||
it.data->func_ptr = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DN_API DN_OSW32DllLoadFunctionsResult DN_OS_W32DllLoadFunctions(DN_OSW32DllCore *dll, DN_Str8 dll_path)
|
||||
{
|
||||
DN_OSW32DllLoadFunctionsResult result = DN_OSW32DllLoadFunctionsResult_LoadLibraryFailed;
|
||||
HMODULE handle = LoadLibraryA(dll_path.data);
|
||||
if (handle) {
|
||||
bool all_good = true;
|
||||
|
||||
// NOTE: Validate that all the functions can be loaded from the DLL
|
||||
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) {
|
||||
DN_Str8 func_name = it.data->name;
|
||||
DN_AssertF(func_name.count && func_name.data[func_name.count] == 0, "Function name must be set and null-terminated");
|
||||
void *func_ptr = GetProcAddress(handle, func_name.data);
|
||||
all_good &= (func_ptr != nullptr);
|
||||
}
|
||||
|
||||
// NOTE: If all functions can be loaded, then mutate the user's `dll` struct
|
||||
if (all_good) {
|
||||
result = DN_OSW32DllLoadFunctionsResult_Ok;
|
||||
for (DN_ForItSize(it, DN_OSW32DllFunction, dll->functions, dll->functions_count)) {
|
||||
DN_Str8 func_name = it.data->name;
|
||||
it.data->func_ptr = GetProcAddress(handle, func_name.data);
|
||||
}
|
||||
|
||||
// NOTE: Cleanup the old handle
|
||||
if (dll->handle)
|
||||
FreeLibrary(DN_Cast(HMODULE) dll->handle);
|
||||
dll->handle = handle;
|
||||
DN_StackTraceReloadSymbols();
|
||||
} else {
|
||||
FreeLibrary(handle);
|
||||
result = DN_OSW32DllLoadFunctionsResult_FunctionMissing;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Errors
|
||||
DN_API DN_Str16 DN_OS_W32ErrorCodeToMsg16Alloc(DN_U32 error_code)
|
||||
{
|
||||
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
@@ -1702,28 +1813,8 @@ DN_API DN_OSW32Error DN_OS_W32LastErrorAlloc()
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_OS_W32MakeProcessDPIAware()
|
||||
{
|
||||
typedef bool SetProcessDpiAwareProc(void);
|
||||
typedef bool SetProcessDpiAwarenessProc(DPI_AWARENESS);
|
||||
typedef bool SetProcessDpiAwarenessContextProc(void * /*DPI_AWARENESS_CONTEXT*/);
|
||||
|
||||
// NOTE(doyle): Taken from cmuratori/refterm snippet on DPI awareness. It
|
||||
// appears we can make this robust by just loading user32.dll and using
|
||||
// GetProcAddress on the DPI function. If it's not there, we're on an old
|
||||
// version of windows, so we can call an older version of the API.
|
||||
void *lib_handle = LoadLibraryA("user32.dll");
|
||||
if (!lib_handle)
|
||||
return;
|
||||
|
||||
if (auto *set_process_dpi_awareness_context = DN_Cast(SetProcessDpiAwarenessContextProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwarenessContext"))
|
||||
set_process_dpi_awareness_context(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
else if (auto *set_process_dpi_awareness = DN_Cast(SetProcessDpiAwarenessProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAwareness"))
|
||||
set_process_dpi_awareness(DPI_AWARENESS_PER_MONITOR_AWARE);
|
||||
else if (auto *set_process_dpi_aware = DN_Cast(SetProcessDpiAwareProc *) GetProcAddress(DN_Cast(HMODULE) lib_handle, "SetProcessDpiAware"))
|
||||
set_process_dpi_aware();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Windows Str8 <-> Str16
|
||||
DN_API DN_Str16 DN_OS_W32Str8ToStr16(DN_Arena *arena, DN_Str8 src)
|
||||
{
|
||||
DN_Str16 result = {};
|
||||
@@ -1845,8 +1936,9 @@ DN_API DN_Str8 DN_OS_W32Str16ToStr8FromHeap(DN_Str16 src)
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE: Windows Executable Directory //////////////////////////////////////////
|
||||
DN_API DN_Str16 DN_OS_W32EXEPathW(DN_Arena *arena)
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// NOTE: Path navigation
|
||||
DN_API DN_Str16 DN_OS_W32ExePathW(DN_Arena *arena)
|
||||
{
|
||||
DN_TcScratch scratch = DN_TcScratchBeginArena(&arena, 1);
|
||||
DN_Str16 result = {};
|
||||
|
||||
Reference in New Issue
Block a user