Qt禁止程序多开的实现示例

 更新时间:2023年09月03日 11:35:48   作者:贝勒里恩  
本文主要介绍了Qt 禁止程序多开的实现示例,主要介绍了三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

一、前言

Qt编写的程序,默认是可以多开的,但是有些时候,我们不希望程序可以同时打开多个,这时候就需要对程序的启动添加限制策略,阻止程序多开。

二、常用的三种方法

1、使用共享内存

原理:运行主函数前线访问固定的共享内存段,看看有没有被使用。

  • 如果没有使用该内存段,就继续运行程序;
  • 如果使用了该内存段,就报警并退出;

使用

  • 修改前
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
  • 修改后
#include "widget.h"
#include <QApplication>
#include <QSharedMemory>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QSharedMemory shared_memory;            
    shared_memory.setKey(QString("666666"));//设置固定共享内存段的key值
    if(shared_memory.attach())   //尝试将进程附加到该共享内存段
    {
        return 0;   
    }
    if(shared_memory.create(1)) //创建1byte的共享内存段
    {
        Widget w;
        w.show();
        return a.exec();
    }
    return 0;
}

2、使用QLocalServe

原理:创建一个本地服务器,并在程序启动的时候去连接服务器。

  • 如果连接上了,则说明已有实例程序存在,退出;
  • 如果连接不上,则说明没有创建服务器,创建一个服务器,并正常运行程序。

使用

    //连接LocalServer
    QString serverName = "localserver";
    QLocalSocket socket;
    socket.connectToServer(serverName);
    if(socket.waitForConnected(1000)) return(-1);
// 如果连接成功,说明已经存在指定的LocalServer,说明已经有应用启动了,此时直接退出应用即可
// 如果没有指定的LocalServer存在,则connectToServer会返回错误信息,此时创建LocalServer
    //创建LocalServer
    QLocalServer server;
    if (server.listen(serverName)) {
        // 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之
        if(server.serverError()== QAbstractSocket::AddressInUseError){
            QLocalServer::removeServer(serverName); 
            server.listen(serverName);
        }
    }

基于QLocalServer原理的定制类:

#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H
#include <QObject>
#include <QApplication>
class QWidget;
class QLocalServer;
class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    SingleApplication(int &argc, char **argv);
    bool isRunning();               // 是否已经有实例在运行
    QWidget *mainWindow;            // MainWindow指针
private slots:
    // 有新连接时触发
    void newLocalConnection();
private:
    // 初始化本地连接
    void initLocalConnection();
    // 创建服务端
    void newLocalServer();
    bool bRunning;                  // 是否已经有实例在运行
    QLocalServer *localServer;      // 本地socket Server
    QString serverName;             // 服务名称
};
#endif // SINGLEAPPLICATION_H
#include "SingleApplication.h"
#include <QWidget>
#include <QtNetwork/QLocalSocket>
#include <QtNetwork/QLocalServer>
#include <QFileInfo>
#include <QLibrary>
SingleApplication::SingleApplication(int &argc, char **argv)
    : QApplication(argc, argv)
    , bRunning(false)
    , localServer(NULL)
    , mainWindow(NULL)
{
    // 取应用程序名作为LocalServer的名字
    serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName();
    //qDebug()<<serverName;
    initLocalConnection();
}
// 说明:
// 检查是否已經有一个实例在运行, true - 有实例运行, false - 没有实例运行
bool SingleApplication::isRunning()
{
    return bRunning;
}
// 说明:
// 通过socket通讯实现程序单实例运行,监听到新的连接时触发该函数
void SingleApplication::newLocalConnection()
{
    QLocalSocket *socket = localServer->nextPendingConnection();
    if (!socket)
        return;
    socket->waitForReadyRead(1000);
    QTextStream stream(socket);
    //其他处理
    delete socket;
    if (mainWindow != NULL)
    {
        //激活窗口
        mainWindow->raise();
        mainWindow->activateWindow();
        mainWindow->setWindowState((mainWindow->windowState() & ~Qt::WindowMinimized) | Qt::WindowActive);
        mainWindow->show();
    }
}
// 说明:
// 通过socket通讯实现程序单实例运行,
// 初始化本地连接,如果连接不上server,则创建,否则退出
void SingleApplication::initLocalConnection()
{
    bRunning = false;
    QLocalSocket socket;
    socket.connectToServer(serverName);
    if(socket.waitForConnected(500))
    {
        bRunning = true;
        // 其他处理,如:将启动参数发送到服务端
        QTextStream stream(&socket);
        QStringList args = QCoreApplication::arguments();
        if (args.count() > 1)
            stream << args.last();
        else
            stream << QString();
        stream.flush();
        socket.waitForBytesWritten();
        return;
    }
    //连接不上服务器,就创建一个
    newLocalServer();
}
// 说明:
// 创建LocalServer
void SingleApplication::newLocalServer()
{
    localServer = new QLocalServer(this);
    connect(localServer, SIGNAL(newConnection()), this, SLOT(newLocalConnection()));
    if(!localServer->listen(serverName))
    {
        // 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之
        if(localServer->serverError() == QAbstractSocket::AddressInUseError)
        {
            QLocalServer::removeServer(serverName); // <-- 重点
            localServer->listen(serverName); // 再次监听
        }
    }
}
#include "mainwindow.h"
#include "SingleApplication.h"
int main(int argc, char *argv[])
{
    //单实例进程,或者说防止程序多开
    SingleApplication a(argc, argv);
    if (!a.isRunning())
    {        
        MainWindow w;
        //传入一个要激活程序的窗口,当多开时会激活已有进程的窗口,且多开失败
        a.mainWindow = &w;
        w.show();
        return a.exec();
    }
    return 0;
}

