Files
fastfetch/src/common/impl/FFPlatform_windows.c
T

328 lines
11 KiB
C
Raw Normal View History

2023-01-15 15:57:26 +01:00
#include "FFPlatform_private.h"
2026-01-06 09:48:38 +08:00
#include "common/io.h"
#include "common/library.h"
#include "common/stringUtils.h"
#include "common/windows/unicode.h"
#include "common/windows/registry.h"
#include "common/windows/nt.h"
2023-01-15 15:57:26 +01:00
2026-03-09 15:59:26 +08:00
#include <stdalign.h>
#include <windows.h>
2023-01-15 15:57:26 +01:00
#include <shlobj.h>
2026-02-10 20:25:50 +08:00
#include <sddl.h>
2025-04-09 14:58:36 +08:00
#define SECURITY_WIN32 1 // For secext.h
#include <secext.h>
2023-08-24 13:47:20 +08:00
static void getExePath(FFPlatform* platform)
{
wchar_t exePathW[MAX_PATH];
2026-03-11 14:34:05 +08:00
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(
ffGetPeb()->ProcessParameters->ImagePathName.Buffer,
2026-03-11 14:34:05 +08:00
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
2024-01-28 09:56:36 +08:00
if (hPath != INVALID_HANDLE_VALUE)
{
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
2024-01-28 09:56:36 +08:00
if (len > 0 && len < MAX_PATH)
2026-03-11 14:34:05 +08:00
{
ffStrbufSetNWS(&platform->exePath, len, exePathW);
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
ffStrbufSubstrAfter(&platform->exePath, 3);
}
2024-01-28 09:56:36 +08:00
}
2026-03-11 14:34:05 +08:00
if (platform->exePath.length == 0)
{
PCUNICODE_STRING imagePathName = &ffGetPeb()->ProcessParameters->ImagePathName;
ffStrbufSetNWS(&platform->exePath, imagePathName->Length / sizeof(wchar_t), imagePathName->Buffer);
}
2026-03-11 14:34:05 +08:00
2023-08-24 13:47:20 +08:00
ffStrbufReplaceAllC(&platform->exePath, '\\', '/');
}
2023-01-15 15:57:26 +01:00
static void getHomeDir(FFPlatform* platform)
{
2025-01-02 14:01:44 +08:00
PWSTR pPath = NULL;
2023-01-15 15:57:26 +01:00
if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_Profile, KF_FLAG_DEFAULT, NULL, &pPath)))
{
2023-01-15 16:26:08 +01:00
ffStrbufSetWS(&platform->homeDir, pPath);
ffStrbufReplaceAllC(&platform->homeDir, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
}
else
{
ffStrbufSetS(&platform->homeDir, getenv("USERPROFILE"));
ffStrbufReplaceAllC(&platform->homeDir, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->homeDir, '/');
2023-01-15 15:57:26 +01:00
}
2025-01-02 14:01:44 +08:00
CoTaskMemFree(pPath);
2023-01-15 15:57:26 +01:00
}
static void getCacheDir(FFPlatform* platform)
{
2025-01-02 14:01:44 +08:00
PWSTR pPath = NULL;
2023-01-15 15:57:26 +01:00
if(SUCCEEDED(SHGetKnownFolderPath(&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &pPath)))
{
2023-01-15 16:26:08 +01:00
ffStrbufSetWS(&platform->cacheDir, pPath);
ffStrbufReplaceAllC(&platform->cacheDir, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->cacheDir, '/');
2023-01-15 15:57:26 +01:00
}
else
{
2023-01-15 16:26:08 +01:00
ffStrbufAppend(&platform->cacheDir, &platform->homeDir);
ffStrbufAppendS(&platform->cacheDir, "AppData/Local/");
2023-01-15 15:57:26 +01:00
}
2025-01-02 14:01:44 +08:00
CoTaskMemFree(pPath);
2023-01-15 15:57:26 +01:00
}
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
{
2025-01-02 14:01:44 +08:00
PWSTR pPath = NULL;
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
2023-01-15 15:57:26 +01:00
{
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
CoTaskMemFree(pPath);
ffStrbufReplaceAllC(&buffer, '\\', '/');
ffStrbufEnsureEndsWithC(&buffer, '/');
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
2023-01-15 15:57:26 +01:00
}
}
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
{
const char* value = getenv(env);
if(!ffStrSet(value))
return;
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateA(64);
ffStrbufAppendS(&buffer, value);
ffStrbufReplaceAllC(&buffer, '\\', '/');
ffStrbufEnsureEndsWithC(&buffer, '/');
if (suffix)
{
ffStrbufAppendS(&buffer, suffix);
ffStrbufEnsureEndsWithC(&buffer, '/');
}
if (ffPathExists(buffer.chars, FF_PATHTYPE_DIRECTORY) && !ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
2023-01-15 15:57:26 +01:00
}
static void getConfigDirs(FFPlatform* platform)
{
if(getenv("MSYSTEM"))
2023-01-15 15:57:26 +01:00
{
// We are in MSYS2 / Git Bash
platformPathAddEnvSuffix(&platform->configDirs, "HOME", ".config/");
platformPathAddEnvSuffix(&platform->configDirs, "HOME", NULL);
platformPathAddEnvSuffix(&platform->configDirs, "MINGW_PREFIX", "etc");
2023-01-15 15:57:26 +01:00
}
ffPlatformPathAddHome(&platform->configDirs, platform, ".config/");
platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_ProgramData);
platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_RoamingAppData);
platformPathAddKnownFolder(&platform->configDirs, &FOLDERID_LocalAppData);
ffPlatformPathAddHome(&platform->configDirs, platform, "");
2023-01-15 15:57:26 +01:00
}
2023-01-15 16:45:16 +01:00
static void getDataDirs(FFPlatform* platform)
2023-01-15 15:57:26 +01:00
{
if(getenv("MSYSTEM") && getenv("HOME"))
{
// We are in MSYS2 / Git Bash
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", ".local/share/");
platformPathAddEnvSuffix(&platform->dataDirs, "HOME", NULL);
platformPathAddEnvSuffix(&platform->dataDirs, "MINGW_PREFIX", "share");
2023-01-15 15:57:26 +01:00
}
ffPlatformPathAddHome(&platform->dataDirs, platform, ".local/share/");
platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_ProgramData);
platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_RoamingAppData);
platformPathAddKnownFolder(&platform->dataDirs, &FOLDERID_LocalAppData);
ffPlatformPathAddHome(&platform->dataDirs, platform, "");
2023-01-15 15:57:26 +01:00
}
static void getUserName(FFPlatform* platform)
{
2025-04-09 14:58:36 +08:00
wchar_t buffer[256];
2026-02-10 20:25:50 +08:00
DWORD size = ARRAY_SIZE(buffer);
if (GetUserNameExW(NameDisplay, buffer, &size))
2025-04-09 14:58:36 +08:00
ffStrbufSetWS(&platform->fullUserName, buffer);
2026-02-10 20:25:50 +08:00
size = ARRAY_SIZE(buffer);
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
ffStrbufSetWS(&platform->userName, buffer);
else
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
2026-03-09 15:59:26 +08:00
alignas(TOKEN_USER) char buf[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size)))
{
TOKEN_USER* tokenUser = (TOKEN_USER*) buf;
UNICODE_STRING sidString = { .Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer) };
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE)))
ffStrbufSetNWS(&platform->sid, sidString.Length / sizeof(wchar_t), sidString.Buffer);
}
2023-01-15 15:57:26 +01:00
}
static void getHostName(FFPlatform* platform)
{
wchar_t buffer[256];
2024-10-18 16:15:48 +08:00
DWORD len = ARRAY_SIZE(buffer);
if (GetComputerNameExW(ComputerNameDnsHostname, buffer, &len) && len > 0)
ffStrbufSetNWS(&platform->hostName, len, buffer);
else
{
len = ARRAY_SIZE(buffer);
if (GetComputerNameExW(ComputerNameNetBIOS, buffer, &len) && len > 0)
ffStrbufSetNWS(&platform->hostName, len, buffer);
}
2023-01-15 15:57:26 +01:00
}
static void getUserShell(FFPlatform* platform)
2023-01-15 15:57:26 +01:00
{
// Works in MSYS2
2025-12-03 14:41:19 +08:00
const char* userShell = getenv("SHELL");
if (userShell)
{
ffStrbufAppendS(&platform->userShell, userShell);
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
}
2023-01-15 15:57:26 +01:00
}
static const char* detectWine(void)
2024-10-14 15:38:54 +08:00
{
2025-07-07 22:34:23 +08:00
const char * __cdecl wine_get_version(void);
2026-03-19 15:24:55 +08:00
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
if (!hntdll) return NULL;
2025-07-07 22:34:23 +08:00
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
if (!ffwine_get_version) return NULL;
return ffwine_get_version();
2024-10-14 15:38:54 +08:00
}
2024-07-02 10:12:26 +08:00
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
2023-01-15 15:57:26 +01:00
{
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
return;
2023-01-15 15:57:26 +01:00
uint32_t ubr = 0;
ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
FF_ARG(ubr, L"UBR"),
FF_ARG(info->version, L"BuildLabEx"),
}, NULL);
2023-01-15 15:57:26 +01:00
PPEB_FULL peb = ffGetPeb();
ffStrbufSetF(&info->release,
"%u.%u.%u.%u",
(unsigned) peb->OSMajorVersion,
(unsigned) peb->OSMinorVersion,
(unsigned) peb->OSBuildNumber,
(unsigned) ubr);
2023-01-15 15:57:26 +01:00
const char* wineVersion = detectWine();
if (wineVersion)
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
else
ffStrbufSetStatic(&info->name, "WIN32_NT");
2023-01-15 15:57:26 +01:00
}
2026-02-18 20:13:14 +08:00
static void getSystemPageSize(FFPlatformSysinfo* info)
2023-01-15 15:57:26 +01:00
{
2026-02-18 20:13:14 +08:00
SYSTEM_BASIC_INFORMATION sbi;
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL)))
info->pageSize = sbi.PhysicalPageSize;
else
info->pageSize = 4096;
}
2023-01-15 15:57:26 +01:00
2026-02-18 20:13:14 +08:00
static void getSystemArchitecture(FFPlatformSysinfo* info)
{
SYSTEM_PROCESSOR_INFORMATION spi;
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL)))
2023-01-15 15:57:26 +01:00
{
2026-02-18 20:13:14 +08:00
switch (spi.ProcessorArchitecture)
{
2023-01-15 15:57:26 +01:00
case PROCESSOR_ARCHITECTURE_AMD64:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "x86_64");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_IA64:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "ia64");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_INTEL:
2026-02-18 20:13:14 +08:00
switch (spi.ProcessorLevel)
{
case 4:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "i486");
break;
case 5:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "i586");
break;
case 6:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "i686");
break;
default:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "i386");
break;
}
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_ARM64:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "aarch64");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_ARM:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "arm");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_PPC:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "ppc");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_MIPS:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "mips");
2023-01-15 15:57:26 +01:00
break;
case PROCESSOR_ARCHITECTURE_ALPHA:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "alpha");
break;
case PROCESSOR_ARCHITECTURE_ALPHA64:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "alpha64");
break;
2023-01-15 15:57:26 +01:00
case PROCESSOR_ARCHITECTURE_UNKNOWN:
default:
2024-07-02 10:12:26 +08:00
ffStrbufSetStatic(&info->architecture, "unknown");
2023-01-15 15:57:26 +01:00
break;
2026-02-18 20:13:14 +08:00
}
2023-01-15 15:57:26 +01:00
}
}
static void getCwd(FFPlatform* platform)
{
PCURDIR cwd = &ffGetPeb()->ProcessParameters->CurrentDirectory;
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
}
2023-01-15 16:06:50 +01:00
void ffPlatformInitImpl(FFPlatform* platform)
2023-01-15 15:57:26 +01:00
{
platform->pid = (uint32_t) (uintptr_t) ffGetTeb()->ClientId.UniqueProcess;
2023-08-24 13:47:20 +08:00
getExePath(platform);
getCwd(platform);
2023-01-15 15:57:26 +01:00
getHomeDir(platform);
getCacheDir(platform);
getConfigDirs(platform);
getDataDirs(platform);
getUserName(platform);
getHostName(platform);
getUserShell(platform);
2023-01-15 15:57:26 +01:00
2024-07-02 10:12:26 +08:00
getSystemReleaseAndVersion(&platform->sysinfo);
2026-02-18 20:13:14 +08:00
getSystemArchitecture(&platform->sysinfo);
getSystemPageSize(&platform->sysinfo);
2023-01-15 15:57:26 +01:00
}