一、前言

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单实例程序-->禁止程序多开相关推荐

  1. 创建单实例WPF应用程序的正确方法是什么?

    在.NET(而不是Windows Forms或控制台)下使用C#和WPF,创建只能作为单个实例运行的应用程序的正确方法是什么? 我知道它与某种称为互斥量的神话事物有关,我很少能找到一个烦人的人来阻止并 ...

  2. Qt实现应用程序单实例运行--LocalServer方式

    使Qt应用程序能够单实例运行的典型实现方法是使用共享内存实现.该方法实现简单,代码简洁. 但有一个致命缺陷:共享内存(QSharedMemory)实现的单程序运行,当运行环境是UNIX时,并且程序不幸 ...

  3. QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSharedMemory共享内存实现进程间通讯(IPC)及禁止程序多开     本文地址:h ...

  4. linux下程序如何实现单实例运行

    1.技术原理 无论是windows还是linux下,程序设计者都会遇到一个问题,那就是如何实现程序的单实例运行.比如,Windows自带的播放软件Windows Medea Player只能启动一个实 ...

  5. 创建WPF单实例应用程序

    1.自定义SingletonWindow类(此方法也适合于传统winform程序) using System; using System.Linq; namespace NetWorld { publ ...

  6. WPF学习笔记-单实例应用程序(包装器)

    1.添加引用Microsoft.VisualBasic 2.创建 app类 class App : System.Windows.Application{protected override void ...

  7. (二)Amazon Lightsail 部署LAMP应用程序之部署单片LAMP应用程序

    部署单片LAMP应用程序 简介:通过复制应用程序代码并提供链接PHP前端和本地MySQL数据库的参数,将LAMP对战应用程序部署到先前启动的Lightsail实例中.完成后,Apache/PHP前端和 ...

  8. Qt Quick实现的涂鸦程序

    之前一直以为 Qt Quick 里 Canvas 才可以自绘,后来发觉不是,原来还有好几种方式都可以绘图!可以使用原始的 OpenGL(Qt Quick 使用 OpenGL 渲染),可以构造QSGNo ...

  9. Windows编程与MFC # 4 单文档应用程序(1)

    整理自VC++程序设计课程课件 使用VC++的应用程序向导MFC AppWizard可以开发: Single document(单文档) Multiple document(多文档) Dialog b ...

最新文章

  1. 分享一个 markdown 编辑器 - Mditor
  2. 【对比分析六】JavaScript中GET和POST的区别及使用场景
  3. 面试题目--MPEG4与H.264的区别
  4. UPS故障案例集(一)
  5. linux查看docker使用率,Linux系统非Docker环境如何限制CPU使用率
  6. @SpringBootApplication揭秘
  7. php mysql 模型_ThinkPHP数据库与模型
  8. JAVA动漫论坛BBS系统的设计与实现
  9. Jimmy Nilsson-应用领域驱动设计和企业应用架构模式-UMLChina讲座-音频和幻灯
  10. RGB色彩模式下的色值与整数之间的互转方法
  11. 如何给PDF文件进行加密?
  12. 小学计算机社团活动总结,小学科技社团活动总结
  13. 挑战程序设计竞赛(第2版)pdf
  14. 现实中的项目范围变更
  15. hinet邮箱密码可以破解?
  16. Second season twentieth episode,poor Phoebe
  17. PC端网页特效 | 常见网页特效案例
  18. nginx如何查看版本号和编译参数
  19. .net mvc 网站 css 和 js 文件加载不出来的问题
  20. Lawliet|Python学习笔记1——基础

热门文章

  1. 市医院深入开展出院随访工作案例
  2. 使用python制作MODBUS RTU主站调试工具(二)—— modbus_tk配置
  3. 电子科大格院18级电子信息导论调研报告-关于朝阳食堂食物浪费现象调查研究报告
  4. 计算机基础知识教材分析,计算机教学计划
  5. w7计算机找不到桌面选项,Win7系统右键计算机属性不见了怎么办?
  6. 基于SSM的水果商城
  7. 码农深夜骑车逆行被拦后爆发大哭,称压力好大!...
  8. 借助MediaSource和SourceBuffer来实现webm格式视频的分片传输
  9. npm安装报错 rollbackFailedOptional verb npm-session 解决办法
  10. 教学记事:用提问的方式解疑