NSIS + QT 做安裝卸載程序

NSIS + QT 做安裝卸載程序。
NSIS僅僅用於把所有的東西封裝爲一個EXE。


NSIS打包
QT做有逼格的可視化界面,並且方便實現。



以下是nSIS源碼:


icon ".\xxx.ico" #設置圖標
OutFile "setup.exe" #設置生成程序
SilentInstall silent #靜默安裝不出現任何NSIS自帶界面


Function .onInit #NSIS程序安裝準備工作
InitPluginsDir #創建臨時目錄(內存)用於保存一些必要的庫
SetOutPath $PLUGINSDIR #將文件保存在臨時目錄中
  File "Qt5Gui.dll" #我的安裝界面必要的庫
  File "Qt5Core.dll"
  File "Qt5Widgets.dll"
  File "Qt5Widgets.dll"
  File "qt.conf"
  File /r "plugins\"
  File "UnRAR.exe"
  File "xxx.rar" #rar.exe生成的必要的庫和文件。
  File "xxx.exe"
FunctionEnd


Function .onInstSuccess #安裝成功後調用
call fun
Functionend


Function fun
   ExecWait $PLUGINSDIR\class8_setup.exe #調用QT安裝程序,等待其運行完後運行下一條語句
   RMDir $PLUGINSDIR                #釋放臨時目錄(內存)
FunctionEnd


section
sectionend




出現圖標不顯示的問題的時候:
在開始裏運行tskill ex*




QT做安裝程序:
1.必要庫的解壓。
2.進度條
3.寫註冊表或配置文件。


這裏直接調用第三方的UnRAR.exe程序。QT開一個進程調用它,並且綁定它的標準輸出內容到主程序槽,用於設置進度條。
當該程序結束時會返回一個結束信號。


附:
rar unrar命令
rar -help
unrar -help

可以看到詳細內容



按照上文的方法,即寫兩個EXE程序。一個發佈的程序,一個是安裝程序,安裝程序用於解壓發佈的程序的壓縮包。


以下是QT源碼:

#ifndef ENV
#define ENV

#include <QDir>
#include <QString>
#include <QStringList>
#include <QDebug>

#include <windows.h>
#include "psapi.h"
#include "stdio.h"
#include <tlhelp32.h>
#include <QStandardPaths>

#include <QByteArray>
#include <QFile>
#include <QCryptographicHash>

namespace ENV{

//define

//創建文件夾
static inline void createFolder(const QString &folderPath);
//查找當前是否有該進程運行
static inline bool findProcess(const QString &proName);
//創建桌面快捷方式
static inline bool createShortCutToDeskTop(const QString &file);
//創建開始菜單快捷方式
static inline bool createShortCutToStartMenue(const QString &file);
//得到文件md5
static inline QByteArray getFileMd5(QFile &file);
static inline QByteArray getFileMd5(const QString &filePath);
//對比文件md5
static inline bool cmpFileMd5(QFile &lhs,QFile &rhs);
static inline bool cmpFileMd5(const QString &lhs,const QString &rhs);



//implementation
void createFolder(const QString &folderPath){
    QDir dir;
    bool exist = dir.exists(folderPath);
    if(!exist){
        QStringList list = folderPath.split('/');
        QString filePath = "";
        int len = 0;
        if(QString(list.at(list.length()-1)).contains('.'))
            len = list.length()-1;
        else
            len = list.length();
        for(int i = 0;i < len;++i){
            filePath = filePath + list[i] + '/';
            exist = dir.exists(filePath);
            if(!exist)
                dir.mkdir(filePath);
        }
    }
}

static inline bool findProcess(const QString &proName)
{
    int count = 0;
    PROCESSENTRY32 pe32;
    pe32.dwSize = sizeof(pe32);
    HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    if(hProcessSnap == INVALID_HANDLE_VALUE)
    {
        count += 0;
    }
    BOOL bMore = ::Process32First(hProcessSnap, &pe32);
    while(bMore)
    {
        if(proName == QString::fromWCharArray(pe32.szExeFile)){
            ++count;
        }
        bMore = ::Process32Next(hProcessSnap, &pe32);
    }
    if(count == 1){
        return true;
    }else if(count > 1){
        return false;
    }
}


bool createShortCutToDeskTop(const QString &file){
    QString deskTopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    QStringList temp = file.split(":/");
    QStringList temp1 = temp[temp.size()-1].split('.');
    return QFile::link(file,deskTopPath+"/"+temp1[0]+".lnk");
}

bool createShortCutToStartMenue(const QString &file){
    QString startMenuePath = "C:/ProgramData/Microsoft/Windows/Start Menu/Programs";
    QStringList temp = file.split(":/");
    QStringList temp1 = temp[temp.size()-1].split('.');
    return QFile::link(file,startMenuePath+"/"+temp1[0]+".lnk");
}


QByteArray getFileMd5(QFile &file)
{
    if(!file.exists())
        return "";
    file.open(QIODevice::ReadOnly);
    QByteArray result = QCryptographicHash::hash(file.readAll(),QCryptographicHash::Md5);
    file.close();
    return result;
}

QByteArray getFileMd5(const QString &filePath){
    return getFileMd5(QFile(filePath));
}

bool cmpFileMd5(QFile &lhs,QFile &rhs)
{
    if(!lhs.exists() || !rhs.exists())
        return false;
    return (getFileMd5(lhs) == getFileMd5(rhs));
}

bool cmpFileMd5(const QString &lhs,const QString &rhs){
    return cmpFileMd5(QFile(lhs),QFile(rhs));
}

}


