进程同目录下单例运行实现
工作中遇到一个实际需求,用户要求程序能够多开,不同目录下的进程通过配置操作不同的系统资源。在实际应用过程中,用户经常将通目录下程序多次运行,导致监控的资源出现竞争问题。
经过查找资料整理,总结出了一套解决方案,仅供参考。
1、启动程序时候通过经常快照查看是否存在该执行程序名字的进程。
2、存在进程就判断该进程的根目录是否为当前运行进程目录。
3、如果为当前进程目录,查找到改进程的主窗口句柄,并将该窗口显示到顶层窗口。
具体实现步骤
一、系统中是否存在该目录执行程序进程
1、使用CreateToolhelp32Snapshot、Process32First、OpenProcess遍历系统进程快照,打开进程PID。
2、通过OpenProcess获得进程HANDLE,然后使用GetModuleFileNameExA获得该进程所在的根目录。
3、比较目录是否为当前执行程序所在目录。
代码实现如下
BOOL ProcessIsRun(DWORD &pid)
{
char filePath[MAX_PATH] = {0};
GetModuleFileName(GetModuleHandle(NULL),filePath,MAX_PATH);
string processPath(filePath);
if (processPath.empty())
{
return FALSE;
}
string processName = "";
int nPos = processPath.rfind('\\');
processName = processPath.substr(nPos+1,string::npos);
const char *processname = processName.c_str();
char temp[1024];
PROCESSENTRY32 pe32;
pe32.dwSize=sizeof(pe32);
HANDLE hProcessSnap=::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
if(hProcessSnap==INVALID_HANDLE_VALUE)
{
::MessageBox(NULL,"CreateToolhelp32Snapshot error","error",MB_OK);
return -1;
}
HANDLE hProcess;
BOOL bMore=::Process32First(hProcessSnap,&pe32);
while(bMore)
{
::wsprintf(temp,"%s",pe32.szExeFile);
if(!::strcmp(temp,processname))
{
if (pe32.th32ProcessID != GetCurrentProcessId())
{
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,(DWORD)pe32.th32ProcessID);
if(hProcess != NULL)
{
char strFilePath[MAX_PATH] = {0} ;
char strProcessName[MAX_PATH] = {0} ;
GetModuleFileNameExA(hProcess, NULL, strFilePath, MAX_PATH);
if(0 == ::strcmp(processPath.c_str(),strFilePath))
{
pid = pe32.th32ProcessID;
return TRUE;
}
}
else
{
break;
}
}
}
bMore=::Process32Next(hProcessSnap,&pe32);
}
return FALSE;
}
二、找到通目录下执行程序的进程PID后将界面呼出显示
1、使用EnumWindows枚举系统中的所有窗口。
2、使用GetWindowThreadProcessId获得该窗口所属的进程。
3、通过GetWindow获取父窗口是否为空来判断窗口是否为主窗口。
4、通过ShowWindow将主窗口进行前置显示
代码实现如下
BOOL IsMainWindow(HWND handle)
{
return GetWindow(handle, GW_OWNER) == (HWND)0 ;
}
BOOL CALLBACK EnumWindowsCallback(HWND handle, LPARAM lParam)
{
handle_data& data = *(handle_data*)lParam;
unsigned long process_id = 0;
GetWindowThreadProcessId(handle, &process_id);
if (data.process_id != process_id || !IsMainWindow(handle))
{
return TRUE;
}
data.best_handle = handle;
return FALSE;
}
HWND FindMainWindow(const DWORD &process_id)
{
handle_data data;
data.process_id = process_id;
data.best_handle = 0;
EnumWindows(EnumWindowsCallback, (LPARAM)&data);
if(NULL != data.best_handle)
{
SetForegroundWindow(data.best_handle);
ShowWindow(data.best_handle,SW_RESTORE);
}
return data.best_handle;
}