Qt禁止程序多開的實現(xiàn)示例
一、前言
Qt編寫的程序,默認是可以多開的,但是有些時候,我們不希望程序可以同時打開多個,這時候就需要對程序的啟動添加限制策略,阻止程序多開。
二、常用的三種方法
1、使用共享內(nèi)存
原理:運行主函數(shù)前線訪問固定的共享內(nèi)存段,看看有沒有被使用。
- 如果沒有使用該內(nèi)存段,就繼續(xù)運行程序;
- 如果使用了該內(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()) //嘗試將進程附加到該共享內(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ù)器,并正常運行程序。
使用:
//連接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)聽失敗,可能是程序崩潰時,殘留進程服務(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)有實例在運行
QWidget *mainWindow; // MainWindow指針
private slots:
// 有新連接時觸發(fā)
void newLocalConnection();
private:
// 初始化本地連接
void initLocalConnection();
// 創(chuàng)建服務(wù)端
void newLocalServer();
bool bRunning; // 是否已經(jīng)有實例在運行
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)有一個實例在運行, true - 有實例運行, false - 沒有實例運行
bool SingleApplication::isRunning()
{
return bRunning;
}
// 說明:
// 通過socket通訊實現(xià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)程序單實例運行,
// 初始化本地連接,如果連接不上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)聽失敗,可能是程序崩潰時,殘留進程服務(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[])
{
//單實例進程,或者說防止程序多開
SingleApplication a(argc, argv);
if (!a.isRunning())
{
MainWindow w;
//傳入一個要激活程序的窗口,當(dāng)多開時會激活已有進程的窗口,且多開失敗
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) {
// 如果已有互斥量存在則釋放句柄并復(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è)計思路示例全解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-08-08
基于Windows C++ 應(yīng)用程序通用日志組件的使用詳解
眾所周知,在調(diào)試、跟蹤和執(zhí)行應(yīng)用程序的過程中,程序的日志能為這些工作提供大量有價值的運行信息。因此,程序的日志對應(yīng)用程序的運行、維護至關(guān)重要2013-05-05
C++程序內(nèi)存棧區(qū)與堆區(qū)模型案例分析
一直以來總是對這個問題的認識比較朦朧,我相信很多朋友也是這樣的,總是聽到內(nèi)存一會在棧上分配,一會又在堆上分配,那么它們之間到底是怎么的區(qū)別呢,讓我們一起來看看2022-03-03
OpenCV實戰(zhàn)之基于Hu矩實現(xiàn)輪廓匹配
這篇文章主要介紹了利用C++ OpenCV實現(xiàn)基于Hu矩的輪廓匹配,文中的示例代碼講解詳細,對我們學(xué)習(xí)OpenCV有一定的幫助,感興趣的可以學(xué)習(xí)一下2022-01-01
Java?C++?算法題解leetcode145商品折扣后最終價格單調(diào)棧
這篇文章主要介紹了Java?C++?算法題解leetcode145商品折扣后最終價格單調(diào)棧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-09-09

