Qt实现检测软件是否多开

Qt实现检测软件是否多开

在桌面软件开发中,软件通常要设置只允许存在一个进程,像一些熟知的音乐软件,QQ音乐这种。而这些软件在限制只有一个进程的同时,通常还会有双击桌面图标唤醒已运行的后台进程的功能。关于双击桌面唤醒已运行进程的方法,请看这篇文章:"还未完成"

本文中所介绍的各种方法,都基本遵循一个逻辑,即:
监测同一个资源,根据资源的占用情况,来决定是否能够启动。

平台特殊

操作系统提供了一些API供我们使用,所以接下来介绍一些使用特定系统API的方法。

windows

CreateMutex

具体API内容请看:MS Learn CreateMutexW

简单来讲,就是创建一个指定命名的互斥对象。当这个互斥对象已存在时,函数将会返回一个错误。

如果 lpName 与现有事件、信号量、可等待计时器、作业或文件映射对象的名称匹配,则函数将失败, GetLastError 函数返回 ERROR_INVALID_HANDLE

思路

通过这个错误,我们就能判断互斥对象创建成功还是失败,进一步根据创建结果去判断有没有实例正在运行。但是要注意一个点,在软件退出的时候,需要将软件启动时创建的互斥对象销毁掉。

代码
cpp 复制代码
    HANDLE m_had = CreateMutex(NULL, TRUE, name.toStdWString().c_str());
    if (GetLastError() == ERROR_ALREADY_EXISTS){
        return false;
    }
    else{
        return true;
    }

	// 解锁
    if (m_had != NULL)
    {
        ret = CloseHandle(m_had);
        if (ret)
        {
            m_had = NULL;
        }
    }

直接检测进程名称

当然,要实现这种需求最简单的就是直接检测进程的运行。以Windows下的应用程序拓展名(exe)为例:

cpp 复制代码
bool checkProcessRunning(const QString& processName, QList<quint64>& listProcessId)
{
	bool res = false;
	HANDLE    hToolHelp32Snapshot;
	hToolHelp32Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
	PROCESSENTRY32    pe = { sizeof(PROCESSENTRY32) };
	BOOL  isSuccess = Process32First(hToolHelp32Snapshot, &pe);
	while (isSuccess)
	{
		size_t len = WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, wcslen(pe.szExeFile), NULL, 0, NULL, NULL);
		char* des = (char*)malloc(sizeof(char) * (len + 1));
		WideCharToMultiByte(CP_ACP, 0, pe.szExeFile, wcslen(pe.szExeFile), des, len, NULL, NULL);
		des[len] = '\0';
		if (!strcmp(des, processName.toStdString().c_str()))
		{
			listProcessId.append(pe.th32ProcessID);
			res = true;
		}
		free(des);
		isSuccess = Process32Next(hToolHelp32Snapshot, &pe);
	}
	CloseHandle(hToolHelp32Snapshot);
	return res;
}

通用方案

对于需要跨平台开发的同学们,上面说的系统API就没办法满足一套代码就可以实现需求。所以下面介绍一些使用Qt封装的一些上层接口的方法。

QLocalServer + QLocalSocket

通过启动一个本地的socket服务,当软件启动时,连接对应的socket服务,根据服务的连接情况,来确定是否已经有实例运行了。

cpp 复制代码
// 创建socket,连接服务
QLocalSocket socket;
socket.connectToServer("server_name", QIODevice::WriteOnly);
if (socket.waitForConnected(500)) {
    // 代表有实例已经运行
    return;
}

// 如果没有实例运行,则创建QLocalServer
m_pLocalServer = new QLocalServer();

if (!localServer.listen("server_name")){
    // 监听失败处理
}

QSharedMemory

在软件运行时,绑定到指定的共享内存中,如果共享内存不存在,则附加成功,也就意味着当前没有程序正在运行。反之,则代表程序正在运行。

cpp 复制代码
//通过共享内存,让程序只产生一个运行实例
QSharedMemory sharedMemory("xxx");
if (sharedMemory.attach(QSharedMemory::ReadOnly))
{
    //已创建有共享内存
    return 0;
}
//创建共享内存,空间大小为1字节
sharedMemory.create(1);

总结

看到这里,不难发现,除了直接获取进程是否存在,其余实现需求的方法归根结底就是一个路子:
进程间通信。 所以只要能够实现进程间通信的方法,都可以用来实现这个需求,哪怕是 RPC。

相关推荐
伐尘7 小时前
【Qt】编译 Qt 5.15.x For Windows 基础教程 Visual Studio 2019 MSVC142 x64
windows·qt·visual studio
吃面不喝汤668 小时前
破解 Qt QProcess 在 Release 模式下的“卡死”之谜
开发语言·qt
搏博11 小时前
软件工程之软件项目管理深度解析
软件工程·软件构建·需求分析·软件需求
charlie11451419115 小时前
逐步理解Qt信号与槽机制
数据库·qt
yaso_zhang20 小时前
当生产了~/qt-arm/bin/qmake,可以单独编译其他-源码的某个模块,如下,编译/qtmultimedia
qt
code bean20 小时前
【Qt/C++】深入理解 Lambda 表达式与 `mutable` 关键字的使用
开发语言·c++·qt
爱看书的小沐1 天前
【小沐学GIS】基于C++绘制二维瓦片地图2D Map(QT、OpenGL、GIS)
c++·qt·gis·opengl·glfw·glut·二维地图
搏博2 天前
软件工程之需求分析涉及的图与工具
数据库·软件工程·软件构建·软件需求
炬火初现2 天前
Qt 的原理及使用(1)——qt的背景及安装
开发语言·qt
weixin_1102 天前
Qt 无边框窗口,支持贴边分屏
c++·qt