Qt 防多开

来源:互联网 发布:java编程代码 编辑:程序博客网 时间:2024/05/16 12:26

防止多开传统的做法有文件锁(如Eclipse的.lock文件), 进程间通信等.

但是使用文件锁方式原实例无法知晓有新实例试图启动, 从而置顶自己的窗口.


进程间通信可以使用共享内存. 如使用启动中的腾讯qq来登录qq音乐.也可以使用server, socket这样讨巧的方法

Qt本身没有提供一个跨平台的防多开解决方案, 官方推荐的QSingleApplication解决方案并不包含在Qt的library中,并且貌似是遵从商业协议而非社区版本. 所以需要我们自己来实现一个.


使用共享内存和文件锁的一个缺点是,程序一旦异常退出, 可能导致下一次无法正常启动 (还记得要去手动删除Eclipse的.lock文件的时候吧)

而使用QLocalServer和QLocalSocket结合QSharedMemory可以很好的实现多开的检查以及对先前实例的唤醒.


参考链接:http://www.qtcentre.org/wiki/index.php?title=SingleApplication#Introduction

我的实际例子

// singleApplication.h
#ifndef SINGLEAPPLICATION_H
#define SINGLEAPPLICATION_H
#include <QApplication>
#include <QSharedMemory>
#include <QLocalServer>
#include "dlgmain.h"
class SingleApplication : public QApplication
{
    Q_OBJECT
public:
    explicit SingleApplication(int &argc, char* argv[], const QString uniqueKey);
    bool isRunning();
    bool sendMessage(const QString & message);
public slots:
    void receiveMessage();
    void showMainWindow();
signals:
    void messageAvailable(QString message);
private:
    bool _isRunning;
    QString _uniqueKey;
    QSharedMemory sharedMemory;
    QLocalServer* localServer;
    static const int timeout = 1000;
};
#endif // SINGLEAPPLICATION_H

// singleApplication.cpp
#include "singleapplication.h"
#include <QLocalSocket>
/*
 * CONSTRUCTION: set SingleApplication's shareMemory key to <uniqueKey>
 * test attach , if success, already has an instance running
 * if not running, use shareMemory to create a segment in the memory
 * new a server to listem for <uniqueKey>, once received, hand over to SLOT(receiveMessage())
 *
 */
SingleApplication::SingleApplication(int &argc, char* argv[], const QString uniqueKey) :
    QApplication(argc, argv), _uniqueKey(uniqueKey)
{
    sharedMemory.setKey(_uniqueKey);
    if(sharedMemory.attach()){
        _isRunning = true;
    }
    else{
        _isRunning = false;
        if(!sharedMemory.create(1)){
            qDebug()<<"Unable to create single instance";
            return;
        }
        // create local server and listener to incomming message from other instances.
        localServer = new QLocalServer(this);
//        connect(localServer, SIGNAL(newConnection()), this, SLOT(receiveMessage()));
        connect(localServer, SIGNAL(newConnection()), this, SLOT(showMainWindow()));
        localServer->listen(_uniqueKey);
    }
}
// public slot
/*
 * RECIVER: waiting for connection.once get one connection, create a socket to communicate with the client.
 *
 */
void SingleApplication::receiveMessage(){
    qDebug()<<"receiveMessage";
    QLocalSocket* localSocket = localServer->nextPendingConnection();
    if(!localSocket->waitForReadyRead(timeout)){
        qDebug()<<"localSocket waitForReadyRead failed.";
        qDebug()<<localSocket->errorString().toLatin1();
        return;
    }
    QByteArray byteArray = localSocket->readAll();
    QString message = QString::fromUtf8(byteArray.constData());
    emit messageAvailable(message);
    localSocket->disconnectFromServer();
}
void SingleApplication::showMainWindow(){
    QLocalSocket *localSocket = localServer->nextPendingConnection();
    if (!localSocket)
        return;
    delete localSocket;
    DlgMain::shareInstance()->show();
}
// public functions;
bool SingleApplication::isRunning(){
    qDebug()<<"SingleApplication is running? "<<_isRunning;
    return _isRunning;
}
/*
 * SENDER: if there is already a instance running, create a Socket to communicate with It's Server.
 *
 */
bool SingleApplication::sendMessage(const QString &message){
    qDebug()<<"sendMessage";
    if(!_isRunning){
        return false;
    } // no instance, do nothing.
    QLocalSocket localSocket(this);
    localSocket.connectToServer(_uniqueKey, QIODevice::WriteOnly);
    if(!localSocket.waitForConnected(timeout)){
        qDebug()<<"waitForConnected";
        qDebug()<<localSocket.errorString().toLatin1();
        return false;
    }
    if(!localSocket.waitForBytesWritten(timeout)){
        qDebug()<<"waitForBytesWritten";
        qDebug()<<localSocket.errorString().toLatin1();
        return false;
    }
    localSocket.disconnectFromServer();
    return true;
}

使用方式:(直接把上面的类拷去用就行,)

// 注意一下main.cpp的调用以及槽的使用就行
#include "dlglogin.h"
#include "singleapplication.h"
int main(int argc, char *argv[])
{
    SingleApplication app(argc, argv, "CocosPlay");
    if(app.isRunning()) {
        app.sendMessage("call");
        return 0;
    }
    QObject::connect(&app, SIGNAL(messageAvailable(QString)), &app, SLOT(showMainWindow()));
 
    DlgLogin* mainWindow = DlgLogin::shareInstance();
    mainWindow->show();
    mainWindow->on_btnLogin_clicked();
    return app.exec();
}



0 0
原创粉丝点击