#endif // ENV



#ifndef SETUP_H
#define SETUP_H

#include <qdebug.h>

#include <QString>

class SetUp{
public:
    explicit SetUp();
    ~SetUp();

    void setConfigPath(const QString &configPath);
    void setFilesPath(const QString *filesPaths,unsigned int num);
    void setRegeditData(const QString &itemPath);

    bool moveFile(const QString &filePath)const;
    void moveFile()const;

    bool createShortCut()const;
    bool createMenueShortCut()const;

    bool checkMutex()const;
private:

    QString m_cfgPath;
    QString *m_filesPaths;
    unsigned int m_num;

private:
    SetUp& operator =(const SetUp &){return *this;}
    SetUp(const SetUp&){}
};

#endif // SETUP_H


#include "setup.h"
#include "configfile.h"
#include "registryfile.h"
#include <QFile>
#include <QStandardPaths>

#include "env.h"

SetUp::SetUp():m_filesPaths(NULL),m_cfgPath(""),m_num(0)
{

}

SetUp::~SetUp()
{
    if(m_filesPaths)
    {
        delete []m_filesPaths;
        m_filesPaths = NULL;
    }
}

void SetUp::setConfigPath(const QString &configPath)
{
    m_cfgPath = configPath;
}

void SetUp::setFilesPath(const QString *filesPaths,unsigned int num)
{
    if(NULL == filesPaths)
        return;
    m_num = num;
    m_filesPaths = new QString[m_num];
    for(unsigned int i = 0;i < m_num;++i)
    {
        this->m_filesPaths[i] = filesPaths[i];
    }
}

bool SetUp::moveFile(const QString &filePath)const
{
    if(!QFile::exists(filePath))
        return false;
    QStringList temp = filePath.split(":/");
    ENV::createFolder(m_cfgPath+'/'+temp[temp.size()-1]);
    bool flag = QFile::copy(filePath,m_cfgPath+'/'+temp[temp.size()-1]);

    if(flag){
        return true;
    }
    return false;
}

void SetUp::moveFile()const
{
    for(unsigned int i = 0;i < m_num;++i)
        moveFile(m_filesPaths[i]);
}

bool SetUp::createShortCut()const{
    QString deskTopPath = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    QStringList temp = m_filesPaths[m_num-1].split(":/");
    return QFile::link(m_cfgPath+'/'+temp[temp.size()-1],deskTopPath+"/"+"jojojojo.lnk");
}

bool SetUp::createMenueShortCut()const
{
    return true;
}

void SetUp::setRegeditData(const QString &itemPath)
{
    ConfigFile *configFile = new RegistryFile(itemPath);
    if(configFile->init())
        configFile->setValue("cfgPath",m_cfgPath);
    delete configFile;
}


bool SetUp::checkMutex()const
{
    return ENV::findProcess("setup_ui.exe");
}

#ifndef CONFIGFILE_H
#define CONFIGFILE_H

#include <QString>
#include <QMap>
#include <QSettings>

class ConfigFile
{
public:
    explicit ConfigFile();
    virtual ~ConfigFile();

