QT笔记:同类型程序只能运行一个

由于NSIS实现自定义界面,以及把安装包和升级包合并太过复杂,在各种尝试失败之后决定自己写安装包和卸载包。

原本项目中已经有一个让程序只运行一次的代码,使用QSystemSemaphore和QSharedMemory实现的。

    QSystemSemaphore sema("Key",1,QSystemSemaphore::Open);
    sema.acquire();//在临界区操作共享内存 SharedMemory
    QSharedMemory mem("Object");//全局对象名
    if (!mem.create(1))//如果全局对象以存在则退出
    {
        NDialog dialog(QApplication::focusWidget());
        NMessageBox Msg(&dialog,NMessageBox::ErrMsg,QObject::tr("软件运行中,再次打开前请先关闭。"));//获取最后一条错误信息
        dialog.setWidget(&Msg,QObject::tr("软件打开错误"));
        dialog.exec();
        sema.release();
        return 0;
    }
    sema.release();

 

但后来发现,这段代码只支持同时运行两个程序,当第三个程序运行时,只会在后台出现,不会有任何界面提示,即使把前两个程序关闭也不行。直到打开任务管理器,把所有程序全部结束掉,再打开才能正常使用。

这种场景在日常使用并不常见,但是如果加入安装/卸载程序,三种程序都用这种方式,出现的概率就大很多,于是引入QtSingleApplication。

由于使用pri文件方式在修改代码时出现了问题(也可能是配置问题),实在懒得深究了,就直接把代码添加到目录里面了。

  1. 下载qtsingleapplication压缩包,并解压。
  2. 在项目文件夹中新建两个文件夹qtlockedfile和qtsingleapplication
  3. 将qtsinglecoreapplication.cpp/.h、qtsingleapplication.cpp/.h、qtlocalpeer.cpp/.h 共6个文件,放到qtsingleapplication文件夹
  4. 将qtlockedfile.cpp/.h、qtlockedfile_win.cpp、qtlockedfile_unix.cpp 共4个文件,放到qtlockedfile文件夹
  5. 将上面的qtsingleapplication文件夹中所有文件,以及qtlockedfile文件夹中的qtlockedfile.cpp/.h文件,共8个文件全部添加到项目中
  6. 在.pro文件中添加
    win32 {
    SOURCES += qtlockedfile/qtlockedfile_win.cpp
    }
    unix {
    SOURCES +=qtlockedfile/qtlockedfile_unix.cpp
    }

     

  7. 在代码的main.cpp中,将原来的
    #include <QApplication>
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        NUninstallDialog w;
        w.show();
        return a.exec();
    }

    改为

    #include "qtsingleapplication/qtsingleapplication.h"
    int main(int argc, char *argv[])
    {
        QtSingleApplication a(QLatin1String("UninstallId"),argc, argv);
        if(a.isRunning())
        {
            NMessageDialog dialog(QApplication::focusWidget());
            dialog.setText(false,QObject::tr("有相同Uninstall卸载程序正在运行,再次打开前请先关闭。"));
            dialog.exec();
            return 1;
        }
        NUninstallDialog w;
        w.show();
        return a.exec();
    }

    这样修改后,打开多少个程序,就会出现多少提示框,不会有程序在后台不出现的情况了。

  8. 不知道是不是我下载的版本问题,还是哪里配置不对,编译后会有几个问题。看了一下代码,一个是因为命名空间的关系,根据提示在qtlockedfile.cpp和qtlockedfile_win.cpp开头加入using namespace QtLP_Private;。另一个是因为分了两个文件夹后的路径问题,在qtlocalpeer.cpp中,将#include "qtlockedfile.cpp"和#include "qtlockedfile_win.cpp"改为#include "../qtlockedfile/qtlockedfile.h"和#include "../qtlockedfile/qtlockedfile_win.cpp"(有需要也可以将_unix的也改一下)。

如果仅仅是解决打开多个程序,以上代码就能满足要求。但由于项目是需要同时检测安装包、卸载包、执行文件的,除了它们自己本身需要只允许一次以外,还需要这三个程序只能运行其中一个。

由于QtSingleApplication是继承QApplication的,而QT程序只允许有一个QApplication类。因此需要在QtSingleApplication中添加一个独立查询AppId的函数。

  1. 在QtSingleApplication中添加公有成员函数
    //QtSingleApplication.h
    bool isAppIdRuning(const QString &appId);
    //QtSingleApplication.cpp
    bool QtSingleApplication::isAppIdRuning(const QString &appId)
    {
        QtLocalPeer lpeer(this, appId);
        return lpeer.isClient();
    }

     

  2. 将main.cpp改为
    int main(int argc, char *argv[])
    {
        QtSingleApplication a(QLatin1String("UninstallId"),argc, argv);
        
        if(a.isRunning())
        {
            NMessageDialog dialog(QApplication::focusWidget());
            dialog.setText(false,QObject::tr("有相同Uninstall卸载程序正在运行,再次打开前请先关闭。"));
            dialog.exec();
            return 1;
        }
    
        if(a.isAppIdRuning("SetupId"))
        {
            NMessageDialog dialog(QApplication::focusWidget());
            dialog.setText(false,QObject::tr("Setup.exe安装程序正在运行,请关闭后再打开本卸载程序。"));
            dialog.exec();
            return 1;
        }
    
        if(a.isAppIdRuning("xxxId"))
        {
            NMessageDialog dialog(QApplication::focusWidget());
            dialog.setText(true,QObject::tr("xxx.exe运行中,是否强行关闭?"));
            if(dialog.exec() != QDialog::Accepted)
            {
                return 1;
            }
        }
    
        NUninstallDialog w;
        w.show();
        return a.exec();
    }

     

  3. 为了保证界面效果,语言翻译和皮肤的加载,要放到if(a.isRunning())前哦!

做安装包和卸载包其实还有几个问题没有攻克,只是这个刚好做起来有点麻烦,所以记录一下。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值