mirror of https://github.com/WerWolv/ImHex
feat: Add command line arguments to process tooltips, exclude kthreads on Linux
Fixes #2558
This commit is contained in:
parent
f234103320
commit
1db79f6117
|
|
@ -86,6 +86,7 @@ namespace hex::plugin::builtin {
|
|||
struct Process {
|
||||
u32 id;
|
||||
std::string name;
|
||||
std::string commandLine;
|
||||
ImGuiExt::Texture icon;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <winternl.h>
|
||||
#include <psapi.h>
|
||||
#include <shellapi.h>
|
||||
#elif defined(OS_MACOS)
|
||||
|
|
@ -30,9 +31,77 @@
|
|||
#include <wolv/io/fs.hpp>
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/literals.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
using namespace wolv::literals;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
using NtQueryInformationProcessFunc = NTSTATUS (NTAPI*)(
|
||||
HANDLE ProcessHandle,
|
||||
PROCESSINFOCLASS ProcessInformationClass,
|
||||
PVOID ProcessInformation,
|
||||
ULONG ProcessInformationLength,
|
||||
PULONG ReturnLength
|
||||
);
|
||||
|
||||
std::string getProcessCommandLine(HANDLE processHandle) {
|
||||
// Get NtQueryInformationProcess function
|
||||
HMODULE ntdll = GetModuleHandleA("ntdll.dll");
|
||||
if (!ntdll) return "";
|
||||
|
||||
auto funcNtQueryInformationProcess = (NtQueryInformationProcessFunc)
|
||||
(void*)GetProcAddress(ntdll, "NtQueryInformationProcess");
|
||||
if (!funcNtQueryInformationProcess) return "";
|
||||
|
||||
// Query for PROCESS_BASIC_INFORMATION to get PEB address
|
||||
PROCESS_BASIC_INFORMATION pbi = {};
|
||||
ULONG len = 0;
|
||||
NTSTATUS status = funcNtQueryInformationProcess(
|
||||
processHandle,
|
||||
ProcessBasicInformation,
|
||||
&pbi,
|
||||
sizeof(pbi),
|
||||
&len
|
||||
);
|
||||
|
||||
if (status != 0 || !pbi.PebBaseAddress) return "";
|
||||
|
||||
// Read PEB to get ProcessParameters address
|
||||
PEB peb = {};
|
||||
SIZE_T bytesRead = 0;
|
||||
if (!ReadProcessMemory(processHandle, pbi.PebBaseAddress, &peb, sizeof(peb), &bytesRead))
|
||||
return "";
|
||||
|
||||
// Read RTL_USER_PROCESS_PARAMETERS
|
||||
RTL_USER_PROCESS_PARAMETERS params = {};
|
||||
if (!ReadProcessMemory(processHandle, peb.ProcessParameters, ¶ms, sizeof(params), &bytesRead))
|
||||
return "";
|
||||
|
||||
// Read the command line string
|
||||
std::vector<wchar_t> cmdLine(params.CommandLine.Length / sizeof(wchar_t) + 1, 0);
|
||||
if (!ReadProcessMemory(processHandle, params.CommandLine.Buffer, cmdLine.data(),
|
||||
params.CommandLine.Length, &bytesRead))
|
||||
return "";
|
||||
|
||||
// Convert wide string to narrow string
|
||||
int sizeNeeded = WideCharToMultiByte(CP_UTF8, 0, cmdLine.data(), -1, nullptr, 0, nullptr, nullptr);
|
||||
if (sizeNeeded <= 0) return "";
|
||||
|
||||
std::string result(sizeNeeded, 0);
|
||||
WideCharToMultiByte(CP_UTF8, 0, cmdLine.data(), -1, &result[0], sizeNeeded, nullptr, nullptr);
|
||||
|
||||
// Remove trailing null terminator
|
||||
if (!result.empty() && result.back() == '\0')
|
||||
result.pop_back();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool ProcessMemoryProvider::open() {
|
||||
if (m_selectedProcess == nullptr)
|
||||
return false;
|
||||
|
|
@ -202,7 +271,7 @@ namespace hex::plugin::builtin {
|
|||
}
|
||||
}
|
||||
|
||||
m_processes.push_back({ u32(processId), processName, std::move(texture) });
|
||||
m_processes.push_back({ u32(processId), processName, getProcessCommandLine(processHandle), std::move(texture) });
|
||||
}
|
||||
#elif defined(OS_MACOS)
|
||||
std::array<pid_t, 2048> pids;
|
||||
|
|
@ -213,7 +282,7 @@ namespace hex::plugin::builtin {
|
|||
const auto result = proc_pidinfo(pids[i], PROC_PIDTBSDINFO, 0,
|
||||
&proc, PROC_PIDTBSDINFO_SIZE);
|
||||
if (result == PROC_PIDTBSDINFO_SIZE) {
|
||||
m_processes.emplace_back(pids[i], proc.pbi_name, ImGuiExt::Texture());
|
||||
m_processes.emplace_back(pids[i], proc.pbi_name, proc->pbi_comm, ImGuiExt::Texture());
|
||||
}
|
||||
}
|
||||
#elif defined(OS_LINUX)
|
||||
|
|
@ -228,13 +297,40 @@ namespace hex::plugin::builtin {
|
|||
continue; // not a PID
|
||||
}
|
||||
|
||||
wolv::io::File file(path /"cmdline", wolv::io::File::Mode::Read);
|
||||
// Parse status file
|
||||
wolv::io::File file(path / "status", wolv::io::File::Mode::Read);
|
||||
std::map<std::string, std::string> statusInfo;
|
||||
if (file.isValid()) {
|
||||
const auto statusContent = file.readString(1_MiB);
|
||||
for (const auto &line : wolv::util::splitString(statusContent, "\n")) {
|
||||
const auto delimiterPos = line.find(':');
|
||||
if (delimiterPos != std::string::npos) {
|
||||
const auto key = line.substr(0, delimiterPos);
|
||||
const auto value = line.substr(delimiterPos + 1);
|
||||
statusInfo[key] = wolv::util::trim(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip kernel threads
|
||||
if (statusInfo.contains("Kthread") && statusInfo["Kthread"] == "1")
|
||||
continue;
|
||||
|
||||
// Parse process name
|
||||
std::string processName;
|
||||
if (statusInfo.contains("Name")) {
|
||||
processName = statusInfo["Name"];
|
||||
}
|
||||
|
||||
wolv::io::File cmdlineFile(path / "cmdline", wolv::io::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
std::string processName = file.readString(0xF'FFFF);
|
||||
auto commandLine = cmdlineFile.readString(1_MiB);
|
||||
if (processName.empty())
|
||||
processName = commandLine;
|
||||
|
||||
m_processes.emplace_back(processId, processName, ImGuiExt::Texture());
|
||||
m_processes.emplace_back(processId, processName, commandLine, ImGuiExt::Texture());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
@ -265,7 +361,11 @@ namespace hex::plugin::builtin {
|
|||
ImGui::TableNextColumn();
|
||||
|
||||
auto height = ImGui::GetTextLineHeight();
|
||||
ImGui::Image(process->icon, { height, height });
|
||||
if (process->icon.isValid()) {
|
||||
ImGui::Image(process->icon, { height, height });
|
||||
} else {
|
||||
ImGui::Dummy({ height, height });
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormatted("{}", process->id);
|
||||
|
|
@ -274,6 +374,15 @@ namespace hex::plugin::builtin {
|
|||
if (ImGui::Selectable(process->name.c_str(), m_selectedProcess != nullptr && process->id == m_selectedProcess->id, ImGuiSelectableFlags_SpanAllColumns))
|
||||
m_selectedProcess = process;
|
||||
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_Stationary | ImGuiHoveredFlags_DelayNormal)) {
|
||||
if (ImGui::BeginTooltip()) {
|
||||
ImGui::PushTextWrapPos(200_scaled);
|
||||
ImGui::TextWrapped("%s", process->commandLine.c_str());
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue