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。

相关推荐
一叶之秋14127 小时前
QT背景介绍与环境搭建
开发语言·qt
QT 小鲜肉8 小时前
【QT/C++】Qt网络编程进阶:UDP通信和HTTP请求的基本原理和实际应用(超详细)
c语言·网络·c++·笔记·qt·http·udp
四维碎片11 小时前
【Qt】大数据量表格刷新优化--只刷新可见区域
开发语言·qt
一叶之秋141212 小时前
Qt开发初识
开发语言·qt
梵尔纳多14 小时前
ffmpeg 使用滤镜实现播放倍速
c++·qt·ffmpeg
QT 小鲜肉17 小时前
【QT/C++】Qt网络编程进阶:TCP网络编程的基本原理和实际应用(超详细)
c语言·开发语言·网络·c++·qt·学习·tcp/ip
Tony小周1 天前
使用QKeyEvent keyPress(QEvent::KeyPress, key模拟键盘发送事件,会导致主程序卡死
嵌入式硬件·qt
Larry_Yanan1 天前
QML学习笔记(五十)QML与C++交互:QML中单例C++对象
开发语言·c++·笔记·qt·学习·ui·交互
zhmhbest1 天前
Qt 全球峰会 2025:中国站速递 —— 技术中立,拥抱更大生态
开发语言·qt·系统架构
feiyangqingyun1 天前
Qt实时绘制飞行轨迹/移动轨迹实时显示/带旋转角度/平滑移动/效果一级棒/地面站软件开发/无人机管理平台
qt·无人机·集群地面站