mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-10-30 00:37:23 +01:00
TerminalShell: improve speed on Windows
[NtQueryInformationProcess](https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryinformationprocess) is an internal NT syscall which may change in the future. However, unlike other NT syscalls NtQueryInformationProcess is well documented on MSDN, so I think it's safe to use. Boost shell detection by 0.3s on my machine. Note querying PowerShell's version `pwsh --version` costs another 0.2s
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -3,20 +3,68 @@ extern "C" {
|
||||
#include "common/processing.h"
|
||||
#include "common/thread.h"
|
||||
}
|
||||
#include "util/windows/wmi.hpp"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <processthreadsapi.h>
|
||||
#include <wchar.h>
|
||||
|
||||
struct ProcessInfo
|
||||
{
|
||||
uint32_t pid;
|
||||
FFstrbuf psName;
|
||||
};
|
||||
#include <chrono>
|
||||
|
||||
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe)
|
||||
#ifdef FF_USE_WIN_FAST_PPID_DETECTION
|
||||
|
||||
#include <winternl.h>
|
||||
|
||||
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);
|
||||
|
||||
Reference in New Issue
Block a user