如何在QT中实现只有一个程序进程

很多人在程序实现时可能会遇到一个问题:我只想让程序实现时只能打开一个程序进程,在已经有运行进程的情况下,如最小化到托盘的情况下,点击打开程序时,不是再次打开新进程,而是把原来进程的窗口显示出来.

这个问题有两个细节需要处理:

1:保证只打开一个进程。这个的方式有很多种.我这里用的是在程序开始时,查找到所有进程名字相同的进程id,然后通过与当前进程Id来进行处理.

2:进程已经存在时,显示存在进程的窗口。通过SendMessage向原进程窗口发送一个用户消息。程序中实现nativeEvent的重载,接收到这个消息时,把窗口显示出来。

保证只有一个进程,并发送消息

//SingleProcess.h

#pragma once
bool MakeSingle(const char* winTitle);

//SingleProcess.cpp

#include <string>
#include <map>
#include <vector>
#include <Windows.h>
#include <iostream>
#include <TlHelp32.h>
#include <algorithm>
#include <Psapi.h>

#include "SingleProcess.h"


#pragma comment(lib,"psapi.lib")

#define LogSave printf

void CloseByProcHandle(HANDLE procHandle);
HANDLE GetProcTerminateHandleByProcId(DWORD procId);
bool GetProcessName( char* processName, int maxLen);
void CloseByProcId(DWORD& procID);
std::string GetProcName(DWORD procID);
std::vector<DWORD> GetProcIDList( const char* proName );

char* wchar2char(const wchar_t* wstr, char* retStr, int retMaxLen);

wchar_t* char2wchar(const char* cstr, wchar_t* retWStr, int retMaxLen);


bool MakeSingle(const char* winTitle )
{
	char processName[MAX_PATH]={0};
	bool ret = GetProcessName(processName, MAX_PATH);
	if(!ret)
	{
		return false;
	}
	std::vector<DWORD> tList = GetProcIDList(processName);
	DWORD processId = GetCurrentProcessId();
	int size = tList.size();
	if (size == 2)
	{
		DWORD pi0 = tList[0];
		DWORD pi1 = tList[1];

		DWORD poid = 0;
		DWORD clsid = 0;
		if (pi0 == processId)
		{
			poid = pi1;
			clsid = pi0;
		}
		else if ( pi1 == processId )
		{
			poid = pi0;
			clsid = pi1;
		}
		if (poid != 0)
		{
			HWND hwnd = ::FindWindowA(NULL, winTitle);
			if (hwnd != NULL || hwnd == INVALID_HANDLE_VALUE)
			{
				::SendMessage(hwnd, WM_USER + 100, 0, 0);
			}
			CloseByProcId(clsid);
		}
	}
	//一般不会执行,防异常
	else if( size > 1)
	{
		for( int i = 0; i < size; ++i )
		{
			DWORD ck = tList[i];

			if (ck == processId)
			{
				CloseByProcId(ck);
				return false;
			}
		}
	}
	return true;
}

//

HANDLE GetProcTerminateHandleByProcId(DWORD procId)
{
	if (procId == 0)
	{
		return NULL;
	}
	HANDLE procHandle = OpenProcess(SYNCHRONIZE | PROCESS_TERMINATE, FALSE, procId);
	return procHandle;
}

void CloseByProcHandle(HANDLE procHandle)
{
	UINT exitCode = 0;
	TerminateProcess(procHandle, exitCode);
	CloseHandle(procHandle);
}
void CloseByProcId(DWORD& procID)
{
	HANDLE procHandle = GetProcTerminateHandleByProcId(procID);
	CloseByProcHandle(procHandle);

	procID = 0;
}
std::string GetProcName(DWORD procID)
{
	TCHAR szProcessName[1024] = TEXT("<unknown>");
	HANDLE procHandle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, procID);
	if (procHandle)
	{
		wchar_t tExeName[MAX_PATH] = { 0 };
		GetProcessImageFileName(procHandle, tExeName, MAX_PATH);

		CloseHandle(procHandle);
		if (tExeName[0] == 0)
		{
			return "";
		}
		char cExeName[MAX_PATH] = { 0 };
		wchar2char(tExeName, cExeName, MAX_PATH);

		std::string name = cExeName;
		std::string stdPath = cExeName;
		int index = stdPath.find_last_of('/');
		if (index > 0)
		{
			name = stdPath.substr(index + 1, stdPath.size() - index - 1);
		}
		else
		{
			index = stdPath.find_last_of('\\');
			if (index > 0)
			{
				name = stdPath.substr(index + 1, stdPath.size() - index - 1);
			}
		}
		return name;
	}
	return "";
}

