1 需求背景
还是原来的网络关机助手项目“PowerControl”,目前他有了一个新的运行环境,就是在我们的某个带有电脑的显示设备上面,可以理解为带有触摸功能的一体机,本来原生设计是无法触发这个需求的,但是由于信号的干扰没有很好的解决,导致整个屏幕下沉,屏幕的四周没法触摸,这就导致了Windows无法关机,也无法打开系统托盘。所以,关机就需要使用我的关机助手的界面来关机。
但是我的程序图标点击默认是启动程序,而我的程序有没有限制,而且默认还是最小化的,点再多也没有用,指示多开 了一堆程序而已。
所以本次需要增加以下功能
程序启动只能有一个进程,不能多开
双击桌面图标,如果程序启动,则显示程序,如果没有,则创建程序。
2 解决方案
要实现上面的功能,我先想到的就是寻找进程,程序启动的时候看看有没有这个的东西,但是呢,有没有搞过,这都21世纪了,百度一下,发现一个有很多种方法大致有一下几种
参考链接,这里只做搬运 https://blog.csdn.net/robertkun/article/details/8518576#
2.1共享内存
据说这种方法在Linux系统下会有一个内存释放的问题,在某种情况下会引起程序的异常或崩溃
核心代码如下
// 确保只运行一次 QSystemSemaphore sema("JAMKey",1,QSystemSemaphore::Open); sema.acquire();// 在临界区操作共享内存 SharedMemory QSharedMemory mem("SystemObject");// 全局对象名 if (!mem.create(1))// 如果全局对象以存在则退出 { QMessageBox::information(0, MESSAGEBOXTXT,"An instance has already been running."); sema.release();// 如果是 Unix 系统,会自动释放。 return 0; } sema.release();// 临界区
2.2使用QLocalServer和QLocalSocker
这种也是我使用的版本,参考链接找不到,不过代码都是找搬过来的,连接:https://blog.csdn.net/sunflover454/article/details/50426639
头文件代码
#ifndef SINGLEAPPLICATION_H #define SINGLEAPPLICATION_H #include <QApplication> #include <QObject> class QWidget; class QLocalServer; class SingleApplication : public QApplication { Q_OBJECT public: SingleApplication(int &argc,char **argv); bool isRuning(); QWidget *mainWindow; private slots: void newLocalConnectioin(); private: void initLocalConnection(); void newLocalServer(); bool bRunning; QLocalServer *localServer; QString 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(nullptr),mainWindow(nullptr) { serverName = QFileInfo(QCoreApplication::applicationFilePath()).fileName(); initLocalConnection(); } bool SingleApplication::isRuning() { return bRunning; } void SingleApplication::newLocalConnectioin() { 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(); } } 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(); else stream << QString(); stream.flush(); socket.waitForBytesWritten(); return; } newLocalServer(); } void SingleApplication::newLocalServer() { localServer = new QLocalServer(this); connect(localServer,SIGNAL(newConnection()),this,SLOT(newLocalConnectioin())); if(!localServer->listen(serverName)) { if(localServer->serverError() == QAbstractSocket::AddressInUseError) { QLocalServer::removeServer(serverName); localServer->listen(serverName); } } }
main 调用
#include "mainwindow.h" #include <QApplication> #include <singleapplication.h> void autoStart() { QString appName = QApplication::applicationName(); QString appPath = QApplication::applicationFilePath(); appPath = appPath.replace("/","\\"); QSettings *reg=new QSettings("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run",QSettings::NativeFormat); QString val = reg->value(appName).toString(); if(val != appPath) reg->setValue(appName,appPath); reg->deleteLater(); } //int main(int argc, char *argv[]) //{ // QApplication a(argc, argv); // autoStart(); // MainWindow w; w.show(); // return a.exec(); //} int main(int argc, char *argv[]) { SingleApplication a(argc, argv); if(!a.isRuning()) { autoStart(); MainWindow w; a.mainWindow = &w; // w.show(); return a.exec(); } return 0; }
2.3使用官方的QSignalApplication
官方类,但是默认不在Qt中,需要自己下载安装:参考链接https://blog.csdn.net/bloke_come/article/details/106319236