3、使用互斥量和文件锁

Q_OS_WIN32宏用来表示编译运行的目标平台是windows,Q_OS_LINUX则标示目标为linux

#if defined Q_OS_WIN32   //for win  
#include <windows.h>  
bool checkOnly()  
{  
    //  创建互斥量  
    HANDLE m_hMutex  =  CreateMutex(NULL, FALSE,  L"fortest_abc123" );  
    //  检查错误代码  
    if  (GetLastError()  ==  ERROR_ALREADY_EXISTS)  {  
      //  如果已有互斥量存在则释放句柄并复位互斥量  
     CloseHandle(m_hMutex);  
     m_hMutex  =  NULL;  
      //  程序退出  
      return  false;  
    }  
    else  
        return true;  
}  
#endif  
#if defined  Q_OS_LINUX   //for linux  
#include <sys/types.h>  
#include <sys/stat.h>  
#include <fcntl.h>  
#include <unistd.h>  
bool checkOnly()  
{  
    const char filename[]  = "/tmp/lockfile";  
    int fd = open (filename, O_WRONLY | O_CREAT , 0644);  
    int flock = lockf(fd, F_TLOCK, 0 );  
    if (fd == -1) {  
            perror("open lockfile/n");  
            return false;  
    }  
    //给文件加锁  
    if (flock == -1) {  
            perror("lock file error/n");  
            return false;  
    }  
    //程序退出后,文件自动解锁  
    return true;  
}  
#endif  
int main(int argc, char *argv[])  
{  
    QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));  
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030"));  
    Q_INIT_RESOURCE(wisdpsclient);  
    QApplication app(argc, argv);  
    //检查程序是否 已经启动过  
    if(checkOnly()==false)  
        return 0;  
    Test dialog;  
    dialog.show();  
    return app.exec();  
} 

到此这篇关于Qt禁止程序多开的实现示例的文章就介绍到这了,更多相关Qt 禁止程序多开内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C语言实现数据的压缩与解压

    C语言实现数据的压缩与解压

    数据压缩是通过一系列的算法和技术将原始数据转换为更紧凑的表示形式,以减少数据占用的存储空间,数据解压缩则是将压缩后的数据恢复到原始的表示形式,本文给大家详细介绍了C语言实现数据压缩与解压,需要的朋友可以参考下
    2023-08-08
  • FFmpeg实现将编码后数据保存成mp4

    FFmpeg实现将编码后数据保存成mp4

    这篇文章主要为大家详细介绍了FFmpeg如何实现将编码后数据保存成mp4,即从内存块中获取原始数据,然后依次进行解码、编码、最后保存成mp4视频文件,感兴趣的可以了解一下
    2023-08-08
  • Linux系统下如何使用C++解析json文件详解

    Linux系统下如何使用C++解析json文件详解

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。下面这篇文章主要给大家介绍了关于Linux系统下如何使用C++解析json文件的相关资料,需要的朋友可以参考下
    2021-06-06
  • C++实现LeetCode(211.添加和查找单词-数据结构设计)

    C++实现LeetCode(211.添加和查找单词-数据结构设计)

    这篇文章主要介绍了C++实现LeetCode(211.添加和查找单词-数据结构设计),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-08-08
  • 利用C++实现获取文件夹下所有文件名

    利用C++实现获取文件夹下所有文件名

    这篇文章主要为大家详细介绍了如何利用C++实现获取文件夹下所有文件名,文中的示例代码讲解详细,对我们学习C++有一定帮助,需要的可以参考一下
    2022-09-09
  • C 语言指针概念的详解

    C 语言指针概念的详解

    这里主要介绍C 语言指针,这里整理了详细的资料,对指针做了详细说明及简单示例代码帮助大家理解什么是指针,有兴趣的小伙伴可以参考下
    2016-08-08
  • C++ 私有析构函数的作用示例详解

    C++ 私有析构函数的作用示例详解

    这篇文章主要介绍了C++ 私有析构函数的作用,私有析构函数不会影响栈上对象的自动析构,它们会在其作用域结束时自动调用析构函数。私有析构函数主要影响的是对堆上对象的显式删除操作,需要的朋友可以参考下
    2023-06-06
  • C++的字符串分割函数的使用详解

    C++的字符串分割函数的使用详解

    本篇文章主要介绍了C++的字符串分割函数,主要用strtok、STL、Boost进行字符串分割,有需要的可以了解一下。
    2016-11-11
  • Qt音视频开发之利用ffmpeg实现解码本地摄像头

    Qt音视频开发之利用ffmpeg实现解码本地摄像头

    一开始用ffmpeg做的是视频流的解析,后面增加了本地视频文件的支持,到后面发现ffmpeg也是支持本地摄像头设备的,所以本文就来用ffmpeg实现解码本地摄像头功能吧
    2023-03-03
  • c++函数中的指针参数与地址参数区别介绍

    c++函数中的指针参数与地址参数区别介绍

    c++函数中的指针参数与地址参数区别介绍;可供参考
    2012-11-11

最新评论