Qt防止应用多重启动和应用重启

背景

玩过DNF和梦幻的人都知道游戏可以双开,最近在想如何实现防止应用重复启动。即启动时,若发现该应用正在运行,则退出并通知已打开的应用显示在最前端。主要实现以下两部分:

  • 判断应用程序是否已经启动;
  • 与已存在的应用进行通信,通知其显示在最前端。

防止多重启动实现方法

QLockFile

QLockFile指定一个临时的"锁文件"帮助进程判断是否存在多个。刚启动应用时,使用QLockFile创建"锁文件"并进行加锁,当第二个应用启动时尝试获得该锁,若获得失败则认为该应用已经启动。若QLockFile已获得锁,则其在销毁时会删除锁文件。假若程序崩溃,锁文件会残留且会被认为失效,新程序在尝试上锁时会发现其已经失效,会使用staleLockTime进行检测,若尝试上锁时距离文件最后一次修改在staleLockTime时间内,则会上锁失败。若希望程序崩溃后可以立即重启,可将检测时间设置较小值。(QLockFile具体用法参见Qt帮助文档)

QLocalServer和QLocalSocket

使用QLocalFile获得应用运行的情况后,我们需要进行进程间通信(IPC),新启动的实例通知已存在的实例显示在最前端,然后新实例退出。
QLocalServer指定一个本地套接字的服务器,实现本地套接字的连接功能。
listen:调用此函数开始监听指定key值,当本地连接发生时会发送 newConnection信号,连接此信号可以对连接进行处理。
nextPendingConnection:调用此函数获得一个新的本地套接字,该套接字已经成功连接,可以与客户进行通信。(在server销毁时,该套接字也会被销毁)
QLocalSocket指定一个本地套接字,可以看成与本地服务器连接的客户。
connectToServer:指定server监听的key值,并与其尝试连接。
waitForConnected:当连接成功返回true或超时返回false,否则一直等待。
disconnectFromServer:尝试关闭套接字,如果有数据正在写入,则写入完成后关闭断开链接呢。

代码实现

初始化函数,根据初始化的返回值来判断程序是否退出。

int Widget::init()
{
    m_LockFile = new QLockFile(QApplication::applicationDirPath() + "/" + "lockfile.lock");
    //设置失效锁文件的检测时间,设置0时貌似有问题
	m_LockFile->setStaleLockTime(1);
	
    //尝试获得锁
    if (m_LockFile->tryLock(0)) {
        //获得锁成功,创建服务器进行监听
        m_LocalSever = new QLocalServer(this);
        connect(m_LocalSever, &QLocalServer::newConnection,
                this, &Widget::onConnection);
        m_LocalSever->listen(QApplication::applicationName());
    } else { 
        //获得锁失败,创建本地套接字(客户),请求连接并发送消息
        m_LocalSocket = new QLocalSocket(this);
        m_LocalSocket->connectToServer(QApplication::applicationName());
        if (m_LocalSocket->waitForConnected(0)) {
            //连接成功发送消息,通知已启动应用显示在最前端,返回-1退出
            m_LocalSocket->write("showTop");
            return -1;
        }
    }

    return 0;
}

服务端接收到连接请求,进行处理

void Widget::onConnection()
{
    //获得与客户通信的本地套接字
    QLocalSocket *client = m_LocalSever->nextPendingConnection();
    connect(client, &QLocalSocket::readyRead, this, [this, client](){
    //读出客户发来消息
        QByteArray arr = client->readLine();
        if (arr == "showTop") {
            if (isMinimized()) {
                showNormal();
                return;
            }
            SetWindowPos((HWND)winId(), HWND_TOPMOST, 0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
            SetWindowPos((HWND)winId(), HWND_NOTOPMOST, 0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
        }
    });

    //断开连接删除链接套接字
    connect(client, &QLocalSocket::disconnected, this, [client](){
        client->deleteLater();
    });
}
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    if (w.init() != 0) {
        return 0;
    }
    w.show();

    return a.exec();
}

应用的重启

void Widget::on_pushButton_clicked()
{
    QString program = QApplication::applicationFilePath();
    QStringList arguments = QApplication::arguments();
    QProcess::startDetached(program, arguments);
    QApplication::quit();
}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值