bool GetProcessName(char* processName, int maxLen)
{
	char szFileFullPath[MAX_PATH] = { 0 };
	char szProcessName[MAX_PATH] = { 0 };
	::GetModuleFileNameA(NULL, szFileFullPath, MAX_PATH);//获取文件路径  
	int length = ::strlen(szFileFullPath);
	int index = -1;
	for (int i = length - 1; i >= 0; i--)//从路径后面开始找\,即倒着找右斜杠  
	{
		char ck = szFileFullPath[i];
		if (ck == '\\' || ck == '/')//找到第一个\,就可以马上获取进程名称了  
		{
			index = i + 1;
			break;
		}
	}
	if (index >= 0)
	{
		memcpy(szProcessName, szFileFullPath + index, length - index);
		strcpy(processName, szProcessName);
		return true;
	}

	return false;
}


std::vector<DWORD> GetProcIDList( const char* proName )
{
	DWORD procIDList[1024];
	DWORD retByteLen=0;
	DWORD retNumProc;
	std::vector<DWORD> tList;
	if( !EnumProcesses(procIDList, sizeof(DWORD)*1024, &retByteLen) )
	{
		return tList;
	}
	retNumProc = retByteLen/sizeof(DWORD);
	std::string srcName = proName;
	std::transform(srcName.begin(), srcName.end(), srcName.begin(), ::tolower);
	std::string ckName;
	int find_i = -1;
	for( int i = 0; i < retNumProc; ++i )
	{
		ckName = GetProcName( procIDList[i] );
		if( ckName.empty() )
		{
			continue;
		}
		std::transform(ckName.begin(),ckName.end(), ckName.begin(), ::tolower);
		find_i = ckName.find(srcName);
		if( find_i >= 0 )
		{
			tList.push_back(procIDList[i]);
		}
	}

	return tList;
}


char* wchar2char(const wchar_t* wstr, char* cstr, int retMaxLen)
{
	if( !cstr )
	{
		return cstr;
	}
	memset(cstr, 0, sizeof(char)*retMaxLen);
	if( !wstr )
	{
		return cstr;
	}

	int nlength=wcslen(wstr);

	//获取转换后的长度
	int nbytes = WideCharToMultiByte( 0, // specify the code page used to perform the conversion

		0,         // no special flags to handle unmapped characters

		wstr,     // wide character string to convert

		nlength,   // the number of wide characters in that string

		NULL,      // no output buffer given, we just want to know how long it needs to be

		0,

		NULL,      // no replacement character given

		NULL );    // we don't want to know if a character didn't make it through the translation

	// make sure the buffer is big enough for this, making it larger if necessary

	if(nbytes>retMaxLen)   nbytes=retMaxLen-1;

	// 通过以上得到的结果,转换unicode 字符为ascii 字符

	WideCharToMultiByte( 0, // specify the code page used to perform the conversion

		0,         // no special flags to handle unmapped characters

		wstr,   // wide character string to convert

		nlength,   // the number of wide characters in that string

		cstr, // put the output ascii characters at the end of the buffer

		nbytes,                           // there is at least this much space there

		NULL,      // no replacement character given

		NULL );

	return cstr;
}

wchar_t* char2wchar(const char* cstr, wchar_t* wstr, int retMaxLen)
{
	if( !wstr )
	{
		return wstr;
	}
	memset(wstr, 0, sizeof(wchar_t)*retMaxLen);
	if( !cstr )
	{
		return wstr;
	}

	size_t nu = strlen(cstr);

	size_t n =(size_t)MultiByteToWideChar(CP_ACP,0,cstr,(int)nu,NULL,0);

	if(n>=retMaxLen)n=retMaxLen-1;

	MultiByteToWideChar(CP_ACP,0,cstr,(int)nu,wstr,(int)n);

	return wstr;
}

接收消息:

//main.cpp中修改添加

const char* winTitle = "MyQTWindown";

MakeSingle(winTitle.c_str());

//Qt窗口设置窗口名字
RealTrade w;
w.setWindowTitle(winTitle);
//w.show();
int ret = a.exec();

重载nativeEvent


bool RealTrade::nativeEvent(const QByteArray &eventType, void *message, long *result)
{
	//LogSave("接收到外部消息");

	MSG* msg = reinterpret_cast<MSG*>(message);
	if (msg->message == WM_USER+100)
	{
		LogSave("WindowShow");
		show();
	}

	return false;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值