    virtual bool init() = 0;

    virtual bool setValue(const QString &valueName,const QVariant &defaultValue) = 0;
    virtual bool getValue(const QString &valueName,QVariant &outValue)const = 0;
    virtual bool getAllValue(QMap<QString,QVariant> &outValues)const = 0;

    virtual bool createItem(const QString &ItemPath) = 0;

protected:
    QSettings *m_settings;
    QString m_filePath;
    bool m_exists;
};

#endif // CONFIGFILE_H


#include "configfile.h"

ConfigFile::ConfigFile()
    :m_settings(NULL),m_filePath(""),m_exists(false)
{

}

ConfigFile::~ConfigFile()
{
    if(m_settings)
    {
        delete m_settings;
        m_settings = NULL;
    }
}


#ifndef INIFILE_H
#define INIFILE_H

#include <configfile.h>

class IniFile : public ConfigFile
{
public:
    explicit IniFile(const QString &filePath = "");
    ~IniFile();

    bool init();

    bool setValue(const QString &valueName,const QVariant &defaultValue);
    bool getValue(const QString &valueName,QVariant &outValue)const;
    bool getAllValue(QMap<QString,QVariant> &outValues)const;

    bool createItem(const QString &ItemPath);

private:
    IniFile(const IniFile&){}
    IniFile& operator=(const IniFile&){return *this;}
};

#endif // INIFILE_H


#include "inifile.h"
#include <QFile>

IniFile::IniFile(const QString &filePath)
    :ConfigFile()
{
    this->m_filePath = filePath;
}

IniFile::~IniFile()
{

}

bool IniFile::init()
{
    if(QFile::exists(m_filePath))
        m_exists = true;
    else
        return false;
    m_settings = new QSettings(m_filePath, QSettings::IniFormat);
    return true;
}

bool IniFile::setValue(const QString &valueName,const QVariant &defaultValue = QVariant())
{
    if(!m_exists)
        return false;
    m_settings->setValue(valueName,defaultValue);
    return true;
}

bool IniFile::getAllValue(QMap<QString,QVariant> &outValues)const
{
    if(!m_exists)
        return false;
    foreach(QString str,m_settings->childKeys())
    {
        outValues.insert(str,m_settings->value(str));
    }
    return true;
}

bool IniFile::getValue(const QString &valueName,QVariant &outValue)const
{
    if(!m_exists)
        return false;
    foreach(QString str,m_settings->childKeys())
    {
        if(valueName == str)
        {
            outValue = m_settings->value(str);
            return true;
        }
    }
    return false;
}

bool IniFile::createItem(const QString &ItemPath){
    QFile file(ItemPath);
    if(file.exists())
        return false;
    file.open(QIODevice::WriteOnly);
    file.close();
    this->m_filePath = ItemPath;
    return true;
}


#ifndef REGISTRYFILE_H
#define REGISTRYFILE_H

#include <configfile.h>

class RegistryFile : public ConfigFile
{
public:
    explicit RegistryFile(const QString &filePath);
    ~RegistryFile();

    bool init();

    bool setValue(const QString &valueName,const QVariant &defaultValue);
    bool getValue(const QString &valueName,QVariant &outValue)const;
    bool getAllValue(QMap<QString,QVariant> &outValues)const;

    bool createItem(const QString &ItemPath);

private:
    RegistryFile(const RegistryFile&){}
    RegistryFile& operator=(const RegistryFile&){return *this;}
};

#endif // REGISTRYFILE_H



#include "registryfile.h"
#include <QFile>
RegistryFile::RegistryFile(const QString &filePath)
    :ConfigFile()
{
    this->m_filePath = filePath;
}

RegistryFile::~RegistryFile(){

}

bool RegistryFile::init()
{
    m_settings = new QSettings(m_filePath, QSettings::NativeFormat);
    return true;
}

bool RegistryFile::setValue(const QString &valueName,const QVariant &defaultValue = QVariant())
{
    m_settings->setValue(valueName,defaultValue);
    return true;
}

bool RegistryFile::getAllValue(QMap<QString,QVariant> &outValues)const
{
    foreach(QString str,m_settings->childKeys())
    {
        outValues.insert(str,m_settings->value(str));
    }
    return true;
}

