TerminalShell (Windows): fix a rare case that fails to detect terminal

This commit is contained in:
李通洲
2023-01-29 20:30:13 +08:00
parent 212e7aa47e
commit a14ef06d14
4 changed files with 101 additions and 2 deletions
+4
View File
@@ -4,6 +4,10 @@ Features:
* Bluetooth module
* Sound module
Bugfixes:
* Fix a rare case that fails to detect terminal
# 1.9.1
Bugfixes:
@@ -12,12 +12,14 @@ typedef struct FFTerminalShellResult
const char* shellExeName; //pointer to a char in shellExe
FFstrbuf shellPrettyName;
FFstrbuf shellVersion;
uint32_t shellPid;
FFstrbuf terminalProcessName;
FFstrbuf terminalExe;
FFstrbuf terminalPrettyName;
const char* terminalExeName; //pointer to a char in terminalExe
FFstrbuf terminalVersion;
uint32_t terminalPid;
FFstrbuf userShellExe;
const char* userShellExeName; //pointer to a char in userShellExe
@@ -162,6 +162,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid)
) {
if (result->shellProcessName.length == 0)
{
result->shellPid = (uint32_t) pid;
ffStrbufSetS(&result->shellProcessName, name);
getProcessInformation(pid, &result->shellProcessName, &result->shellExe, &result->shellExeName);
}
@@ -170,6 +171,7 @@ static void getTerminalShell(FFTerminalShellResult* result, pid_t pid)
return;
}
result->terminalPid = (uint32_t) pid;
ffStrbufSetS(&result->terminalProcessName, name);
getProcessInformation(pid, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName);
}
@@ -336,10 +338,12 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
ffStrbufInitA(&result.shellExe, exePathLen);
result.shellExeName = result.shellExe.chars;
ffStrbufInit(&result.shellVersion);
result.shellPid = 0;
ffStrbufInit(&result.terminalProcessName);
ffStrbufInitA(&result.terminalExe, exePathLen);
result.terminalExeName = result.terminalExe.chars;
result.terminalPid = 0;
ffStrbufInit(&result.userShellExe);
result.userShellExeName = result.userShellExe.chars;
@@ -2,6 +2,7 @@ extern "C" {
#include "terminalshell.h"
#include "common/processing.h"
#include "common/thread.h"
#include "util/mallocHelper.h"
}
#include <processthreadsapi.h>
@@ -10,6 +11,7 @@ extern "C" {
#ifdef FF_USE_WIN_NTAPI
#include <ntstatus.h>
#include <winternl.h>
static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrbuf* exe, const char** exeName)
@@ -54,6 +56,45 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
return true;
}
static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid)
{
ULONG size = 0;
if(NtQuerySystemInformation(SystemProcessInformation, nullptr, 0, &size) != STATUS_INFO_LENGTH_MISMATCH)
return false;
size += sizeof(SystemProcessInformation) * 5; //What if new processes are created during two syscalls?
SYSTEM_PROCESS_INFORMATION* FF_AUTO_FREE pstart = (SYSTEM_PROCESS_INFORMATION*)malloc(size);
if(!pstart)
return false;
if(!NT_SUCCESS(NtQuerySystemInformation(SystemProcessInformation, pstart, size, nullptr)))
return false;
uint32_t currentProcessId = (uint32_t) GetCurrentProcessId();
for (auto ptr = pstart; ptr->NextEntryOffset; ptr = (SYSTEM_PROCESS_INFORMATION*)((uint8_t*)ptr + ptr->NextEntryOffset))
{
if ((uint32_t)(uintptr_t) ptr->InheritedFromUniqueProcessId != ppid)
continue;
uint32_t pid = (uint32_t)(uintptr_t) ptr->UniqueProcessId;
if (pid == currentProcessId)
continue;
if(!getProcessInfo(pid, nullptr, &result->terminalProcessName, &result->terminalExe, &result->terminalExeName))
return false;
result->terminalPid = pid;
ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName);
if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe"))
ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4);
return true;
}
return false;
}
#else
#include "util/windows/wmi.hpp"
@@ -95,6 +136,33 @@ static bool getProcessInfo(uint32_t pid, uint32_t* ppid, FFstrbuf* pname, FFstrb
return true;
}
static bool getTerminalInfoByEnumeratingChildProcesses(FFTerminalShellResult* result, uint32_t ppid)
{
wchar_t sql[256] = {};
swprintf(sql, 256, L"SELECT Name, ExecutablePath, ProcessId FROM Win32_Process WHERE ProcessId <> %" PRIu32 " AND ParentProcessId = %" PRIu32,
(uint32_t) GetCurrentProcessId(),
ppid);
FFWmiQuery query(sql);
if(!query)
return false;
if(FFWmiRecord record = query.next())
{
record.getString(L"Name", &result->terminalProcessName);
record.getString(L"ExecutablePath", &result->terminalExe);
result->terminalExeName = result->terminalExe.chars + ffStrbufLastIndexC(&result->terminalExe, '\\') + 1;
uint64_t pid;
record.getUnsigned(L"ProcessId", &pid);
result->terminalPid = (uint32_t) pid;
ffStrbufSet(&result->terminalPrettyName, &result->terminalProcessName);
if(ffStrbufEndsWithIgnCaseS(&result->terminalPrettyName, ".exe"))
ffStrbufSubstrBefore(&result->terminalPrettyName, result->terminalPrettyName.length - 4);
return true;
}
return false;
}
#endif
extern "C" bool fftsGetShellVersion(FFstrbuf* exe, const char* exeName, FFstrbuf* version);
@@ -135,6 +203,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult*
if(instance->config.shellVersion)
fftsGetShellVersion(&result->shellExe, result->shellPrettyName.chars, &result->shellVersion);
result->shellPid = pid;
if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "pwsh"))
ffStrbufSetS(&result->shellPrettyName, "PowerShell");
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "powershell"))
@@ -154,7 +223,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult*
module.dwSize = sizeof(module);
for(BOOL success = Module32FirstW(snapshot, &module); success; success = Module32NextW(snapshot, &module))
{
if(wcsncmp(module.szModule, L"clink_dll_", wcslen(L"clink_dll_")) == 0)
if(wcsncmp(module.szModule, L"clink_dll_", strlen("clink_dll_")) == 0)
{
ffStrbufAppendS(&result->shellPrettyName, "CMD (with Clink)");
break;
@@ -170,6 +239,7 @@ static uint32_t getShellInfo(const FFinstance* instance, FFTerminalShellResult*
else if(ffStrbufIgnCaseEqualS(&result->shellPrettyName, "explorer"))
{
ffStrbufSetS(&result->shellPrettyName, "Windows Explorer"); // Started without shell
// In this case, terminal process will be created by fastfetch itself.
return 0;
}
@@ -205,6 +275,21 @@ static uint32_t getTerminalInfo(const FFinstance* instance, FFTerminalShellResul
return getTerminalInfo(instance, result, ppid);
}
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "sihost") ||
ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "explorer")
) {
ffStrbufClear(&result->terminalProcessName);
ffStrbufClear(&result->terminalPrettyName);
ffStrbufClear(&result->terminalExe);
result->terminalExeName = "";
// Maybe terminal process is created by shell
if(!getTerminalInfoByEnumeratingChildProcesses(result, result->shellPid))
return 0;
}
else
result->terminalPid = pid;
if(ffStrbufIgnCaseEqualS(&result->terminalPrettyName, "WindowsTerminal"))
ffStrbufSetS(&result->terminalPrettyName, ffStrbufContainIgnCaseS(&result->terminalExe, ".WindowsTerminalPreview_")
? "Windows Terminal Preview"
@@ -288,11 +373,13 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
result.shellExeName = "";
ffStrbufInit(&result.shellPrettyName);
ffStrbufInit(&result.shellVersion);
result.shellPid = 0;
ffStrbufInit(&result.terminalProcessName);
ffStrbufInitA(&result.terminalExe, 128);
result.terminalExeName = "";
ffStrbufInit(&result.terminalPrettyName);
result.terminalPid = 0;
ffStrbufInit(&result.userShellExe);
result.userShellExeName = "";
@@ -303,7 +390,9 @@ const FFTerminalShellResult* ffDetectTerminalShell(const FFinstance* instance)
goto exit;
ppid = getShellInfo(instance, &result, ppid);
getTerminalInfo(instance, &result, ppid);
if(ppid)
getTerminalInfo(instance, &result, ppid);
if(result.terminalProcessName.length == 0)
getTerminalFromEnv(&result);