如何在Windows下用C++检测进程是否已运行并控制CreateProcess创建逻辑?
Windows下检测进程运行状态与避免重复创建进程的实现方案
一、C++检测进程是否运行的方法
1. 通过进程快照(Toolhelp32)检测进程名
这是最常用的通用方法,遍历系统中所有进程并匹配进程名:
#include <windows.h> #include <tlhelp32.h> #include <string> #include <cwchar> bool IsProcessRunning(const std::wstring& processName) { // 创建进程快照 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { return false; } PROCESSENTRY32 pe32{}; pe32.dwSize = sizeof(PROCESSENTRY32); // 获取第一个进程信息 if (!Process32First(hSnapshot, &pe32)) { CloseHandle(hSnapshot); return false; } // 遍历所有进程 do { // 不区分大小写匹配进程名 if (_wcsicmp(pe32.szExeFile, processName.c_str()) == 0) { CloseHandle(hSnapshot); return true; } } while (Process32Next(hSnapshot, &pe32)); CloseHandle(hSnapshot); return false; }
注意事项:
- 32位程序在64位系统中只能检测到32位进程,若要检测64位进程,需编译为64位程序或使用底层系统API(如
NtQuerySystemInformation) - 进程名可能存在重名(如多个
notepad.exe),若需精确匹配特定实例,需结合进程ID、窗口标题或互斥体等信息
2. 通过命名互斥体实现唯一实例(最可靠)
如果是确保自身程序只运行一个实例,或者目标程序支持互斥体检测,使用命名互斥体是最优方案,能避免竞态条件:
#include <windows.h> #include <iostream> int main() { // 全局命名互斥体,前缀Global\可跨用户会话检测(如服务与桌面进程) HANDLE hMutex = CreateMutexW(NULL, TRUE, L"Global\\MyUniqueApp_{F4D1A920-785E-4C2A-8F9D-5C3B8E1B1E11}"); if (hMutex == NULL) { std::cerr << "创建互斥体失败,错误码:" << GetLastError() << std::endl; return 1; } // 检查是否已有实例运行 if (GetLastError() == ERROR_ALREADY_EXISTS) { MessageBoxW(NULL, L"程序已在运行中", L"提示", MB_OK | MB_ICONINFORMATION); CloseHandle(hMutex); return 0; } // 执行程序核心逻辑,包括调用CreateProcess启动外部进程 // ... // 程序退出前释放互斥体 CloseHandle(hMutex); return 0; }
注意事项:
- 互斥体名称需全局唯一,建议使用GUID避免冲突
- 若仅需当前用户会话内唯一,可去掉
Global\\前缀
3. 通过窗口标题检测
如果目标进程有唯一可识别的窗口标题,可直接查找窗口:
#include <windows.h> #include <string> bool IsTargetWindowRunning(const std::wstring& windowTitle) { HWND hWnd = FindWindowW(NULL, windowTitle.c_str()); return hWnd != NULL; }
局限性:窗口标题可能动态变化,或多个窗口使用相同标题,可靠性较低
二、结合CreateProcess实现「已运行则不创建」逻辑
先检测目标进程状态,再决定是否调用CreateProcess:
#include <windows.h> #include <tlhelp32.h> #include <string> #include <iostream> bool IsProcessRunning(const std::wstring& processName) { // 实现同上述快照方法 HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return false; PROCESSENTRY32 pe32{}; pe32.dwSize = sizeof(PROCESSENTRY32); if (!Process32First(hSnapshot, &pe32)) { CloseHandle(hSnapshot); return false; } do { if (_wcsicmp(pe32.szExeFile, processName.c_str()) == 0) { CloseHandle(hSnapshot); return true; } } while (Process32Next(hSnapshot, &pe32)); CloseHandle(hSnapshot); return false; } int main() { const std::wstring targetExe = L"notepad.exe"; if (!IsProcessRunning(targetExe)) { STARTUPINFOW si{}; PROCESS_INFORMATION pi{}; si.cb = sizeof(si); // 注意:第二个参数需为可修改的字符串,若传入const需强制转换(确保内存可写) wchar_t cmdLine[MAX_PATH] = {0}; wcscpy_s(cmdLine, targetExe.c_str()); if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { std::wcout << L"进程创建成功,PID:" << pi.dwProcessId << std::endl; // 关闭进程与线程句柄(无需等待时立即关闭) CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } else { std::wcerr << L"创建进程失败,错误码:" << GetLastError() << std::endl; } } else { std::wcout << L"目标进程" << targetExe << L"已在运行" << std::endl; } return 0; }
三、外部检测方法(无需编写代码)
1. 命令行工具
tasklist:
tasklist /fi "imagename eq notepad.exe"若输出包含
notepad.exe,则进程正在运行wmic:
wmic process where name="notepad.exe" get processid有返回结果则进程运行中
2. PowerShell命令
Get-Process -Name notepad -ErrorAction SilentlyContinue
若返回非空结果,说明进程正在运行
内容的提问来源于stack exchange,提问作者Sahil Mirza
相关产品推荐
相关产品推荐

