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原理的定制類:
#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ù)名稱
};
#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++中typedef 和 #define 的區(qū)別
這篇文章主要介紹了C++中typedef 與 #define 的區(qū)別,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Cocos2d-x UI開(kāi)發(fā)之CCControlSlider控件類使用實(shí)例
這篇文章主要介紹了Cocos2d-x UI開(kāi)發(fā)之CCControlSlider控件類使用實(shí)例,本文代碼中包含大量注釋講解了CCControlSlider控件類的使用,需要的朋友可以參考下2014-09-09
C語(yǔ)言實(shí)現(xiàn)隨機(jī)生成6位數(shù)密碼
這篇文章主要為大家詳細(xì)介紹了如何使用C語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單而實(shí)用的隨機(jī)密碼生成器,該生成器將生成包含字母、數(shù)字和特殊字符的隨機(jī)密碼,有需要的小伙伴可以參考下2023-11-11
C語(yǔ)言中魔性的float浮點(diǎn)數(shù)精度問(wèn)題
這篇文章主要介紹了魔性的float浮點(diǎn)數(shù)精度問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01
C++ 哈夫曼樹(shù)對(duì)文件壓縮、加密實(shí)現(xiàn)代碼
這篇文章主要介紹了C++ 哈夫曼樹(shù)對(duì)文件壓縮、加密實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08
C/C++使用C語(yǔ)言實(shí)現(xiàn)多態(tài)
這篇文章主要介紹了C/C++多態(tài)的實(shí)現(xiàn)機(jī)制理解的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下,希望能給你帶來(lái)幫助2021-08-08
C++實(shí)現(xiàn)LeetCode(75.顏色排序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(75.顏色排序),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++實(shí)現(xiàn)LeetCode(190.顛倒二進(jìn)制位)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(190.顛倒二進(jìn)制位),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