bool RegistryFile::getValue(const QString &valueName,QVariant &outValue)const
{
    foreach(QString str,m_settings->childKeys())
    {
        if(str == valueName)
        {
            outValue = m_settings->value(str);
            return true;
        }
    }
    return false;
}

bool RegistryFile::createItem(const QString &ItemPath){
    QSettings *tempSetting = new QSettings(ItemPath,QSettings::NativeFormat);
    delete tempSetting;
    return true;
}

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>

class QMovie;
class QProcess;
class SetUp;

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private slots:
    void on_pushButton_clicked();
    void uncompressFinished();
    void uncompressSuccess();

private:
    Ui::Dialog *ui;
    QMovie *m_movie;
    QProcess *m_pro;
    SetUp *m_setUp;
    bool m_isOver;
    int count;
};

#endif // DIALOG_H




#include "dialog.h"
#include "ui_dialog.h"

#include <QStandardPaths>
#include <QProcess>
#include <QMovie>
#include "setup.h"
#include "env.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),count(0),m_setUp(NULL),
    ui(new Ui::Dialog),m_isOver(false)
{
    ui->setupUi(this);
    m_movie=new QMovie(":/background.gif");
    ui->progressBar->setMaximum(465);
    ui->progressBar->setValue(0);
    ui->gif->setMovie(m_movie);
    this->setWindowIcon(QIcon(":/class8big.ico"));
    m_movie->start();
    m_pro = new QProcess;
    connect(m_pro,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(uncompressFinished()));
    connect(m_pro,SIGNAL(readyReadStandardOutput()),this,SLOT(uncompressSuccess()));
    m_setUp = new SetUp;
}

Dialog::~Dialog()
{
    delete ui;
    delete m_setUp;
}

void Dialog::uncompressFinished(){
    qDebug()<<"install success!";
    ui->progressBar->setValue(ui->progressBar->maximum());
    ui->pushButton->setText("安裝成功");
    m_isOver = true;
    delete m_pro;
}

void Dialog::uncompressSuccess(){
    qDebug()<<++count;
    ui->progressBar->setValue(count);
}

void Dialog::on_pushButton_clicked()
{
    if(!m_isOver){
     if(m_setUp->checkMutex()){
         qDebug()<<"mutex"<<endl;
     }
     QString configPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
     QString itemPath = "HKEY_CURRENT_USER\\Software\\calss8";

     QStringList list = configPath.split('/');
     QString setupPath = "";
     for(int i = 0;i < list.size()-1;++i)
         setupPath += list[i] + '/';
     setupPath += "Class9";
     QString runPath = QCoreApplication::applicationDirPath();
     ENV::createFolder(setupPath);
     m_setUp->setConfigPath(setupPath);
     m_setUp->setRegeditData(itemPath);

     QString cmd = runPath + '/' + "unrar" + " x -y " + runPath+"/class8.rar "+setupPath;
     qDebug()<<cmd;
     m_pro->start(cmd);
    }
    else
        this->close();
}


<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>363</width>
    <height>283</height>
   </rect>
  </property>
  <property name="sizePolicy">
   <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
    <horstretch>0</horstretch>
    <verstretch>0</verstretch>
   </sizepolicy>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <layout class="QHBoxLayout" name="horizontalLayout_2">
   <item>
    <layout class="QVBoxLayout" name="verticalLayout">
     <item>
      <widget class="QLabel" name="gif">
       <property name="text">
        <string>TextLabel</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QProgressBar" name="progressBar">
       <property name="value">
        <number>24</number>
       </property>
      </widget>
     </item>
     <item>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
        <spacer name="horizontalSpacer">
         <property name="orientation">
          <enum>Qt::Horizontal</enum>
         </property>
         <property name="sizeHint" stdset="0">
          <size>
           <width>40</width>
           <height>25</height>
          </size>
         </property>
        </spacer>
       </item>
       <item>
        <widget class="QPushButton" name="pushButton">
         <property name="sizePolicy">
          <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
           <horstretch>0</horstretch>
           <verstretch>0</verstretch>
          </sizepolicy>
         </property>
         <property name="minimumSize">
          <size>
           <width>60</width>
           <height>25</height>
          </size>
         </property>
         <property name="maximumSize">
          <size>
           <width>60</width>
           <height>25</height>
          </size>
         </property>
         <property name="text">
          <string>開始安裝</string>
         </property>
        </widget>
       </item>
      </layout>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章