diff --git a/engine/system/sys_main.h b/engine/system/sys_main.h index 5d83fc7..e39ab6d 100644 --- a/engine/system/sys_main.h +++ b/engine/system/sys_main.h @@ -7,6 +7,7 @@ #include #include #include +#include // ======= // Classes @@ -78,6 +79,7 @@ class sys_IMain { virtual char* ClipboardPaste() = 0; virtual bool SetWorkDir(std::filesystem::path const& newCwd = {}) = 0; virtual void SpawnProcess(std::filesystem::path cmdName, const char* argList) = 0; + virtual int GetProcessCount(const std::vector& imageNames) = 0; virtual std::optional OpenURL(const char* url) = 0; virtual void Error(const char* fmt, ...) = 0; virtual void Exit(const char* msg = NULL) = 0; diff --git a/engine/system/win/sys_local.h b/engine/system/win/sys_local.h index 86d4759..fd29715 100644 --- a/engine/system/win/sys_local.h +++ b/engine/system/win/sys_local.h @@ -37,6 +37,7 @@ class sys_main_c: public sys_IMain { char* ClipboardPaste(); bool SetWorkDir(std::filesystem::path const& newCwd = {}); void SpawnProcess(std::filesystem::path cmdName, const char* argList); + int GetProcessCount(const std::vector& imageNames); std::optional OpenURL(const char* url); // return value has failure reason void Error(const char* fmt, ...); void Exit(const char* msg = NULL); diff --git a/engine/system/win/sys_main.cpp b/engine/system/win/sys_main.cpp index 3078e0d..413b72f 100644 --- a/engine/system/win/sys_main.cpp +++ b/engine/system/win/sys_main.cpp @@ -15,6 +15,7 @@ #ifdef _WIN32 #include #include +#include #elif __linux__ #include #include @@ -35,6 +36,9 @@ #include #include +#include +#include +#include // ====== // Locals @@ -434,6 +438,47 @@ void sys_main_c::SpawnProcess(std::filesystem::path cmdName, const char* argList #endif } +int sys_main_c::GetProcessCount(const std::vector& imageNames) +{ +#ifdef _WIN32 + if (imageNames.empty()) { + return 0; + } + std::unordered_set lookup; + lookup.reserve(imageNames.size()); + for (const auto& name : imageNames) { + std::wstring lowered = name; + std::transform(lowered.begin(), lowered.end(), lowered.begin(), [](wchar_t c) { + return std::towlower(c); + }); + lookup.insert(std::move(lowered)); + } + HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (snapshot == INVALID_HANDLE_VALUE) { + return -1; + } + PROCESSENTRY32W entry{}; + entry.dwSize = sizeof(entry); + int count = 0; + if (Process32FirstW(snapshot, &entry)) { + do { + std::wstring exe(entry.szExeFile); + std::transform(exe.begin(), exe.end(), exe.begin(), [](wchar_t c) { + return std::towlower(c); + }); + if (lookup.find(exe) != lookup.end()) { + ++count; + } + } while (Process32NextW(snapshot, &entry)); + } + CloseHandle(snapshot); + return count; +#else + (void)imageNames; + return -1; +#endif +} + std::string GetWineHostVersion() { #ifdef _WIN32 diff --git a/ui_api.cpp b/ui_api.cpp index 166c9d6..7fe0cf2 100644 --- a/ui_api.cpp +++ b/ui_api.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include "core/core_tex_manipulation.h" @@ -101,6 +102,7 @@ ** ConPrintTable(table[, noRecurse]) ** ConExecute("") ** SpawnProcess(""[, ""]) +** count = GetProcessCount({"", ...}) ** err = OpenURL("") ** SetProfiling(isEnabled) ** Restart() @@ -2017,6 +2019,26 @@ static int l_SpawnProcess(lua_State* L) return 0; } +static int l_GetProcessCount(lua_State* L) +{ + ui_main_c* ui = GetUIPtr(L); + ui->LAssert(L, lua_gettop(L) >= 1, "Usage: GetProcessCount(names)"); + ui->LAssert(L, lua_istable(L, 1), "GetProcessCount() argument 1: expected table, got %s", luaL_typename(L, 1)); + std::vector names; + size_t len = lua_rawlen(L, 1); + names.reserve(len); + for (size_t i = 1; i <= len; ++i) { + lua_rawgeti(L, 1, static_cast(i)); + ui->LAssert(L, lua_isstring(L, -1), "GetProcessCount() table values must be strings, got %s", luaL_typename(L, -1)); + auto name = lua_tostring(L, -1); + names.emplace_back(std::filesystem::u8path(name).wstring()); + lua_pop(L, 1); + } + int count = ui->sys->GetProcessCount(names); + lua_pushinteger(L, count); + return 1; +} + static int l_OpenURL(lua_State* L) { ui_main_c* ui = GetUIPtr(L); @@ -2249,6 +2271,7 @@ int ui_main_c::InitAPI(lua_State* L) ADDFUNC(ConClear); ADDFUNC(print); ADDFUNC(SpawnProcess); + ADDFUNC(GetProcessCount); ADDFUNC(OpenURL); ADDFUNC(SetProfiling); ADDFUNC(TakeScreenshot);