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

