Qt单实例程序-->禁止程序多开
一、前言
Qt编写的程序,默认是可以多开的,但是有些时候,我们不希望程序可以同时打开多个,这时候就需要对程序的启动添加限制策略,阻止程序多开。
二、常用的三种方法
1、使用共享内存
原理:运行主函数前线访问固定的共享内存段,看看有没有被使用。
- 如果没有使用该内存段,就继续运行程序;
- 如果使用了该内存段,就报警并退出;
使用:
- 修改前
#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)) //创建1byte的共享内存段{Widget w;w.show();return a.exec();}return 0;
}
2、使用QLocalServe
原理:创建一个本地服务器,并在程序启动的时候去连接服务器。
- 如果连接上了,则说明已有实例程序存在,退出;
- 如果连接不上,则说明没有创建服务器,创建一个服务器,并正常运行程序。
使用:
//连接LocalServerQString serverName = "localserver";QLocalSocket socket;socket.connectToServer(serverName);if(socket.waitForConnected(1000)) return(-1);// 如果连接成功,说明已经存在指定的LocalServer,说明已经有应用启动了,此时直接退出应用即可
// 如果没有指定的LocalServer存在,则connectToServer会返回错误信息,此时创建LocalServer//创建LocalServerQLocalServer server;if (server.listen(serverName)) {// 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之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:// 有新连接时触发void newLocalConnection();private:// 初始化本地连接void initLocalConnection();// 创建服务端void newLocalServer();bool bRunning; // 是否已经有实例在运行QLocalServer *localServer; // 本地socket ServerQString 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通讯实现程序单实例运行,监听到新的连接时触发该函数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,则创建,否则退出void SingleApplication::initLocalConnection()
{bRunning = false;QLocalSocket socket;socket.connectToServer(serverName);if(socket.waitForConnected(500)){bRunning = true;// 其他处理,如:将启动参数发送到服务端QTextStream stream(&socket);QStringList args = QCoreApplication::arguments();if (args.count() > 1)stream << args.last();elsestream << QString();stream.flush();socket.waitForBytesWritten();return;}//连接不上服务器,就创建一个newLocalServer();
}// 说明:
// 创建LocalServervoid SingleApplication::newLocalServer()
{localServer = new QLocalServer(this);connect(localServer, SIGNAL(newConnection()), this, SLOT(newLocalConnection()));if(!localServer->listen(serverName)){// 此时监听失败,可能是程序崩溃时,残留进程服务导致的,移除之if(localServer->serverError() == QAbstractSocket::AddressInUseError){QLocalServer::removeServer(serverName); // <-- 重点localServer->listen(serverName); // 再次监听}}
}
#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()
{ // 创建互斥量 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单实例程序-->禁止程序多开相关推荐
- 创建单实例WPF应用程序的正确方法是什么?
在.NET(而不是Windows Forms或控制台)下使用C#和WPF,创建只能作为单个实例运行的应用程序的正确方法是什么? 我知道它与某种称为互斥量的神话事物有关,我很少能找到一个烦人的人来阻止并 ...
- Qt实现应用程序单实例运行--LocalServer方式
使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现.该方法实现简单,代码简洁. 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸 ...
- QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开 本文地址:h ...
- linux下程序如何实现单实例运行
1.技术原理 无论是windows还是linux下,程序设计者都会遇到一个问题,那就是如何实现程序的单实例运行.比如,Windows自带的播放软件Windows Medea Player只能启动一个实 ...
- 创建WPF单实例应用程序
1.自定义SingletonWindow类(此方法也适合于传统winform程序) using System; using System.Linq; namespace NetWorld { publ ...
- WPF学习笔记-单实例应用程序(包装器)
1.添加引用Microsoft.VisualBasic 2.创建 app类 class App : System.Windows.Application{protected override void ...
- (二)Amazon Lightsail 部署LAMP应用程序之部署单片LAMP应用程序
部署单片LAMP应用程序 简介:通过复制应用程序代码并提供链接PHP前端和本地MySQL数据库的参数,将LAMP对战应用程序部署到先前启动的Lightsail实例中.完成后,Apache/PHP前端和 ...
- Qt Quick实现的涂鸦程序
之前一直以为 Qt Quick 里 Canvas 才可以自绘,后来发觉不是,原来还有好几种方式都可以绘图!可以使用原始的 OpenGL(Qt Quick 使用 OpenGL 渲染),可以构造QSGNo ...
- Windows编程与MFC # 4 单文档应用程序(1)
整理自VC++程序设计课程课件 使用VC++的应用程序向导MFC AppWizard可以开发: Single document(单文档) Multiple document(多文档) Dialog b ...
最新文章
- 分享一个 markdown 编辑器 - Mditor
- 【对比分析六】JavaScript中GET和POST的区别及使用场景
- 面试题目--MPEG4与H.264的区别
- UPS故障案例集(一)
- linux查看docker使用率,Linux系统非Docker环境如何限制CPU使用率
- @SpringBootApplication揭秘
- php mysql 模型_ThinkPHP数据库与模型
- JAVA动漫论坛BBS系统的设计与实现
- Jimmy Nilsson-应用领域驱动设计和企业应用架构模式-UMLChina讲座-音频和幻灯
- RGB色彩模式下的色值与整数之间的互转方法
- 如何给PDF文件进行加密?
- 小学计算机社团活动总结,小学科技社团活动总结
- 挑战程序设计竞赛(第2版)pdf
- 现实中的项目范围变更
- hinet邮箱密码可以破解?
- Second season twentieth episode,poor Phoebe
- PC端网页特效 | 常见网页特效案例
- nginx如何查看版本号和编译参数
- .net mvc 网站 css 和 js 文件加载不出来的问题
- Lawliet|Python学习笔记1——基础
热门文章
- 市医院深入开展出院随访工作案例
- 使用python制作MODBUS RTU主站调试工具(二)—— modbus_tk配置
- 电子科大格院18级电子信息导论调研报告-关于朝阳食堂食物浪费现象调查研究报告
- 计算机基础知识教材分析,计算机教学计划
- w7计算机找不到桌面选项,Win7系统右键计算机属性不见了怎么办?
- 基于SSM的水果商城
- 码农深夜骑车逆行被拦后爆发大哭,称压力好大!...
- 借助MediaSource和SourceBuffer来实现webm格式视频的分片传输
- npm安装报错 rollbackFailedOptional verb npm-session 解决办法
- 教学记事:用提问的方式解疑