From ea6ad4ac86dc466105945bd1ec3cdcd5121565fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=80=9A=E6=B4=B2?= Date: Fri, 13 Mar 2026 10:50:31 +0800 Subject: [PATCH] Global (Windows): prefers NTAPI for querying registry values --- src/common/impl/FFPlatform_windows.c | 11 +- src/common/windows/nt.h | 93 ++++ src/common/windows/registry.c | 444 +++++++++++++----- src/common/windows/registry.h | 73 ++- src/detection/cpu/cpu_windows.c | 26 +- src/detection/cursor/cursor_windows.c | 13 +- .../displayserver/displayserver_windows.c | 23 +- src/detection/gpu/gpu_windows.c | 15 +- src/detection/icons/icons_windows.c | 2 +- src/detection/os/os_windows.c | 12 +- .../terminalfont/terminalfont_windows.c | 17 +- .../terminalshell/terminalshell_windows.c | 2 +- src/detection/wallpaper/wallpaper_windows.c | 2 +- src/detection/wmtheme/wmtheme_windows.c | 41 +- tests/format.c | 2 +- 15 files changed, 575 insertions(+), 201 deletions(-) diff --git a/src/common/impl/FFPlatform_windows.c b/src/common/impl/FFPlatform_windows.c index d0bcb5889..5ca296afe 100644 --- a/src/common/impl/FFPlatform_windows.c +++ b/src/common/impl/FFPlatform_windows.c @@ -205,22 +205,23 @@ static const char* detectWine(void) static void getSystemReleaseAndVersion(FFPlatformSysinfo* info) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) return; uint32_t ubr = 0; - ffRegReadUint(hKey, L"UBR", &ubr, NULL); + ffRegReadValues(hKey, 2, (FFRegValueArg[]) { + FF_ARG(ubr, L"UBR"), + FF_ARG(info->version, L"BuildLabEx"), + }, NULL); - ffStrbufAppendF(&info->release, + ffStrbufSetF(&info->release, "%u.%u.%u.%u", (unsigned) SharedUserData->NtMajorVersion, (unsigned) SharedUserData->NtMinorVersion, (unsigned) SharedUserData->NtBuildNumber, (unsigned) ubr); - ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL); - const char* wineVersion = detectWine(); if (wineVersion) ffStrbufSetF(&info->name, "Wine_%s", wineVersion); diff --git a/src/common/windows/nt.h b/src/common/windows/nt.h index 4538c834f..1709e0b6f 100644 --- a/src/common/windows/nt.h +++ b/src/common/windows/nt.h @@ -1005,3 +1005,96 @@ NTSYSAPI NTSTATUS NTAPI RtlExpandEnvironmentStrings( _In_ SIZE_T DestinationLength, _Out_opt_ PSIZE_T ReturnLength ); + +NTSYSAPI NTSTATUS NTAPI NtOpenKey( + _Out_ PHANDLE KeyHandle, + _In_ ACCESS_MASK DesiredAccess, + _In_ POBJECT_ATTRIBUTES ObjectAttributes +); + +typedef enum _KEY_VALUE_INFORMATION_CLASS +{ + KeyValueBasicInformation, // KEY_VALUE_BASIC_INFORMATION + KeyValueFullInformation, // KEY_VALUE_FULL_INFORMATION + KeyValuePartialInformation, // KEY_VALUE_PARTIAL_INFORMATION + KeyValueFullInformationAlign64, // KEY_VALUE_FULL_INFORMATION_ALIGN64 + KeyValuePartialInformationAlign64, // KEY_VALUE_PARTIAL_INFORMATION_ALIGN64 + KeyValueLayerInformation, // KEY_VALUE_LAYER_INFORMATION + MaxKeyValueInfoClass +} KEY_VALUE_INFORMATION_CLASS; + +NTSYSAPI NTSTATUS NTAPI NtQueryValueKey( + _In_ HANDLE KeyHandle, + _In_ PCUNICODE_STRING ValueName, + _In_ KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyValueInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength +); + +NTSYSAPI NTSTATUS NTAPI RtlFormatCurrentUserKeyPath( + _Out_ PUNICODE_STRING CurrentUserKeyPath +); + +typedef struct _KEY_VALUE_PARTIAL_INFORMATION +{ + ULONG TitleIndex; + ULONG Type; + ULONG DataLength; + _Field_size_bytes_(DataLength) UCHAR Data[]; +} KEY_VALUE_PARTIAL_INFORMATION, *PKEY_VALUE_PARTIAL_INFORMATION; + +typedef enum _KEY_INFORMATION_CLASS +{ + KeyBasicInformation, // KEY_BASIC_INFORMATION + KeyNodeInformation, // KEY_NODE_INFORMATION + KeyFullInformation, // KEY_FULL_INFORMATION + KeyNameInformation, // KEY_NAME_INFORMATION + KeyCachedInformation, // KEY_CACHED_INFORMATION + KeyFlagsInformation, // KEY_FLAGS_INFORMATION + KeyVirtualizationInformation, // KEY_VIRTUALIZATION_INFORMATION + KeyHandleTagsInformation, // KEY_HANDLE_TAGS_INFORMATION + KeyTrustInformation, // KEY_TRUST_INFORMATION + KeyLayerInformation, // KEY_LAYER_INFORMATION + MaxKeyInfoClass +} KEY_INFORMATION_CLASS; + +NTSYSAPI NTSTATUS NTAPI NtEnumerateKey( + _In_ HANDLE KeyHandle, + _In_ ULONG Index, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength +); + +typedef struct _KEY_BASIC_INFORMATION +{ + LARGE_INTEGER LastWriteTime; // Number of 100-nanosecond intervals since this key or any of its values changed. + ULONG TitleIndex; // Reserved // A legacy field originally intended for use with localization such as an index of a resource table. + ULONG NameLength; // The size, in bytes, of the key name string in the Name array. + _Field_size_bytes_(NameLength) WCHAR Name[]; // The name of the registry key. This string is not null-terminated. +} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION; + +typedef struct _KEY_FULL_INFORMATION +{ + LARGE_INTEGER LastWriteTime; + ULONG TitleIndex; + ULONG ClassOffset; + ULONG ClassLength; + ULONG SubKeys; + ULONG MaxNameLength; + ULONG MaxClassLength; + ULONG Values; + ULONG MaxValueNameLength; + ULONG MaxValueDataLength; + WCHAR Class[]; +} KEY_FULL_INFORMATION, *PKEY_FULL_INFORMATION; + +NTSYSAPI NTSTATUS NTAPI NtQueryKey( + _In_ HANDLE KeyHandle, + _In_ KEY_INFORMATION_CLASS KeyInformationClass, + _Out_writes_bytes_to_opt_(Length, *ResultLength) PVOID KeyInformation, + _In_ ULONG Length, + _Out_ PULONG ResultLength +); diff --git a/src/common/windows/registry.c b/src/common/windows/registry.c index c46c877ff..fd06b7c90 100644 --- a/src/common/windows/registry.c +++ b/src/common/windows/registry.c @@ -1,17 +1,21 @@ #include "registry.h" #include "unicode.h" #include "common/mallocHelper.h" +#include "common/windows/nt.h" -static const char* hKey2Str(HKEY hKey) +#include +#include + +static HANDLE hRootKeys[8 /*(uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS - (uintptr_t) HKEY_CLASSES_ROOT + 1*/]; + +static const char* hKey2Str(HANDLE hRootKey) { - #define HKEY_CASE(compareKey) if(hKey == compareKey) return #compareKey; + #define HKEY_CASE(compareKey) if(hRootKey == hRootKeys[(uintptr_t)compareKey - (uintptr_t)HKEY_CLASSES_ROOT]) return #compareKey; HKEY_CASE(HKEY_CLASSES_ROOT) HKEY_CASE(HKEY_CURRENT_USER) HKEY_CASE(HKEY_LOCAL_MACHINE) HKEY_CASE(HKEY_USERS) HKEY_CASE(HKEY_PERFORMANCE_DATA) - HKEY_CASE(HKEY_PERFORMANCE_TEXT) - HKEY_CASE(HKEY_PERFORMANCE_NLSTEXT) HKEY_CASE(HKEY_CURRENT_CONFIG) HKEY_CASE(HKEY_DYN_DATA) HKEY_CASE(HKEY_CURRENT_USER_LOCAL_SETTINGS) @@ -20,152 +24,370 @@ static const char* hKey2Str(HKEY hKey) return "UNKNOWN"; } -bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error) +HANDLE ffRegGetRootKeyHandle(HKEY hKey) { - if(RegOpenKeyExW(hKey, subKeyW, 0, KEY_READ, result) != ERROR_SUCCESS) + assert(hKey); + assert((uintptr_t) hKey >= (uintptr_t) HKEY_CLASSES_ROOT && (uintptr_t) hKey <= (uintptr_t) HKEY_CURRENT_USER_LOCAL_SETTINGS); + + if (hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT]) + return hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT]; + + HANDLE result = NULL; + switch ((uintptr_t) hKey) { - if(error) + case (uintptr_t) HKEY_CURRENT_USER: { + UNICODE_STRING path = {}; + if (!NT_SUCCESS(RtlFormatCurrentUserKeyPath(&path))) return NULL; + if (!NT_SUCCESS(NtOpenKey(&result, KEY_READ, &(OBJECT_ATTRIBUTES) { + .Length = sizeof(OBJECT_ATTRIBUTES), + .RootDirectory = NULL, + .ObjectName = &path, + }))) + { + RtlFreeUnicodeString(&path); + return NULL; + } + RtlFreeUnicodeString(&path); + break; + } + case (uintptr_t) HKEY_LOCAL_MACHINE: { + if (!NT_SUCCESS(NtOpenKey(&result, KEY_READ, &(OBJECT_ATTRIBUTES) { + .Length = sizeof(OBJECT_ATTRIBUTES), + .RootDirectory = NULL, + .ObjectName = &(UNICODE_STRING)RTL_CONSTANT_STRING(L"\\Registry\\Machine"), + }))) + return NULL; + break; + } + default: + // Unsupported + assert(false); + return NULL; + } + hRootKeys[(uintptr_t) hKey - (uintptr_t) HKEY_CLASSES_ROOT] = result; + return result; +} + +bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error) +{ + assert(hKey); + assert(subKeyW); + assert(result); + + USHORT subKeyLen = (USHORT) (wcslen(subKeyW) * sizeof(wchar_t)); + if (!NT_SUCCESS(NtOpenKey(result, KEY_READ, &(OBJECT_ATTRIBUTES) { + .Length = sizeof(OBJECT_ATTRIBUTES), + .RootDirectory = hKey, + .ObjectName = &(UNICODE_STRING) { + .Length = subKeyLen, + .MaximumLength = subKeyLen + (USHORT) sizeof(wchar_t), + .Buffer = (wchar_t*) subKeyW, + }, + }))) + { + if (error) { FF_STRBUF_AUTO_DESTROY subKeyA = ffStrbufCreateWS(subKeyW); - ffStrbufAppendF(error, "RegOpenKeyExW(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); + ffStrbufAppendF(error, "NtOpenKey(%s\\%s) failed", hKey2Str(hKey), subKeyA.chars); } return false; } return true; } -bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) +static bool processRegValue(const FFRegValueArg* arg, const ULONG regType, const void* regData, ULONG regDataLen, FFstrbuf* error) { - DWORD bufSize; //with tailing '\0' - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, NULL, &bufSize) != ERROR_SUCCESS) + switch (arg->type) { - if(error) + case FF_ARG_TYPE_STRBUF: { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_SZ) failed", valueNameA.chars); + if (regType != REG_SZ && regType != REG_EXPAND_SZ) + goto type_mismatch; + + FFstrbuf* strbuf = (FFstrbuf*) arg->value; + uint32_t strLen = regDataLen / sizeof(wchar_t); + if (strLen == 0) + ffStrbufClear(strbuf); + else + { + const wchar_t* ws = (const wchar_t*) regData; + if (ws[strLen - 1] == L'\0') + --strLen; + ffStrbufSetNWS(strbuf, strLen, ws); + } + break; } - return false; - } - assert(bufSize >= sizeof(wchar_t)); - wchar_t* FF_AUTO_FREE resultW = (wchar_t*)malloc(bufSize); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_SZ, NULL, resultW, &bufSize) != ERROR_SUCCESS) - { - if(error) + + case FF_ARG_TYPE_UINT: + case FF_ARG_TYPE_UINT64: + case FF_ARG_TYPE_UINT16: + case FF_ARG_TYPE_UINT8: + case FF_ARG_TYPE_BOOL: { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_REG_SZ) failed", valueNameA.chars); + uint64_t value = 0; + + if (regType == REG_DWORD) + { + if (regDataLen < sizeof(uint32_t)) + goto type_mismatch; + value = *(uint32_t*) regData; + } + else if (regType == REG_QWORD) + { + if (regDataLen < sizeof(uint64_t)) + goto type_mismatch; + value = *(uint64_t*) regData; + } + else + goto type_mismatch; + + if (arg->type == FF_ARG_TYPE_UINT) *(uint32_t*) arg->value = (uint32_t) value; + else if (arg->type == FF_ARG_TYPE_UINT64) *(uint64_t*) arg->value = (uint64_t) value; + else if (arg->type == FF_ARG_TYPE_UINT16) *(uint16_t*) arg->value = (uint16_t) value; + else if (arg->type == FF_ARG_TYPE_UINT8) *(uint8_t*) arg->value = (uint8_t) value; + else if (arg->type == FF_ARG_TYPE_BOOL) *(bool*) arg->value = value != 0; + break; } - return false; + + case FF_ARG_TYPE_FLOAT: + { + if (regDataLen < sizeof(float)) + goto type_mismatch; + *(float*) arg->value = *(float*) regData; + break; + } + + case FF_ARG_TYPE_DOUBLE: + { + if (regDataLen < sizeof(double)) + goto type_mismatch; + *(double*) arg->value = *(double*) regData; + break; + } + + case FF_ARG_TYPE_LIST: + { + if (regType != REG_MULTI_SZ && regType != REG_BINARY) + goto type_mismatch; + + FFlist* list = (FFlist*) arg->value; + ffListClear(list); + + if (regType == REG_MULTI_SZ) + { + if (list->elementSize != sizeof(FFstrbuf)) + { + if (error) + { + FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: expected list of strbuf for REG_MULTI_SZ", nameA.chars); + } + return false; + } + + for ( + const wchar_t* ptr = (const wchar_t*) regData; + (const uint8_t*) ptr < (const uint8_t*) regData + regDataLen && *ptr; + ptr++ + ) + { + uint32_t strLen = (uint32_t) wcsnlen(ptr, regDataLen / sizeof(wchar_t) - (size_t) (ptr - (const wchar_t*) regData)); + ffStrbufInitNWS(FF_LIST_ADD(FFstrbuf, *list), strLen, ptr); + ptr += strLen; + } + } + else + { + if (list->elementSize != sizeof(uint8_t)) + { + if (error) + { + FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: expected list of uint8_t for REG_BINARY", nameA.chars); + } + return false; + } + + ffListReserve(list, regDataLen); + memcpy(list->data, regData, regDataLen); + list->length = regDataLen; + } + break; + } + + case FF_ARG_TYPE_INT: // Use UINT instead + case FF_ARG_TYPE_STRING: + case FF_ARG_TYPE_NULL: + default: + if (error) + { + FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "processRegValue(%s) unsupported FFArgType %u", nameA.chars, (unsigned) arg->type); + } + return false; } - ffStrbufSetNWS(result, (uint32_t) (bufSize / sizeof(*resultW) - 1), resultW); + return true; + +type_mismatch: + if (error) + { + FF_STRBUF_AUTO_DESTROY nameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "ffRegReadValues(%s) type mismatch: regType=%u, argType=%u, dataLen=%u", + nameA.chars, (unsigned) regType, (unsigned) arg->type, (unsigned) regDataLen); + } + return false; } -bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error) +bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error) { - assert(result && length); - DWORD bufSize = 0; - LONG err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, NULL, &bufSize); - if(err != ERROR_SUCCESS || bufSize == 0) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, NULL, &bufSize) failed", valueNameA.chars); - } - return false; - } + UNICODE_STRING* valueNameU = &(UNICODE_STRING) { + .Length = arg->name ? (USHORT) (wcslen(arg->name) * sizeof(wchar_t)) : 0 /*(default)*/, + .MaximumLength = 0, + .Buffer = (wchar_t*) arg->name, + }; - uint8_t* buf = (uint8_t*) malloc(bufSize); - err = RegGetValueW(hKey, NULL, valueNameW, RRF_RT_REG_BINARY, NULL, buf, &bufSize); - if(err != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, NULL, RRF_RT_REG_BINARY, NULL, length) failed", valueNameA.chars); - } - free(buf); - return false; - } - *result = buf; - *length = bufSize; - return true; -} + alignas(KEY_VALUE_PARTIAL_INFORMATION) uint8_t staticBuffer[128 + sizeof(KEY_VALUE_PARTIAL_INFORMATION)]; + FF_AUTO_FREE uint8_t* dynamicBuffer = NULL; -bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) -{ - DWORD bufSize = sizeof(*result); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_DWORD, NULL, result, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_DWORD) failed", valueNameA.chars); - } - return false; - } - return true; -} + KEY_VALUE_PARTIAL_INFORMATION* buffer = (KEY_VALUE_PARTIAL_INFORMATION*) &staticBuffer; + DWORD bufSize = sizeof(staticBuffer); + if (NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize))) + goto process_value; -bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error) -{ - DWORD bufSize = sizeof(*result); - if(RegGetValueW(hKey, NULL, valueNameW, RRF_RT_QWORD, NULL, result, &bufSize) != ERROR_SUCCESS) - { - if(error) - { - if(!valueNameW) - valueNameW = L"(default)"; - FF_STRBUF_AUTO_DESTROY valueNameA = ffStrbufCreateWS(valueNameW); - ffStrbufAppendF(error, "RegGetValueW(%s, result, RRF_RT_QWORD) failed", valueNameA.chars); - } - return false; - } - return true; -} - -bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error) -{ - DWORD bufSize = 0; - if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, NULL, &bufSize, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + if (bufSize == 0) { if (error) - ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed"); + { + FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "NtQueryValueKey(%s, %s) failed", hKey2Str(hKey), valueNameA.chars); + } return false; } - ++bufSize; - wchar_t* FF_AUTO_FREE resultW = (wchar_t*) malloc(bufSize * sizeof(*resultW)); - if(RegEnumKeyExW(hKey, index, resultW, &bufSize, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + + dynamicBuffer = (uint8_t*) malloc(bufSize); + buffer = (KEY_VALUE_PARTIAL_INFORMATION*) dynamicBuffer; + + if (!NT_SUCCESS(NtQueryValueKey(hKey, valueNameU, KeyValuePartialInformation, buffer, bufSize, &bufSize))) { if (error) - ffStrbufAppendF(error, "RegEnumKeyExW(hKey, %u) failed", (unsigned) index); + { + FF_STRBUF_AUTO_DESTROY valueNameA = arg->name ? ffStrbufCreateWS(arg->name) : ffStrbufCreateStatic("(default)"); + ffStrbufAppendF(error, "NtQueryValueKey(%s, %s, buffer) failed", hKey2Str(hKey), valueNameA.chars); + } return false; } - ffStrbufSetWS(result, resultW); - return true; + +process_value: + return processRegValue(arg, buffer->Type, buffer->Data, buffer->DataLength, error); } -bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error) +bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error) { - DWORD buffer; - if(RegQueryInfoKeyW(hKey, NULL, NULL, NULL, &buffer, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) + if (__builtin_expect(argc == 0, false)) + return true; + + assert(argv); + + FF_AUTO_FREE UNICODE_STRING* names = (UNICODE_STRING*) calloc(argc, sizeof(*names)); + FF_AUTO_FREE KEY_VALUE_ENTRY* entries = (KEY_VALUE_ENTRY*) calloc(argc, sizeof(*entries)); + + for (uint32_t i = 0; i < argc; ++i) + { + if (__builtin_expect(!argv[i].value, false)) + { + if (error) ffStrbufAppendF(error, "ffRegReadValues(argv[%u].pVar) is NULL", (unsigned) i); + return false; + } + + names[i] = (UNICODE_STRING) { + .Length = argv[i].name ? (USHORT) (wcslen(argv[i].name) * sizeof(wchar_t)) : 0 /*(default)*/, + .MaximumLength = 0, + .Buffer = (wchar_t*) argv[i].name, + }; + entries[i].ValueName = &names[i]; + } + + ULONG bufferSize = argc * 128; + if (bufferSize < 512) + bufferSize = 512; + + FF_AUTO_FREE uint8_t* buffer = NULL; + + while (true) + { + buffer = (uint8_t*) realloc(buffer, bufferSize); + + ULONG writtenSize = bufferSize; + ULONG requiredSize = 0; + NTSTATUS status = NtQueryMultipleValueKey(hKey, entries, argc, buffer, &writtenSize, &requiredSize); + + if (!NT_SUCCESS(status)) + { + // Buffer too small: docs guarantee requiredSize is returned when provided. + if (requiredSize > bufferSize) + { + bufferSize = requiredSize; + continue; + } + + if (error) + ffStrbufAppendF(error, "NtQueryMultipleValueKey(%s, argc=%u) failed, status=0x%08X", + hKey2Str(hKey), (unsigned) argc, (unsigned) status); + return false; + } + + break; + } + + for (uint32_t i = 0; i < argc; ++i) + { + const FFRegValueArg* arg = &argv[i]; + const KEY_VALUE_ENTRY* entry = &entries[i]; + + if (!processRegValue(arg, entry->Type, buffer + entry->DataOffset, entry->DataLength, error)) + return false; + } + + return true; +} + +bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error) +{ + assert(hKey); + assert(result); + + alignas(KEY_BASIC_INFORMATION) uint8_t buffer[sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(wchar_t)]; + ULONG bufSize = (ULONG) sizeof(buffer); + KEY_BASIC_INFORMATION* keyInfo = (KEY_BASIC_INFORMATION*) buffer; + + if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize))) { if (error) - ffStrbufAppendS(error, "RegQueryInfoKeyW(hKey) failed"); + ffStrbufAppendF(error, "NtEnumerateKey(hKey, %u, keyInfo) failed", (unsigned) index); return false; } - *result = buffer; + ffStrbufSetNWS(result, keyInfo->NameLength / sizeof(wchar_t), keyInfo->Name); + return true; +} + +bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error) +{ + assert(hKey); + assert(result); + + alignas(KEY_FULL_INFORMATION) uint8_t buffer[sizeof(KEY_FULL_INFORMATION) + MAX_PATH * sizeof(wchar_t)]; + ULONG bufSize = sizeof(buffer); + KEY_FULL_INFORMATION* keyInfo = (KEY_FULL_INFORMATION*) buffer; + + if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize))) + { + if (error) + ffStrbufAppendS(error, "NtQueryKey(hKey, KeyFullInformation, keyInfo) failed"); + return false; + } + + *result = (uint32_t) keyInfo->SubKeys; return true; } diff --git a/src/common/windows/registry.h b/src/common/windows/registry.h index 1c3f7f46f..7c9b9a39a 100644 --- a/src/common/windows/registry.h +++ b/src/common/windows/registry.h @@ -1,21 +1,68 @@ #pragma once #include "fastfetch.h" +#include "common/argType.h" +#include "common/io.h" -#include +#ifndef HKEY_CURRENT_USER +#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) +#define HKEY_CURRENT_USER ((HKEY) (ULONG_PTR)((LONG)0x80000001)) +#define HKEY_LOCAL_MACHINE ((HKEY) (ULONG_PTR)((LONG)0x80000002)) +#define HKEY_USERS ((HKEY) (ULONG_PTR)((LONG)0x80000003)) +#define HKEY_PERFORMANCE_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000004)) +#define HKEY_CURRENT_CONFIG ((HKEY) (ULONG_PTR)((LONG)0x80000005)) +#define HKEY_DYN_DATA ((HKEY) (ULONG_PTR)((LONG)0x80000006)) +#define HKEY_CURRENT_USER_LOCAL_SETTINGS ((HKEY) (ULONG_PTR)((LONG)0x80000007)) +#endif -static inline void wrapRegCloseKey(HKEY* phKey) +typedef struct FFRegValueArg { - if(*phKey) - RegCloseKey(*phKey); + FFArgType type; + const void* value; + const wchar_t* name; +} FFRegValueArg; + +HANDLE ffRegGetRootKeyHandle(HKEY hKey); +bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error); +bool ffRegReadValue(HANDLE hKey, const FFRegValueArg* arg, FFstrbuf* error); +bool ffRegReadValues(HANDLE hKey, uint32_t argc, const FFRegValueArg argv[], FFstrbuf* error); +bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error); +bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error); + +static inline bool ffRegOpenKeyForRead(HKEY hRootKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error) +{ + return ffRegOpenSubkeyForRead(ffRegGetRootKeyHandle(hRootKey), subKeyW, result, error); } -#define FF_HKEY_AUTO_DESTROY HKEY __attribute__((__cleanup__(wrapRegCloseKey))) - -bool ffRegOpenKeyForRead(HKEY hKey, const wchar_t* subKeyW, HKEY* result, FFstrbuf* error); -bool ffRegReadStrbuf(HKEY hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error); -bool ffRegReadData(HKEY hKey, const wchar_t* valueNameW, uint8_t** result, uint32_t* length, FFstrbuf* error); -bool ffRegReadUint(HKEY hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error); -bool ffRegReadUint64(HKEY hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error); -bool ffRegGetSubKey(HKEY hKey, uint32_t index, FFstrbuf* result, FFstrbuf* error); -bool ffRegGetNSubKeys(HKEY hKey, uint32_t* result, FFstrbuf* error); +static inline bool ffRegReadStrbuf(HANDLE hKey, const wchar_t* valueNameW, FFstrbuf* result, FFstrbuf* error) +{ + return ffRegReadValue(hKey, &(FFRegValueArg) { + .type = FF_ARG_TYPE_STRBUF, + .value = result, + .name = valueNameW, + }, error); +} +static inline bool ffRegReadUint(HANDLE hKey, const wchar_t* valueNameW, uint32_t* result, FFstrbuf* error) +{ + return ffRegReadValue(hKey, &(FFRegValueArg) { + .type = FF_ARG_TYPE_UINT, + .value = result, + .name = valueNameW, + }, error); +} +static inline bool ffRegReadUint64(HANDLE hKey, const wchar_t* valueNameW, uint64_t* result, FFstrbuf* error) +{ + return ffRegReadValue(hKey, &(FFRegValueArg) { + .type = FF_ARG_TYPE_UINT64, + .value = result, + .name = valueNameW, + }, error); +} +static inline bool ffRegReadData(HANDLE hKey, const wchar_t* valueNameW, FFlist* result /*list of uint8_t*/, FFstrbuf* error) +{ + return ffRegReadValue(hKey, &(FFRegValueArg) { + .type = FF_ARG_TYPE_LIST, + .value = result, + .name = valueNameW, + }, error); +} diff --git a/src/detection/cpu/cpu_windows.c b/src/detection/cpu/cpu_windows.c index 31f1f5627..0dd06a1f3 100644 --- a/src/detection/cpu/cpu_windows.c +++ b/src/detection/cpu/cpu_windows.c @@ -250,28 +250,18 @@ static const char* detectNCores(FFCPUResult* cpu) static const char* detectByRegistry(FFCPUResult* cpu) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", &hKey, NULL)) return "ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L\"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0\", &hKey, NULL) failed"; - ffRegReadStrbuf(hKey, L"ProcessorNameString", &cpu->name, NULL); - if (ffRegReadStrbuf(hKey, L"VendorIdentifier", &cpu->vendor, NULL)) + if (ffRegReadValues(hKey, 3, (FFRegValueArg[]) { + FF_ARG(cpu->name, L"ProcessorNameString"), + FF_ARG(cpu->vendor, L"VendorIdentifier"), + FF_ARG(cpu->frequencyBase, L"~MHz"), + }, NULL)) ffStrbufTrimRightSpace(&cpu->vendor); - - if (cpu->coresLogical == 0) - { - FF_HKEY_AUTO_DESTROY hProcsKey = NULL; - if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor", &hProcsKey, NULL)) - { - uint32_t cores; - if (ffRegGetNSubKeys(hProcsKey, &cores, NULL)) - cpu->coresOnline = cpu->coresPhysical = cpu->coresLogical = (uint16_t) cores; - } - } - - uint32_t mhz; - if(ffRegReadUint(hKey, L"~MHz", &mhz, NULL)) - cpu->frequencyBase = mhz; + else + return "ffRegReadValues() failed for CPU registry key"; return NULL; } diff --git a/src/detection/cursor/cursor_windows.c b/src/detection/cursor/cursor_windows.c index 1856ad04d..220b76309 100644 --- a/src/detection/cursor/cursor_windows.c +++ b/src/detection/cursor/cursor_windows.c @@ -1,17 +1,18 @@ #include "cursor.h" +#include "common/io.h" #include "common/windows/registry.h" void ffDetectCursor(FFCursorResult* result) { - FF_HKEY_AUTO_DESTROY hKey; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Control Panel\\Cursors", &hKey, &result->error)) { - if (!ffRegReadStrbuf(hKey, NULL, &result->theme, &result->error)) - return; - uint32_t cursorBaseSize; - if (ffRegReadUint(hKey, L"CursorBaseSize", &cursorBaseSize, NULL)) - ffStrbufAppendF(&result->size, "%u", (unsigned) cursorBaseSize); + if (ffRegReadValues(hKey, 2, (FFRegValueArg[]) { + FF_ARG(result->theme, NULL), + FF_ARG(cursorBaseSize, L"CursorBaseSize"), + }, &result->error)) + ffStrbufAppendUInt(&result->size, cursorBaseSize); } } diff --git a/src/detection/displayserver/displayserver_windows.c b/src/detection/displayserver/displayserver_windows.c index 487c72642..62555339f 100644 --- a/src/detection/displayserver/displayserver_windows.c +++ b/src/detection/displayserver/displayserver_windows.c @@ -1,6 +1,7 @@ #include "displayserver.h" -#include "common/windows/unicode.h" #include "common/edidHelper.h" +#include "common/windows/registry.h" +#include "common/windows/unicode.h" #include #include @@ -49,8 +50,7 @@ static void detectDisplays(FFDisplayServerResult* ds) .id = path->targetInfo.id, }, }; - uint8_t edidData[1024]; - DWORD edidLength = 0; + FF_LIST_AUTO_DESTROY edid = ffListCreate(sizeof(uint8_t)); if(DisplayConfigGetDeviceInfo(&targetName.header) == ERROR_SUCCESS) { @@ -69,16 +69,17 @@ static void detectDisplays(FFDisplayServerResult* ds) } wcscpy(pRegPath, L"Device Parameters"); - edidLength = ARRAY_SIZE(edidData); - if (RegGetValueW(HKEY_LOCAL_MACHINE, regPath, L"EDID", RRF_RT_REG_BINARY, NULL, edidData, &edidLength) == ERROR_SUCCESS && - edidLength > 0 && edidLength % 128 == 0) + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; + if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regPath, &hKey, NULL) && + ffRegReadData(hKey, L"EDID", &edid, NULL) && + ffEdidIsValid(edid.data, edid.length)) { - ffEdidGetName(edidData, &name); - ffEdidGetPhysicalSize(edidData, &physicalWidth, &physicalHeight); + ffEdidGetName(edid.data, &name); + ffEdidGetPhysicalSize(edid.data, &physicalWidth, &physicalHeight); } else { - edidLength = 0; + ffListClear(&edid); if (targetName.flags.friendlyNameFromEdid) ffStrbufSetWS(&name, targetName.monitorFriendlyDeviceName); else @@ -209,8 +210,8 @@ static void detectDisplays(FFDisplayServerResult* ds) else display->hdrStatus = FF_DISPLAY_HDR_STATUS_UNKNOWN; } - if (edidLength > 0) - ffEdidGetSerialAndManufactureDate(edidData, &display->serial, &display->manufactureYear, &display->manufactureWeek); + if (edid.length > 0) + ffEdidGetSerialAndManufactureDate(edid.data, &display->serial, &display->manufactureYear, &display->manufactureWeek); display->drrStatus = path->flags & DISPLAYCONFIG_PATH_BOOST_REFRESH_RATE ? FF_DISPLAY_DRR_STATUS_ENABLED : FF_DISPLAY_DRR_STATUS_DISABLED; } } diff --git a/src/detection/gpu/gpu_windows.c b/src/detection/gpu/gpu_windows.c index 2c689337a..b7a5487bc 100644 --- a/src/detection/gpu/gpu_windows.c +++ b/src/detection/gpu/gpu_windows.c @@ -1,12 +1,12 @@ #include "gpu.h" #include "detection/gpu/gpu_driver_specific.h" -#include "common/library.h" #include "common/windows/unicode.h" #include "common/windows/registry.h" #include "common/mallocHelper.h" #include "common/debug.h" #include "common/windows/nt.h" +#include #include #define FF_EMPTY_GUID_STR L"{00000000-0000-0000-0000-000000000000}" @@ -19,6 +19,13 @@ const uint32_t regDriverKeyPrefixLength = (uint32_t) __builtin_strlen("SYSTEM\\C #define GUID_DEVCLASS_DISPLAY_STRING L"{4d36e968-e325-11ce-bfc1-08002be10318}" // Found in +static inline void wrapRegCloseKey(HKEY* phKey) +{ + if(*phKey) + RegCloseKey(*phKey); +} +#define FF_HKEY_AUTO_DESTROY __attribute__((__cleanup__(wrapRegCloseKey))) + const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* gpus) { FF_DEBUG("Starting GPU detection"); @@ -115,7 +122,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* uint64_t adapterLuid = 0; - FF_HKEY_AUTO_DESTROY hVideoIdKey = NULL; + FF_HKEY_AUTO_DESTROY HKEY hVideoIdKey = NULL; wchar_t buffer[256]; ULONG bufferLen = 0; @@ -147,7 +154,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* { FF_DEBUG("Found VideoID: %ls", buffer); wmemcpy(regDirectxKey + regDirectxKeyPrefixLength, buffer, FF_GUID_STRLEN); - FF_HKEY_AUTO_DESTROY hDirectxKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hDirectxKey = NULL; if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDirectxKey, &hDirectxKey, NULL)) { FF_DEBUG("Opened DirectX registry key"); @@ -237,7 +244,7 @@ const char* ffDetectGPUImpl(FF_MAYBE_UNUSED const FFGPUOptions* options, FFlist* { FF_DEBUG("Found driver GUID: %ls", buffer); wmemcpy(regDriverKey + regDriverKeyPrefixLength, buffer, FF_GUID_STRLEN + strlen("\\0000")); - FF_HKEY_AUTO_DESTROY hRegDriverKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hRegDriverKey = NULL; if (ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regDriverKey, &hRegDriverKey, NULL)) { FF_DEBUG("Opened driver registry key"); diff --git a/src/detection/icons/icons_windows.c b/src/detection/icons/icons_windows.c index 44c8b9630..8aa75e2de 100644 --- a/src/detection/icons/icons_windows.c +++ b/src/detection/icons/icons_windows.c @@ -3,7 +3,7 @@ const char* ffDetectIcons(FFIconsResult* result) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\NewStartPanel", &hKey, NULL) && !ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\ClassicStartMenu", &hKey, NULL)) return "ffRegOpenKeyForRead(Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\HideDesktopIcons\\{NewStartPanel|ClassicStartMenu}) failed"; diff --git a/src/detection/os/os_windows.c b/src/detection/os/os_windows.c index bdb979d30..07b11761a 100644 --- a/src/detection/os/os_windows.c +++ b/src/detection/os/os_windows.c @@ -10,7 +10,7 @@ PWSTR WINAPI BrandingFormatString(PCWSTR format); static bool getCodeName(FFOSResult* os) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) return false; @@ -39,13 +39,9 @@ void ffDetectOSImpl(FFOSResult* os) if(os->variant.length == 0) // Windows PE? { - wchar_t buf[128]; - DWORD bufSize = (DWORD) sizeof(buf); // with trailing '\0' - if(RegGetValueW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", L"ProductName", RRF_RT_REG_SZ, NULL, buf, &bufSize) == ERROR_SUCCESS) - { - assert(bufSize >= sizeof(wchar_t)); - ffStrbufSetNWS(&os->variant, bufSize / sizeof(wchar_t) - 1, buf); - } + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; + if(ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL)) + ffRegReadStrbuf(hKey, L"ProductName", &os->variant, NULL); } ffStrbufSet(&os->prettyName, &os->variant); diff --git a/src/detection/terminalfont/terminalfont_windows.c b/src/detection/terminalfont/terminalfont_windows.c index 2d8c087c7..da41efdf0 100644 --- a/src/detection/terminalfont/terminalfont_windows.c +++ b/src/detection/terminalfont/terminalfont_windows.c @@ -268,16 +268,25 @@ static void detectConEmu(FFTerminalFontResult* terminalFont) static void detectWarp(FFTerminalFontResult* terminalFont) { - FF_HKEY_AUTO_DESTROY key = NULL; + FF_AUTO_CLOSE_FD HANDLE key = NULL; if (!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Warp.dev\\Warp", &key, &terminalFont->error)) return; FF_STRBUF_AUTO_DESTROY fontName = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY fontSize = ffStrbufCreate(); - if (!ffRegReadStrbuf(key, L"FontName", &fontName, NULL)) + if (ffRegReadValues(key, 2, (FFRegValueArg[]) { + FF_ARG(fontName, L"FontName"), + FF_ARG(fontSize, L"FontSize") + }, &terminalFont->error)) + { + ffStrbufTrim(&fontName, '"'); + ffStrbufAppendS(&fontSize, "px"); + } + else + { ffStrbufSetS(&fontName, "Hack"); - if (!ffRegReadStrbuf(key, L"FontSize", &fontSize, &terminalFont->error)) - ffStrbufSetS(&fontSize, "13"); + ffStrbufSetS(&fontSize, "13.0px"); + } ffFontInitValues(&terminalFont->font, fontName.chars, fontSize.chars); } diff --git a/src/detection/terminalshell/terminalshell_windows.c b/src/detection/terminalshell/terminalshell_windows.c index f180d2894..9d4f3dff0 100644 --- a/src/detection/terminalshell/terminalshell_windows.c +++ b/src/detection/terminalshell/terminalshell_windows.c @@ -191,7 +191,7 @@ static bool detectDefaultTerminal(FFTerminalResult* result) goto conhost; } - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, regPath, &hKey, NULL)) { FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate(); diff --git a/src/detection/wallpaper/wallpaper_windows.c b/src/detection/wallpaper/wallpaper_windows.c index f713e0172..8a5324c84 100644 --- a/src/detection/wallpaper/wallpaper_windows.c +++ b/src/detection/wallpaper/wallpaper_windows.c @@ -3,7 +3,7 @@ const char* ffDetectWallpaper(FFstrbuf* result) { - FF_HKEY_AUTO_DESTROY hKey = NULL; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; if(!ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Control Panel\\Desktop", &hKey, NULL)) return "ffRegOpenKeyForRead(Control Panel\\Desktop) failed"; diff --git a/src/detection/wmtheme/wmtheme_windows.c b/src/detection/wmtheme/wmtheme_windows.c index 5584af3e9..4b953673e 100644 --- a/src/detection/wmtheme/wmtheme_windows.c +++ b/src/detection/wmtheme/wmtheme_windows.c @@ -63,18 +63,18 @@ const char* colorHexToString(DWORD hex) bool ffDetectWmTheme(FFstrbuf* themeOrError) { { - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes", &hKey, NULL)) + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; + if (ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes", &hKey, NULL)) { FF_STRBUF_AUTO_DESTROY theme = ffStrbufCreate(); - if(ffRegReadStrbuf(hKey, L"CurrentTheme", &theme, NULL)) + if (ffRegReadStrbuf(hKey, L"CurrentTheme", &theme, NULL)) { ffStrbufSubstrBeforeLastC(&theme, '.'); ffStrbufSubstrAfterLastC(&theme, '\\'); if(isalpha(theme.chars[0])) theme.chars[0] = (char)toupper(theme.chars[0]); - ffStrbufAppendF(themeOrError, "%s", theme.chars); + ffStrbufAppend(themeOrError, &theme); } } } @@ -82,28 +82,35 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError) do { uint32_t rgbColor; uint32_t bgrColor; - DWORD bufSize = sizeof(bgrColor); - if(RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"AccentColor", RRF_RT_REG_DWORD, NULL, &bgrColor, &bufSize) == ERROR_SUCCESS) - rgbColor = ((bgrColor & 0xFF) << 16) | (bgrColor & 0xFF00) | ((bgrColor >> 16) & 0xFF); - else if(RegGetValueW(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", L"ColorizationColor", RRF_RT_REG_DWORD, NULL, &rgbColor, &bufSize) == ERROR_SUCCESS) - rgbColor &= 0xFFFFFF; - else - break; + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; + if (ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\DWM", &hKey, NULL)) + { + if (ffRegReadUint(hKey, L"AccentColor", &bgrColor, NULL)) + rgbColor = ((bgrColor & 0xFF) << 16) | (bgrColor & 0xFF00) | ((bgrColor >> 16) & 0xFF); + else if (ffRegReadUint(hKey, L"ColorizationColor", &rgbColor, NULL)) + rgbColor &= 0xFFFFFF; + else + break; + } + else break; - if(themeOrError->length > 0) ffStrbufAppendS(themeOrError, " - "); + if (themeOrError->length > 0) ffStrbufAppendS(themeOrError, " - "); const char* text = colorHexToString(rgbColor); - if(text) + if (text) ffStrbufAppendS(themeOrError, text); else ffStrbufAppendF(themeOrError, "#%06lX", (long)rgbColor); } while (false); { - FF_HKEY_AUTO_DESTROY hKey = NULL; - if(ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hKey, NULL)) + FF_AUTO_CLOSE_FD HANDLE hKey = NULL; + if (ffRegOpenKeyForRead(HKEY_CURRENT_USER, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hKey, NULL)) { uint32_t system = 1, apps = 1; - if (ffRegReadUint(hKey, L"SystemUsesLightTheme", &system, NULL) && ffRegReadUint(hKey, L"AppsUseLightTheme", &apps, NULL)) + if (ffRegReadValues(hKey, 2, (FFRegValueArg[]) { + FF_ARG(system, L"SystemUsesLightTheme"), + FF_ARG(apps, L"AppsUseLightTheme"), + }, NULL)) { bool paren = themeOrError->length > 0; if (paren) @@ -117,7 +124,7 @@ bool ffDetectWmTheme(FFstrbuf* themeOrError) if(themeOrError->length == 0) { - ffStrbufAppendS(themeOrError, "Failed to find current theme"); + ffStrbufSetStatic(themeOrError, "Failed to find current theme"); return false; } return true; diff --git a/tests/format.c b/tests/format.c index 1606ba885..cecce2498 100644 --- a/tests/format.c +++ b/tests/format.c @@ -9,7 +9,7 @@ static void verify(const char* format, const char* arg, const char* expected, in FF_STRBUF_AUTO_DESTROY result = ffStrbufCreate(); FF_STRBUF_AUTO_DESTROY formatter = ffStrbufCreateStatic(format); const FFformatarg arguments[] = { - { .type = FF_FORMAT_ARG_TYPE_STRING, arg } + { .type = FF_ARG_TYPE_STRING, arg } }; ffParseFormatString(&result, &formatter, 1, arguments); if (!ffStrbufEqualS(&result, expected))