diff --git a/CMakeLists.txt b/CMakeLists.txt index 1687f162c..880839700 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -64,6 +64,7 @@ cmake_dependent_option(ENABLE_OPENCL "Enable opencl" ON "LINUX OR BSD OR WIN32" cmake_dependent_option(ENABLE_LIBCJSON "Enable libcjson" ON "LINUX OR WIN32" OFF) cmake_dependent_option(ENABLE_FREETYPE "Enable freetype" ON "ANDROID" OFF) cmake_dependent_option(ENABLE_THREADS "Enable multithreading" ON "Threads_FOUND AND NOT ANDROID" OFF) +cmake_dependent_option(USE_WIN_FAST_PPID_DETECTION "Use internal NTAPI instead of querying WMI to get PPID" ON "WIN32" OFF) option(BUILD_TESTS "Build tests" OFF) # Also create test executables option(SET_TWEAK "Add tweak to project version" ON) # This is set to off by github actions for release builds @@ -523,7 +524,11 @@ elseif(WIN32) PRIVATE "opengl32" PRIVATE "wbemuuid" PRIVATE "ws2_32" + PRIVATE "ntdll" ) + if(USE_WIN_FAST_PPID_DETECTION) + target_compile_definitions(libfastfetch PRIVATE FF_USE_WIN_FAST_PPID_DETECTION) + endif() endif() target_include_directories(libfastfetch diff --git a/src/detection/terminalshell/terminalshell_windows.cpp b/src/detection/terminalshell/terminalshell_windows.cpp index cd904f97e..71a34c6ea 100644 --- a/src/detection/terminalshell/terminalshell_windows.cpp +++ b/src/detection/terminalshell/terminalshell_windows.cpp @@ -3,20 +3,68 @@ extern "C" { #include "common/processing.h" #include "common/thread.h" } -#include "util/windows/wmi.hpp" #include #include #include -struct ProcessInfo -{ - uint32_t pid; - FFstrbuf psName; -}; +#include -static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe) +#ifdef FF_USE_WIN_FAST_PPID_DETECTION + +#include + +static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) { + HANDLE hProcess = pid == 0 + ? GetCurrentProcess() + : OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, TRUE, pid); + + if(ppid) + { + PROCESS_BASIC_INFORMATION info; + ULONG size; + if(NT_SUCCESS(NtQueryInformationProcess(hProcess, ProcessBasicInformation, &info, sizeof(info), &size))) + { + assert(size == sizeof(info)); + *ppid = (uint32_t)info.InheritedFromUniqueProcessId; + } + else + { + CloseHandle(hProcess); + return false; + } + } + if(exe) + { + DWORD bufSize = exe->allocated; + if(QueryFullProcessImageNameA(hProcess, 0, exe->chars, &bufSize)) + exe->length = bufSize; + else + { + CloseHandle(hProcess); + return false; + } + } + if(pname && exeName) + { + *exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1; + ffStrbufSetS(pname, *exeName); + } + + CloseHandle(hProcess); + return true; +} + +#else + +#include "util/windows/wmi.hpp" + +static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName) +{ + if(pid == 0) + pid = GetCurrentProcessId(); + wchar_t query[256] = {}; swprintf(query, 256, L"SELECT %ls %ls ParentProcessId FROM Win32_Process WHERE ProcessId = %" PRIu32, pname ? L"Name," : L"", @@ -49,20 +97,26 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb if(exe) ffGetWmiObjString(pclsObj, L"ExecutablePath", exe); + if(exeName) + { + *exeName = exe->chars + ffStrbufLastIndexC(exe, '\\') + 1; + } + pclsObj->Release(); pEnumerator->Release(); return true; } +#endif + extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version); static uint32_t getShellInfo(FFTerminalShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->shellProcessName, &result->shellExe, &result->shellExeName)) return 0; - result->shellExeName = result->shellExe.chars + ffStrbufLastIndexC(&result->shellExe, '\\') + 1; ffStrbufSet(&result->shellPrettyName, &result->shellProcessName); if(ffStrbufEndsWithIgnCaseS(&result->shellPrettyName, ".exe")) @@ -113,9 +167,8 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) { uint32_t ppid; - if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe)) + if(pid == 0 || !getProcessInfo(pid, &ppid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName)) return 0; - result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\'); ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName); if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe")) @@ -135,7 +188,7 @@ static uint32_t getTerminalInfo(FFTerminalShellResult* result, uint32_t pid) ffStrbufClear(&result->terminalProcessName); ffStrbufClear(&result->terminalPrettyName); ffStrbufClear(&result->terminalExe); - result->terminalExeName = nullptr; + result->terminalExeName = ""; return getTerminalInfo(result, ppid); } @@ -212,21 +265,21 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance) ffStrbufInit(&result.shellProcessName); ffStrbufInitA(&result.shellExe, 128); - result.shellExeName = result.shellExe.chars; + result.shellExeName = ""; ffStrbufInit(&result.shellPrettyName); ffStrbufInit(&result.shellVersion); ffStrbufInit(&result.terminalProcessName); ffStrbufInitA(&result.terminalExe, 128); - result.terminalExeName = result.terminalExe.chars; + result.terminalExeName = ""; ffStrbufInit(&result.terminalPrettyName); ffStrbufInit(&result.userShellExe); - result.userShellExeName = result.userShellExe.chars; + result.userShellExeName = ""; ffStrbufInit(&result.userShellVersion); - uint32_t ppid = GetCurrentProcessId(); - if(!getProcessInfo(ppid, &ppid, nullptr, nullptr)) + uint32_t ppid; + if(!getProcessInfo(0, &ppid, nullptr, nullptr, nullptr)) goto exit; ppid = getShellInfo(&result, ppid);