Qt禁止程序多開的實現(xiàn)示例
一、前言
Qt編寫的程序,默認(rèn)是可以多開的,但是有些時候,我們不希望程序可以同時打開多個,這時候就需要對程序的啟動添加限制策略,阻止程序多開。
二、常用的三種方法
1、使用共享內(nèi)存
原理:運(yùn)行主函數(shù)前線訪問固定的共享內(nèi)存段,看看有沒有被使用。
- 如果沒有使用該內(nèi)存段,就繼續(xù)運(yùn)行程序;
- 如果使用了該內(nèi)存段,就報警并退出;
使用:
- 修改前
#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"));//設(shè)置固定共享內(nèi)存段的key值 if(shared_memory.attach()) //嘗試將進(jìn)程附加到該共享內(nèi)存段 { return 0; } if(shared_memory.create(1)) //創(chuàng)建1byte的共享內(nèi)存段 { Widget w; w.show(); return a.exec(); } return 0; }
2、使用QLocalServe
原理:創(chuàng)建一個本地服務(wù)器,并在程序啟動的時候去連接服務(wù)器。
- 如果連接上了,則說明已有實例程序存在,退出;
- 如果連接不上,則說明沒有創(chuàng)建服務(wù)器,創(chuàng)建一個服務(wù)器,并正常運(yùn)行程序。
使用:
//連接LocalServer QString serverName = "localserver"; QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(1000)) return(-1); // 如果連接成功,說明已經(jīng)存在指定的LocalServer,說明已經(jīng)有應(yīng)用啟動了,此時直接退出應(yīng)用即可 // 如果沒有指定的LocalServer存在,則connectToServer會返回錯誤信息,此時創(chuàng)建LocalServer //創(chuàng)建LocalServer QLocalServer server; if (server.listen(serverName)) { // 此時監(jiān)聽失敗,可能是程序崩潰時,殘留進(jìn)程服務(wù)導(dǎo)致的,移除之 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(); // 是否已經(jīng)有實例在運(yùn)行 QWidget *mainWindow; // MainWindow指針 private slots: // 有新連接時觸發(fā) void newLocalConnection(); private: // 初始化本地連接 void initLocalConnection(); // 創(chuàng)建服務(wù)端 void newLocalServer(); bool bRunning; // 是否已經(jīng)有實例在運(yùn)行 QLocalServer *localServer; // 本地socket Server QString serverName; // 服務(wù)名稱 }; #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) { // 取應(yīng)用程序名作為LocalServer的名字 serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); //qDebug()<<serverName; initLocalConnection(); } // 說明: // 檢查是否已經(jīng)有一個實例在運(yùn)行, true - 有實例運(yùn)行, false - 沒有實例運(yùn)行 bool SingleApplication::isRunning() { return bRunning; } // 說明: // 通過socket通訊實現(xiàn)程序單實例運(yùn)行,監(jiān)聽到新的連接時觸發(fā)該函數(shù) 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通訊實現(xiàn)程序單實例運(yùn)行, // 初始化本地連接,如果連接不上server,則創(chuàng)建,否則退出 void SingleApplication::initLocalConnection() { bRunning = false; QLocalSocket socket; socket.connectToServer(serverName); if(socket.waitForConnected(500)) { bRunning = true; // 其他處理,如:將啟動參數(shù)發(fā)送到服務(wù)端 QTextStream stream(&socket); QStringList args = QCoreApplication::arguments(); if (args.count() > 1) stream << args.last(); else stream << QString(); stream.flush(); socket.waitForBytesWritten(); return; } //連接不上服務(wù)器,就創(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)聽失敗,可能是程序崩潰時,殘留進(jìn)程服務(wù)導(dǎo)致的,移除之 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[]) { //單實例進(jìn)程,或者說防止程序多開 SingleApplication a(argc, argv); if (!a.isRunning()) { MainWindow w; //傳入一個要激活程序的窗口,當(dāng)多開時會激活已有進(jìn)程的窗口,且多開失敗 a.mainWindow = &w; w.show(); return a.exec(); } return 0; }
3、使用互斥量和文件鎖
Q_OS_WIN32宏用來表示編譯運(yùn)行的目標(biāo)平臺是windows,Q_OS_LINUX則標(biāo)示目標(biāo)為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) { // 如果已有互斥量存在則釋放句柄并復(fù)位互斥量 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); //檢查程序是否 已經(jīng)啟動過 if(checkOnly()==false) return 0; Test dialog; dialog.show(); return app.exec(); }
到此這篇關(guān)于Qt禁止程序多開的實現(xiàn)示例的文章就介紹到這了,更多相關(guān)Qt 禁止程序多開內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用C++17實現(xiàn)JSON庫設(shè)計思路示例全解
這篇文章主要為大家介紹了使用C++17實現(xiàn)JSON庫設(shè)計思路示例全解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08基于Windows C++ 應(yīng)用程序通用日志組件的使用詳解
眾所周知,在調(diào)試、跟蹤和執(zhí)行應(yīng)用程序的過程中,程序的日志能為這些工作提供大量有價值的運(yùn)行信息。因此,程序的日志對應(yīng)用程序的運(yùn)行、維護(hù)至關(guān)重要2013-05-05C++程序內(nèi)存棧區(qū)與堆區(qū)模型案例分析
一直以來總是對這個問題的認(rèn)識比較朦朧,我相信很多朋友也是這樣的,總是聽到內(nèi)存一會在棧上分配,一會又在堆上分配,那么它們之間到底是怎么的區(qū)別呢,讓我們一起來看看2022-03-03OpenCV實戰(zhàn)之基于Hu矩實現(xiàn)輪廓匹配
這篇文章主要介紹了利用C++ OpenCV實現(xiàn)基于Hu矩的輪廓匹配,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)OpenCV有一定的幫助,感興趣的可以學(xué)習(xí)一下2022-01-01Java?C++?算法題解leetcode145商品折扣后最終價格單調(diào)棧
這篇文章主要介紹了Java?C++?算法題解leetcode145商品折扣后最終價格單調(diào)棧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09