WM: uses SystemBasicProcessInformation if available

This commit is contained in:
李通洲
2026-09-02 16:12:10 +08:00
parent 1128a75d8c
commit 00af2d1df2
+95 -55
View File
@@ -114,70 +114,110 @@ static bool isProcessTrusted(DWORD processId, FFProcessType processType, UNICODE
#define ffStrEqualNWS(str, compareTo) (_wcsnicmp(str, L##compareTo, sizeof(compareTo) - 1) == 0)
const char* ffDetectWMPlugin(FFstrbuf* pluginName) {
// Returns true if the process was recognized as a WM plugin and pluginName was set.
static bool handleProcess(FFstrbuf* pluginName, uint32_t pid, const UNICODE_STRING* imageName) {
alignas(UNICODE_STRING) uint8_t buffer[4096];
UNICODE_STRING* filePath = (UNICODE_STRING*) buffer;
FF_AUTO_FREE SYSTEM_PROCESS_INFORMATION* pstart = nullptr;
// Multiple attempts in case processes change while
// we are in the middle of querying them.
ULONG size = 0;
for (int attempts = 0;; ++attempts) {
if (size) {
pstart = (SYSTEM_PROCESS_INFORMATION*) realloc(pstart, size);
assert(pstart);
}
NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, pstart, size, &size);
if (NT_SUCCESS(status)) {
break;
} else if (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 4) {
size += sizeof(SYSTEM_PROCESS_INFORMATION) * 5;
if (imageName->Length == strlen("FancyWM-GUI.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(imageName->Buffer, "FancyWM-GUI.exe") &&
isProcessTrusted(pid, FF_PROCESS_TYPE_WINDOWS_STORE | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, nullptr, pluginName)) {
ffStrbufPrependS(pluginName, "FancyWM ");
} else {
return "NtQuerySystemInformation(SystemProcessInformation) failed";
ffStrbufSetStatic(pluginName, "FancyWM");
}
return true;
} else if (imageName->Length == strlen("glazewm-watcher.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(imageName->Buffer, "glazewm-watcher.exe") &&
isProcessTrusted(pid, FF_PROCESS_TYPE_SIGNED | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, nullptr, pluginName)) {
ffStrbufPrependS(pluginName, "GlazeWM ");
} else {
ffStrbufSetStatic(pluginName, "GlazeWM");
}
return true;
} else if (imageName->Length == strlen("komorebi.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(imageName->Buffer, "komorebi.exe") &&
isProcessTrusted(pid, FF_PROCESS_TYPE_CUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateNWS(filePath->Length / sizeof(wchar_t), filePath->Buffer);
if (ffProcessAppendStdOut(pluginName, (char* const[]) {
path.chars,
"--version",
nullptr,
}) == nullptr) {
ffStrbufSubstrBeforeFirstC(pluginName, '\n');
}
}
if (pluginName->length == 0) {
ffStrbufSetStatic(pluginName, "Komorebi");
}
return true;
}
for (SYSTEM_PROCESS_INFORMATION* ptr = pstart;; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
assert(ptr->ImageName.Length == 0 || ptr->ImageName.MaximumLength >= ptr->ImageName.Length + 2); // nullptr terminated
if (ptr->ImageName.Length == strlen("FancyWM-GUI.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(ptr->ImageName.Buffer, "FancyWM-GUI.exe") &&
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_WINDOWS_STORE | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, nullptr, pluginName)) {
ffStrbufPrependS(pluginName, "FancyWM ");
} else {
ffStrbufSetStatic(pluginName, "FancyWM");
}
break;
} else if (ptr->ImageName.Length == strlen("glazewm-watcher.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(ptr->ImageName.Buffer, "glazewm-watcher.exe") &&
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_SIGNED | FF_PROCESS_TYPE_GUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion && ffGetFileVersion(filePath->Buffer, nullptr, pluginName)) {
ffStrbufPrependS(pluginName, "GlazeWM ");
} else {
ffStrbufSetStatic(pluginName, "GlazeWM");
}
break;
} else if (ptr->ImageName.Length == strlen("komorebi.exe") * sizeof(wchar_t) &&
ffStrEqualNWS(ptr->ImageName.Buffer, "komorebi.exe") &&
isProcessTrusted((DWORD) (uintptr_t) ptr->UniqueProcessId, FF_PROCESS_TYPE_CUI, filePath, sizeof(buffer))) {
if (instance.config.general.detectVersion) {
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreateNWS(filePath->Length / sizeof(wchar_t), filePath->Buffer);
if (ffProcessAppendStdOut(pluginName, (char* const[]) {
path.chars,
"--version",
nullptr,
}) == nullptr) {
ffStrbufSubstrBeforeFirstC(pluginName, '\n');
}
}
if (pluginName->length == 0) {
ffStrbufSetStatic(pluginName, "Komorebi");
}
break;
return false;
}
const char* ffDetectWMPlugin(FFstrbuf* pluginName) {
if (ffIsSystemBasicProcessInfoAvailable()) {
// Unlike SystemProcessInformation, SystemBasicProcessInformation only returns processes
// (no threads), so a single query with a modest buffer is enough.
ULONG size = 0;
if (NtQuerySystemInformation(SystemBasicProcessInformation, nullptr, 0, &size) != STATUS_INFO_LENGTH_MISMATCH) {
goto fallback;
}
// The process table may change between the two calls; retry with a larger buffer.
size += size / 8 + sizeof(SYSTEM_BASICPROCESS_INFORMATION);
FF_AUTO_FREE SYSTEM_BASICPROCESS_INFORMATION* pstart = malloc(size);
if (!NT_SUCCESS(NtQuerySystemInformation(SystemBasicProcessInformation, pstart, size, &size))) {
goto fallback;
}
if (ptr->NextEntryOffset == 0) {
break;
for (auto ptr = pstart;; ptr = (SYSTEM_BASICPROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
assert(ptr >= pstart && (uint8_t*) ptr < (uint8_t*) pstart + size);
if (handleProcess(pluginName, (uint32_t)(uintptr_t) ptr->UniqueProcessId, &ptr->ImageName)) {
return nullptr;
}
// The last process in the list always has a NextEntryOffset of 0, even if the buffer was truncated.
if (!ptr->NextEntryOffset) {
break;
}
}
return nullptr;
}
fallback:
{
FF_AUTO_FREE SYSTEM_PROCESS_INFORMATION* pstart = nullptr;
// Multiple attempts in case processes change while
// we are in the middle of querying them.
ULONG size = 0;
for (int attempts = 0;; ++attempts) {
if (size) {
pstart = (SYSTEM_PROCESS_INFORMATION*) realloc(pstart, size);
assert(pstart);
}
NTSTATUS status = NtQuerySystemInformation(SystemProcessInformation, pstart, size, &size);
if (NT_SUCCESS(status)) {
break;
} else if (status == STATUS_INFO_LENGTH_MISMATCH && attempts < 4) {
size += sizeof(SYSTEM_PROCESS_INFORMATION) * 5;
} else {
return "NtQuerySystemInformation(SystemProcessInformation) failed";
}
}
for (auto ptr = pstart;; ptr = (SYSTEM_PROCESS_INFORMATION*) ((uint8_t*) ptr + ptr->NextEntryOffset)) {
assert(ptr->ImageName.Length == 0 || ptr->ImageName.MaximumLength >= ptr->ImageName.Length + 2); // nullptr terminated
if (handleProcess(pluginName, (uint32_t)(uintptr_t) ptr->UniqueProcessId, &ptr->ImageName)) {
return nullptr;
}
if (ptr->NextEntryOffset == 0) {
break;
}
}
}