Qt禁止程序多開的實現示例
更新時間:2023年09月03日 11:35:48 作者:貝勒里恩
本文主要介紹了Qt 禁止程序多開的實現示例,主要介紹了三種方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
一、前言
Qt編寫的程序,默認是可以多開的,但是有些時候,我們不希望程序可以同時打開多個,這時候就需要對程序的啟動添加限制策略,阻止程序多開。
二、常用的三種方法
1、使用共享內存
原理:運行主函數前線訪問固定的共享內存段,看看有沒有被使用。
- 如果沒有使用該內存段,就繼續(xù)運行程序;
- 如果使用了該內存段,就報警并退出;
使用:
- 修改前
#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)) //創(chuàng)建1byte的共享內存段 { Widget w; w.show(); return a.exec(); } return 0; }
2、使用QLocalServe
原理:創(chuàng)建一個本地服務器,并在程序啟動的時候去連接服務器。
- 如果連接上了,則說明已有實例程序存在,退出;
- 如果連接不上,則說明沒有創(chuàng)建服務器,創(chuàng)建一個服務器,并正常運行程序。
使用:
//連接LocalServer QString serverName = "localserver"; QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(1000)) return(-1); // 如果連接成功,說明已經存在指定的LocalServer,說明已經有應用啟動了,此時直接退出應用即可 // 如果沒有指定的LocalServer存在,則connectToServer會返回錯誤信息,此時創(chuàng)建LocalServer //創(chuàng)建LocalServer QLocalServer server; if (server.listen(serverName)) { // 此時監(jiān)聽失敗,可能是程序崩潰時,殘留進程服務導致的,移除之 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: // 有新連接時觸發(fā) void newLocalConnection(); private: // 初始化本地連接 void initLocalConnection(); // 創(chuàng)建服務端 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通訊實現程序單實例運行,監(jiān)聽到新的連接時觸發(fā)該函數 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,則創(chuàng)建,否則退出 void SingleApplication::initLocalConnection() { bRunning = false; QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(500)) { bRunning = true; // 其他處理,如:將啟動參數發(fā)送到服務端 QTextStream stream(&socket); QStringList args = QCoreApplication::arguments(); if (args.count() > 1) stream << args.last(); else stream << QString(); stream.flush(); socket.waitForBytesWritten(); return; } //連接不上服務器,就創(chuàng)建一個 newLocalServer(); } // 說明: // 創(chuàng)建LocalServer void SingleApplication::newLocalServer() { localServer = new QLocalServer(this); connect(localServer, SIGNAL(newConnection()), this, SLOT(newLocalConnection())); if(!localServer->listen(serverName)) { // 此時監(jiān)聽失敗,可能是程序崩潰時,殘留進程服務導致的,移除之 if(localServer->serverError() == QAbstractSocket::AddressInUseError) { QLocalServer::removeServer(serverName); // <-- 重點 localServer->listen(serverName); // 再次監(jiān)聽 } } }
#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() { // 創(chuàng)建互斥量 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 禁止程序多開內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java?C++?算法題解leetcode145商品折扣后最終價格單調棧
這篇文章主要介紹了Java?C++?算法題解leetcode145商品折扣后最終價格單調棧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09