mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-11-05 04:34:19 +01:00
Packages (Windows): caches winget packages count; enables winget by default
This commit is contained in:
+17
-13
@@ -1307,19 +1307,23 @@ typedef struct _KEY_BASIC_INFORMATION {
|
||||
_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;
|
||||
typedef struct _KEY_CACHED_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 SubKeys; // The number of subkeys for a key.
|
||||
ULONG MaxNameLen; // The maximum length, in bytes, of a subkey name.
|
||||
ULONG Values; // The number of value entries.
|
||||
ULONG MaxValueNameLen; // The maximum length, in bytes, of a value entry name.
|
||||
ULONG MaxValueDataLen; // The maximum length, in bytes, of a value entry data field.
|
||||
ULONG NameLength; // Size, in bytes, of the key's own (leaf) name, without the terminator. The name itself is not stored.
|
||||
} KEY_CACHED_INFORMATION, *PKEY_CACHED_INFORMATION;
|
||||
// 36 bytes of members, but LARGE_INTEGER makes the struct 8-byte aligned, and that is exactly what
|
||||
// the kernel demands: a 36-byte buffer is rejected with STATUS_BUFFER_TOO_SMALL (measured).
|
||||
// The kernel writes all 40 bytes -- the 4 padding bytes included, zeroed -- and reports
|
||||
// ResultLength = 40 whatever size you pass, so a larger buffer buys nothing (measured 40..4096).
|
||||
// This is the only information class that never appends a string: NameLength is the length of the
|
||||
// key's own (leaf) name in bytes without the terminator, and the name itself is not returned.
|
||||
static_assert(sizeof(KEY_CACHED_INFORMATION) == 40, "KEY_CACHED_INFORMATION should be 40 bytes");
|
||||
|
||||
NTSYSAPI NTSTATUS NTAPI NtQueryKey(
|
||||
_In_ HANDLE KeyHandle,
|
||||
|
||||
@@ -355,6 +355,10 @@ bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* err
|
||||
ULONG bufSize = (ULONG) sizeof(buffer);
|
||||
KEY_BASIC_INFORMATION* keyInfo = (KEY_BASIC_INFORMATION*) buffer;
|
||||
|
||||
// Every failure mode fails NT_SUCCESS, and the read below depends on that: on a too-small buffer
|
||||
// the kernel returns STATUS_BUFFER_OVERFLOW, writes the *full* NameLength but copies only part of
|
||||
// the name (measured), so treating that status as success would read past what was written.
|
||||
// The longest name the CM accepts, 255 characters, still fits: 255 * 2 + 16 <= sizeof(buffer).
|
||||
if (!NT_SUCCESS(NtEnumerateKey(hKey, index, KeyBasicInformation, keyInfo, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtEnumerateKey(hKey=%p, index=%u) failed", hKey, (unsigned) index);
|
||||
if (error) {
|
||||
@@ -367,22 +371,26 @@ bool ffRegGetSubKey(HANDLE hKey, uint32_t index, FFstrbuf* result, FFstrbuf* err
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffRegGetNSubKeys(HANDLE hKey, uint32_t* result, FFstrbuf* error) {
|
||||
// Reads the counters the key object already caches. KeyFullInformation would return the same numbers
|
||||
// but also marshals the key's class string out; measured per query on the ARP and MSIX keys:
|
||||
// 837 ns vs 895 ns (interleaved, 200k queries each). The open dominates the total -- 22.10 us vs
|
||||
// 22.40 us for open + query -- so this is a small win, not a big one.
|
||||
//
|
||||
// The kernel writes exactly sizeof(KEY_CACHED_INFORMATION) bytes and rejects a smaller buffer with
|
||||
// STATUS_BUFFER_TOO_SMALL without writing anything, so pass a whole KEY_CACHED_INFORMATION.
|
||||
bool ffRegQueryKey(HANDLE hKey, KEY_CACHED_INFORMATION* 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;
|
||||
ULONG bufSize = (ULONG) sizeof(*result);
|
||||
|
||||
if (!NT_SUCCESS(NtQueryKey(hKey, KeyFullInformation, keyInfo, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtQueryKey(hKey=%p, KeyFullInformation) failed", hKey);
|
||||
if (!NT_SUCCESS(NtQueryKey(hKey, KeyCachedInformation, result, bufSize, &bufSize))) {
|
||||
FF_DEBUG("NtQueryKey(hKey=%p, KeyCachedInformation) failed", hKey);
|
||||
if (error) {
|
||||
ffStrbufAppendF(error, "NtQueryKey(hKey=%p, KeyFullInformation, keyInfo) failed", hKey);
|
||||
ffStrbufAppendF(error, "NtQueryKey(hKey=%p, KeyCachedInformation, keyInfo) failed", hKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
*result = (uint32_t) keyInfo->SubKeys;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/argType.h"
|
||||
#include "common/io.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#ifndef HKEY_CURRENT_USER
|
||||
#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR) ((LONG) 0x80000000))
|
||||
@@ -26,7 +27,9 @@ bool ffRegOpenSubkeyForRead(HANDLE hKey, const wchar_t* subKeyW, HANDLE* result,
|
||||
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);
|
||||
// Fills `result` with the counters the key object caches, including LastWriteTime: the number of
|
||||
// 100-nanosecond intervals since this key or any of its values was last changed (FILETIME epoch).
|
||||
bool ffRegQueryKey(HANDLE hKey, KEY_CACHED_INFORMATION* result, FFstrbuf* error);
|
||||
|
||||
static inline bool ffRegOpenKeyForRead(HKEY hRootKey, const wchar_t* subKeyW, HANDLE* result, FFstrbuf* error) {
|
||||
return ffRegOpenSubkeyForRead(ffRegGetRootKeyHandle(hRootKey), subKeyW, result, error);
|
||||
|
||||
Reference in New Issue
Block a user