写一段Mingw64上编译和Windows 11上运行的GCC的C++程序,获取正在运行的进程窗口的标题,通过字符串来精确匹配,或者用通配符或正则表达式,获得一个进程列表,当这个进程列表中的所有进程都退出的时候,就自动调用一个另外的exe程序或bat批处理脚本,用ini配置文件来记录配置信息,实现异常处理和日志文件写入,日志包含发生错误和运行exe或bat文件的时间戳,运行状态,运行的文件名和出现错误时的函数调用堆栈。
这个程序提供了完整的进程监视和自动执行功能,并包含了详细的日志记录和错误处理机制。
cpp
#include <windows.h>
#include <psapi.h>
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <regex>
#include <chrono>
#include <iomanip>
#include <sstream>
#include <dbghelp.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")
#pragma comment(lib, "dbghelp.lib")
#pragma comment(lib, "psapi.lib")
// 配置结构体
struct Config {
std::vector<std::string> processPatterns;
std::string executePath;
std::string logFile;
int checkInterval;
bool useRegex;
};
// 日志函数
void Log(const std::string& message, const std::string& logFile);
void LogError(const std::string& functionName, const std::string& logFile);
// 堆栈跟踪函数
std::string GetStackTrace();
// 配置读取函数
Config ReadConfig(const std::string& configFile);
std::string GetIniString(const std::string& iniFile, const std::string& section,
const std::string& key, const std::string& defaultValue);
int GetIniInt(const std::string& iniFile, const std::string& section,
const std::string& key, int defaultValue);
bool GetIniBool(const std::string& iniFile, const std::string& section,
const std::string& key, bool defaultValue);
// 进程检查函数
bool IsProcessRunning(const Config& config);
bool MatchProcessName(const std::string& processName, const std::string& pattern, bool useRegex);
std::vector<std::string> GetRunningProcesses();
// 执行程序函数
bool ExecuteProgram(const std::string& programPath, const std::string& logFile);
int main() {
// 读取配置
Config config = ReadConfig("config.ini");
if (config.processPatterns.empty()) {
Log("错误: 没有配置要监视的进程模式", config.logFile);
return 1;
}
Log("进程监视器启动", config.logFile);
Log("监视的进程模式: ", config.logFile);
for (const auto& pattern : config.processPatterns) {
Log(" - " + pattern, config.logFile);
}
Log("检查间隔: " + std::to_string(config.checkInterval) + "ms", config.logFile);
Log("使用正则表达式: " + std::string(config.useRegex ? "是" : "否"), config.logFile);
Log("目标程序: " + config.executePath, config.logFile);
// 主循环
while (true) {
try {
if (!IsProcessRunning(config)) {
Log("所有监视的进程已退出,正在启动: " + config.executePath, config.logFile);
if (ExecuteProgram(config.executePath, config.logFile)) {
Log("成功执行: " + config.executePath, config.logFile);
} else {
Log("执行失败: " + config.executePath, config.logFile);
}
break;
}
Sleep(config.checkInterval);
} catch (const std::exception& e) {
Log("异常: " + std::string(e.what()), config.logFile);
LogError("主循环", config.logFile);
} catch (...) {
Log("未知异常", config.logFile);
LogError("主循环", config.logFile);
}
}
Log("进程监视器退出", config.logFile);
return 0;
}
// 读取配置
Config ReadConfig(const std::string& configFile) {
Config config;
config.processPatterns.clear();
std::string patterns = GetIniString(configFile, "Monitor", "ProcessPatterns", "");
if (!patterns.empty()) {
size_t pos = 0;
while ((pos = patterns.find(',')) != std::string::npos) {
config.processPatterns.push_back(patterns.substr(0, pos));
patterns.erase(0, pos + 1);
}
config.processPatterns.push_back(patterns);
}
config.executePath = GetIniString(configFile, "Monitor", "ExecutePath", "");
config.logFile = GetIniString(configFile, "Monitor", "LogFile", "monitor.log");
config.checkInterval = GetIniInt(configFile, "Monitor", "CheckInterval", 5000);
config.useRegex = GetIniBool(configFile, "Monitor", "UseRegex", false);
return config;
}
// 从INI文件读取字符串
std::string GetIniString(const std::string& iniFile, const std::string& section,
const std::string& key, const std::string& defaultValue) {
char buffer[256];
DWORD result = GetPrivateProfileString(section.c_str(), key.c_str(),
defaultValue.c_str(), buffer,
sizeof(buffer), iniFile.c_str());
return std::string(buffer);
}
// 从INI文件读取整数
int GetIniInt(const std::string& iniFile, const std::string& section,
const std::string& key, int defaultValue) {
return GetPrivateProfileInt(section.c_str(), key.c_str(), defaultValue, iniFile.c_str());
}
// 从INI文件读取布尔值
bool GetIniBool(const std::string& iniFile, const std::string& section,
const std::string& key, bool defaultValue) {
int value = GetPrivateProfileInt(section.c_str(), key.c_str(),
defaultValue ? 1 : 0, iniFile.c_str());
return value != 0;
}
// 检查是否有进程在运行
bool IsProcessRunning(const Config& config) {
std::vector<std::string> processes = GetRunningProcesses();
for (const auto& pattern : config.processPatterns) {
for (const auto& process : processes) {
if (MatchProcessName(process, pattern, config.useRegex)) {
return true;
}
}
}
return false;
}
// 匹配进程名
bool MatchProcessName(const std::string& processName, const std::string& pattern, bool useRegex) {
if (useRegex) {
try {
std::regex re(pattern, std::regex::icase);
return std::regex_search(processName, re);
} catch (const std::regex_error&) {
return false;
}
} else {
// 使用通配符匹配
return PathMatchSpec(processName.c_str(), pattern.c_str());
}
}
// 获取所有运行中的进程
std::vector<std::string> GetRunningProcesses() {
std::vector<std::string> processes;
DWORD aProcesses[1024], cbNeeded, cProcesses;
if (!EnumProcesses(aProcesses, sizeof(aProcesses), &cbNeeded)) {
return processes;
}
cProcesses = cbNeeded / sizeof(DWORD);
for (unsigned int i = 0; i < cProcesses; i++) {
if (aProcesses[i] == 0) continue;
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE, aProcesses[i]);
if (hProcess) {
char szProcessName[MAX_PATH] = "<未知>";
if (GetModuleBaseName(hProcess, NULL, szProcessName,
sizeof(szProcessName) / sizeof(char))) {
processes.push_back(szProcessName);
}
CloseHandle(hProcess);
}
}
return processes;
}
// 执行程序
bool ExecuteProgram(const std::string& programPath, const std::string& logFile) {
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// 创建可修改的字符串副本
char cmdLine[MAX_PATH];
strncpy(cmdLine, programPath.c_str(), MAX_PATH);
cmdLine[MAX_PATH - 1] = '\0';
// 启动程序
if (!CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
LogError("CreateProcess", logFile);
return false;
}
// 等待程序完成
WaitForSingleObject(pi.hProcess, INFINITE);
// 获取退出代码
DWORD exitCode;
if (GetExitCodeProcess(pi.hProcess, &exitCode)) {
Log("程序退出代码: " + std::to_string(exitCode), logFile);
}
// 关闭句柄
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return exitCode == 0;
}
// 记录日志
void Log(const std::string& message, const std::string& logFile) {
auto now = std::chrono::system_clock::now();
auto now_time = std::chrono::system_clock::to_time_t(now);
auto now_ms = std::chrono::duration_cast<std::chrono::milliseconds>(
now.time_since_epoch()) % 1000;
std::ostringstream oss;
oss << std::put_time(std::localtime(&now_time), "%Y-%m-%d %H:%M:%S")
<< '.' << std::setfill('0') << std::setw(3) << now_ms.count();
std::ofstream file(logFile, std::ios_base::app);
if (file.is_open()) {
file << "[" << oss.str() << "] " << message << std::endl;
}
}
// 记录错误
void LogError(const std::string& functionName, const std::string& logFile) {
DWORD error = GetLastError();
if (error == 0) {
return;
}
LPSTR messageBuffer = nullptr;
size_t size = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)&messageBuffer, 0, NULL);
std::string message(messageBuffer, size);
LocalFree(messageBuffer);
std::string logMessage = "错误在 " + functionName + ": " + message + "\n堆栈跟踪:\n" + GetStackTrace();
Log(logMessage, logFile);
}
// 获取堆栈跟踪
std::string GetStackTrace() {
void* stack[100];
HANDLE process = GetCurrentProcess();
SymInitialize(process, NULL, TRUE);
WORD frames = CaptureStackBackTrace(0, 100, stack, NULL);
std::ostringstream oss;
SYMBOL_INFO* symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1);
symbol->MaxNameLen = 255;
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
for (int i = 0; i < frames; i++) {
SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol);
oss << i << ": " << symbol->Name << " (0x" << std::hex << symbol->Address << std::dec << ")" << std::endl;
}
free(symbol);
return oss.str();
}
编译说明
使用MinGW-w64编译此程序,需要链接以下库:
-lshlwapi
(用于PathMatchSpec函数)-ldbghelp
(用于堆栈跟踪功能)-lpsapi
(用于进程枚举)
编译命令示例:
bash
g++ -std=c++11 -o process_monitor.exe process_monitor.cpp -lshlwapi -ldbghelp -lpsapi
配置文件示例 (config.ini)
ini
[Monitor]
; 要监视的进程名称模式,多个模式用逗号分隔
ProcessPatterns=notepad.exe,chrome.exe,firefox.exe
; 当所有监视进程退出后要执行的程序或批处理
ExecutePath=C:\path\to\your\program.exe
; 日志文件路径
LogFile=monitor.log
; 检查进程状态的间隔(毫秒)
CheckInterval=5000
; 是否使用正则表达式匹配进程名(否则使用通配符)
UseRegex=false
功能说明
- 进程监视: 程序会定期检查系统中运行的进程,并根据配置的模式进行匹配
- 多种匹配模式: 支持通配符和正则表达式两种匹配方式
- 自动执行: 当所有匹配的进程都退出后,自动执行配置的程序或脚本
- 日志记录: 详细记录程序运行状态、错误信息和堆栈跟踪
- 错误处理: 完善的异常处理和错误报告机制
注意事项
- 程序需要以足够权限运行,以便能够枚举系统进程
- 堆栈跟踪功能需要调试符号,在发布版本中可能无法提供完整信息
- 确保配置的执行路径正确无误
- 检查间隔不宜过短,以免对系统性能造成影响