软件自动更新解决方案及QT实现
from:https://blog.csdn.net/hulinhulin/article/details/46839107
軟件自動(dòng)更新解決放案及QT實(shí)現(xiàn)...1
1 文件的版本控制-XML.2
2 更新程序的實(shí)現(xiàn)...2
2.1 界面設(shè)置...2
2.2 程序功能...3
2.2.1 下載網(wǎng)絡(luò)數(shù)據(jù)...3
2.2.2 XML文件的分析...6
2.2.3 下載XML文件的DownLoadXML函數(shù)...8
2.2.4 返回指定XML文件中的name版本號(hào)...8
2.2.5 返回指定XML文件中的name版本號(hào)...10
2.2.6 比較兩個(gè)XML文件CheckUpdateFiles.11
2.2.7 下載文件DownLoadUpdateFiles.13
2.2.7 退出當(dāng)前程序,并啟動(dòng)指定的程序...16
3 更新程序的啟動(dòng)...16
3.1 從主程序啟動(dòng)更新程序...16
3.2 主程序的關(guān)閉...17
3.3 更新程序關(guān)閉時(shí)啟動(dòng)主程序...17
4 程序調(diào)試...17
軟件自動(dòng)更新解決放案及QT實(shí)現(xiàn)
需要考慮解決的問題:
1)?需要知道哪些文件需要更新,哪些不需要;
2)?從哪里下載更新文件;
3)?將舊的文件用新的文件替換掉(包含版本控制文件);
4)?更新完畢后重新啟動(dòng)主程序;
?
第一個(gè)問題,可以為程序所使用的文件都設(shè)定一個(gè)版本號(hào),版本號(hào)都記錄在一個(gè) XML 文件中,升級(jí)時(shí),檢查最新程序的版本控制文件和當(dāng)前的版本控制文件,最新版本號(hào)較大時(shí),表示該文件需要更新。如果一個(gè)文件不再需要了,則將該文件的版本信息從最新的版本控制文件中刪除,通過對(duì)比控制文件,就知道該文件不再需要了,可以將之刪除;
第二個(gè)問題,最新的版本控制文件需要放在一個(gè)可供方便下載的地方,例如FTP或者一個(gè)固定的IP;
第三個(gè)問題,通過對(duì)比新的版本控制文件和舊的版本控制文件來確定哪些需要替換或者刪除;
第四個(gè)問題,更新程序運(yùn)行完后,啟動(dòng)主程序即可,需要一個(gè)標(biāo)識(shí)來說明是否更新完成;
?
按照以上的思路,下面對(duì)每一個(gè)步驟結(jié)合程序進(jìn)行詳細(xì)地闡述,軟件使用QT5.1實(shí)現(xiàn)。
?
1?文件的版本控制-XML
下面是使用XML文件來表示的版本控制文件:
<?xml version="1.0"encoding="utf-8"?>?
<filelist>?
?<filename="qico.dll" dir="imageformats"version="1.0"/>
?<filename="qminimal.dll" dir="imageformats"version="1.0"/>
…..
?<file name="main.exe"version="1.0"/>
</filelist>?
Name表示文件的名稱;
dir表示所在的目錄(相對(duì)目錄);
version表示當(dāng)前文件的版本;
2?更新程序的實(shí)現(xiàn)
更新程序使用QT5.1來實(shí)現(xiàn),最終生成一個(gè)可執(zhí)行文件(exe文件)。新建工程時(shí)選擇QT GUI應(yīng)用,其他都默認(rèn),工程名為Updater。
2.1?界面設(shè)置
在構(gòu)造函數(shù)中設(shè)置界面。
應(yīng)用程序在屏幕中間:
QDesktopWidget *deskdop = QApplication::desktop();
this->move((deskdop->width() -this->width())/2, (deskdop->height() - this->height())/2);
?
無標(biāo)題欄:
this->setWindowFlags(Qt::FramelessWindowHint);//沒有標(biāo)題欄
?
隱藏菜單欄和工具欄??
this->ui->menuBar->hide();
this->ui->mainToolBar->hide();
?
固定高和寬:
this->setFixedSize(400,200);
???
設(shè)置背景顏色(兩種方法都可以)
???//this->setStyleSheet("QMainWindow{background:rgb(240,250,250)}");
QPalette pal;
pal.setColor(QPalette::Background,QColor(255,245,225) );
this->setPalette(pal);
this->setAutoFillBackground(true);
2.2?程序功能
??? 程序功能包括從網(wǎng)絡(luò)下載數(shù)據(jù),分析XML文件,比較當(dāng)前的XML及下載的XML文件,并最終確定哪些文件需要更新或者添加
2.2.1?下載網(wǎng)絡(luò)數(shù)據(jù)
新建類CHttpDownLoadFile,類功能:從指定網(wǎng)絡(luò)中下載指定的文件,并且存儲(chǔ)到指定的本地文件目錄中。
主要的成員函數(shù)及槽函數(shù):
public slots:
???void ReplyNewDataArrived();//響應(yīng)m_netReply有新的數(shù)據(jù)到達(dá)
???void ReplyFinished();//響應(yīng)數(shù)據(jù)接收完成
public:
???QNetworkAccessManager *m_netAccessManager;//網(wǎng)絡(luò)參數(shù)
???QNetworkReply *m_netReply;
?
???QUrl m_urlAdress;//網(wǎng)絡(luò)地址
???QString m_strFileName;//需要下載的文件名
???QString m_strDir;//文件的存儲(chǔ)位置
?
???QFile *m_file;//下載的文件
?
??? ???qint64m_nReceived;//下載文件時(shí),已經(jīng)接收的文件大小和總共大小
???qint64m_nTotal;
主要函數(shù)及功能:
a.構(gòu)造函數(shù)
CHttpDownloadFile(QString url,QStringfileName,QString dir,QObject *parent = 0);
url表示文件的網(wǎng)絡(luò)地址;
filename表示文件名;
dir表示文件存儲(chǔ)路徑
??? 如果fileName不為空,那么文件名使用fileName,否則從url提取(注:不需要加后綴)。如果dir不為空,那么將文件存儲(chǔ)到dir指向的文件夾中,否則存儲(chǔ)在默認(rèn)路徑中(即與可執(zhí)行文件在同一個(gè)文件夾中),如果文件夾不存在,那么會(huì)創(chuàng)建,dir舉例:c:/temp/,或者c:/temp,如果前面不加盤符,那么將會(huì)在默認(rèn)文件夾中創(chuàng)建。
b. 開始下載文件的函數(shù):void DownLoadFile()
m_netReply=m_netAccessManager->get(QNetworkRequest(m_urlAdress));
connect(m_netReply,SIGNAL(readyRead()),
this,SLOT( ReplyNewDataArrived()) );//當(dāng)有新數(shù)據(jù)到達(dá)時(shí)就會(huì)觸發(fā)此信號(hào)
connect(m_netReply, SIGNAL(finished()),
this,SLOT( ReplyFinished()) );//完成數(shù)據(jù)接收后發(fā)送此信號(hào)
connect(m_netReply, SIGNAL(error(QNetworkReply::NetworkError)),this, SLOT( ReplyError(QNetworkReply::NetworkError)) );//出現(xiàn)錯(cuò)誤時(shí)發(fā)送此信號(hào);
connect(m_netReply, SIGNAL(downloadProgress(qint64,qint64)), this, SLOT(ReplyDownloadProgress(qint64,qint64) ) );//用來提示文件下載進(jìn)度
?
???/*************存儲(chǔ)文件的檢測(cè)及使用************/
???if( m_strFileName.isEmpty() )//文件名
??? {
???????QFileInfo fileInfo(m_urlAdress.path());
???????m_strFileName = fileInfo.fileName();
??? }
?
???if( !m_strDir.isEmpty() )//文件夾
??? {
???????QDir directory( m_strDir );
?
???????if( !directory.exists() )//沒有此文件夾,則創(chuàng)建
???????{
???????????directory.mkpath( m_strDir );
???????}
?
???????m_strFileName = m_strDir + "/"+m_strFileName;//添加/是為了防止用戶名沒有加/,因?yàn)閷?duì)于文件夾來說兩個(gè)/都會(huì)當(dāng)成一個(gè)/
??? }
???if( QFile::exists(m_strFileName) )//如果文件已經(jīng)存在,那么刪除
??? {
???????QFile::remove(m_strFileName);
??? }
???m_file = new QFile( m_strFileName );
???if (!m_file->open(QIODevice::WriteOnly))
??? {
???????qDebug()<<"不能存儲(chǔ)文件:"<<m_strFileName;
???????delete m_file;
???????m_file = NULL;
???????return;
??? }
c.槽函數(shù)void ReplyFinished(),當(dāng)下載網(wǎng)絡(luò)數(shù)據(jù)結(jié)束時(shí)響應(yīng)此函數(shù),主要是釋放資源
???m_netAccessManager->deleteLater();
???m_netReply->deleteLater();
???m_file->close();
???m_file->deleteLater();
?
d.槽函數(shù)voidReplyNewDataArrived()—當(dāng)數(shù)據(jù)到達(dá)時(shí)調(diào)用此函數(shù),并存儲(chǔ)到指定的文件中??? if(m_file)??? {??????? m_file->write(m_netReply->readAll());??????? m_file->flush();//注意需要刷新??? }??? else??? {??????? qDebug()<<m_netReply->readAll();??? }2.2.2 XML文件的分析
??? QFile file(filename);
??? if(!file.open(QIODevice::ReadOnly | QFile::Text)) {
???????qDebug()<<"open for read error..." ;
??? }
??? QString errorStr;
??? int errorLine;
??? int errorColumn;
??? QDomDocument doc;
???if(!doc.setContent(&file, false, &errorStr, &errorLine,&errorColumn)) {
???????qDebug()<<"setcontent error..." ;
??????? file.close();
??? }
??? file.close();
??? QDomElement root =doc.documentElement();
??? if (root.tagName() !="filelist")
??? {
??????qDebug()<<"root.tagname != filelist.." ;
??? }
??? else
??? {
??????? QDomNodeListnodeList = root.elementsByTagName("file");
??????? for(inti=0;i<nodeList.size();i++)
??????? {
???????? ???qDebug()<<nodeList.at(i).toElement().attribute("name")
?????????????????????<<nodeList.at(i).toElement().attribute("dir")
???????????????????????<<nodeList.at(i).toElement().attribute("version");
??????? }
}???????
}
這里只是將XML文件的內(nèi)容輸出,詳細(xì)的代碼在工程Updater的其他函數(shù)中。
2.2.3?下載XML文件的DownLoadXML函數(shù)
函數(shù)下載XML文件,當(dāng)XML文件下載完成時(shí)發(fā)送下載完成信號(hào),提示進(jìn)行下一步操作。
????/**從網(wǎng)頁(yè)下載XML版本控制文件,里面記錄了最新的文件版本**/
????QStringstrCurrentDir=QDir::currentPath();//當(dāng)前程序運(yùn)行路徑
????QStringstrDownLoad=strCurrentDir+"/download/";//存放下載文件的路徑
?
????QDirdirectory(strDownLoad);//如果路徑不存在,則創(chuàng)建
????if(!directory.exists())
????{
???????directory.mkpath(strDownLoad);
????}
?
????m_httpXML=newCHttpDownloadFile("http://www.***.com/download/**.xml","",strDownLoad,this);//調(diào)用下載文件的類
????connect(m_httpXML,SIGNAL(DownloadFinishedSignal()),this,SLOT(ReplyHttpFinished()));//發(fā)生錯(cuò)誤時(shí)一樣會(huì)發(fā)送此信號(hào)
m_httpXML->DownLoadFile();
在ReplyHttpFinished()函數(shù)中需要錯(cuò)誤處理。
實(shí)例化m_httpXML時(shí),需要將parent設(shè)置為this,這樣當(dāng)程序結(jié)束時(shí),會(huì)自動(dòng)釋放。
2.2.4?返回指定XML文件中的name版本號(hào)
????/***********在xml中查找名字與name相同的元素,并返回版本號(hào)**
?????*xml:xml文件的路徑;
?????*name:需要查找的元素名稱;
?????*
?????*return:QString:版本號(hào),如果有則返回,沒有則為空
?????************************************************/
?QStringGetElementVersion(QStringxml,QStringname);
?
實(shí)現(xiàn):
GetElementVersion(QStringxml,QStringname)
{
????QStringresult="";
????if(xml.isEmpty()||name.isEmpty())
????{
???????qDebug()<<"名稱或者xml文件路徑為空";
???????returnresult;
????}
?
????if(!QFile::exists(xml))
????{
???????qDebug()<<"xml文件不存在";
???????returnresult;
????}
?
????QFilefile(xml);
????if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打開成功
????{
???????QDomDocumentdoc;
???????if(doc.setContent(&file))
???????{
???????????QDomElementroot=doc.documentElement();
???????????if(root.tagName()=="filelist")
???????????{
????????????????inti=0;
????????????????QDomNodeListnodeList=root.elementsByTagName("file");
????????????????for(;i<nodeList.size();i++)
????????????????{
????????????????????QStringtempName???=nodeList.at(i).toElement().attribute("name");
????????????????????//QStringdir????=nodeList.at(i).toElement().attribute("dir");
????????????????????QStringversion=nodeList.at(i).toElement().attribute("version");
?
????????????????????if(name==tempName)
????????????????????{
????????????????????????qDebug()<<"find!"<<name;
????????????????????????result=version;
????????????????????????break;
????????????????????}
????????????????}
?
????????????????if(i==nodeList.size())
????????????????{
????????????????????qDebug()<<"can'tfind!"<<name;
????????????????}
???????????}
???????????else
???????????{
????????????????qDebug()<<"root.tagname!=filelist..";
???????????}
???????}
???????else
???????{
???????????qDebug()<<"setcontenterror...";
???????}
?
???????file.close();
????}
????else
????{
???????qDebug()<<"openforreaderror...";
????}
?
????returnresult;
}
2.2.5?返回指定XML文件中的name版本號(hào)
????/**************比較兩個(gè)版本號(hào)*******************
?????*@params:
?????*?v1,v2:兩個(gè)版本號(hào),格式:1.1.0,不能為空
?????*
?????*@return:
?????*?true:如果兩個(gè)版本號(hào)碼相同;
?????*?false:兩個(gè)版本號(hào)不同
?????*
?????*說明:暫時(shí)只比較了是否相同
?????*******************************************/
?boolCheckVersion(QStringv1,QStringv2);
實(shí)現(xiàn)比較簡(jiǎn)單,就不貼代碼了。
2.2.6?比較兩個(gè)XML文件CheckUpdateFiles
通過比較兩個(gè)XML文件來確定需要下載的文件。
/************比較兩個(gè)XML文件****************
?????*@params:
?????*?name1,name2:兩個(gè)XML文件,不能為空,并且文件需要存在,name1必須是最新的xml文件(剛剛下載下來的),name2是本地的xml文件;
?????*
?????*@return:
?????*0-someerrorhappens,elsesuccess
?????*將需要更新的文件名存儲(chǔ)到m_listFileName中
?????*路徑存儲(chǔ)到m_listFileDir中
?????*
?????*注意:m_listFileDir和m_listFileName的個(gè)數(shù)是一樣的,
?????*????如果沒有元素表示所有的文件都不用更新
?????******************************************/
?intCheckUpdateFiles(QStringname1,QStringname2);
?
實(shí)現(xiàn):
CheckUpdateFiles(QStringname1,QStringname2)
{
????m_listFileDir.clear();
????m_listFileName.clear();
?
????if(name1.isEmpty()||name2.isEmpty())return0;
?
????if(QFile::exists(name2))
????{
???????if(QFile::exists(name1))
???????{
???????????m_strTip="檢查需要更新的文件...";
?
???????????QFilefile(name1);
???????????if(file.open(QIODevice::ReadOnly|QFile::Text))//文件打開成功
???????????{
????????????????QStringerrorStr;
????????????????interrorLine;
????????????????interrorColumn;
?
????????????????QDomDocumentdoc;
????????????????if(doc.setContent(&file,false,&errorStr,&errorLine,&errorColumn))
????????????????{
????????????????????QDomElementroot=doc.documentElement();
????????????????????if(root.tagName()=="filelist")
????????????????????{
????????????????????????QDomNodeListnodeList=root.elementsByTagName("file");
????????????????????????for(inti=0;i<nodeList.size();i++)
????????????????????????{
????????????????????????????QStringname???=nodeList.at(i).toElement().attribute("name");
????????????????????????????QStringdir????=nodeList.at(i).toElement().attribute("dir");
????????????????????????????QStringversion=nodeList.at(i).toElement().attribute("version");
?
????????????????????????????QStringversionDownload=GetElementVersion(name2,name);//獲取本地xml文件對(duì)應(yīng)文件(name)的版本信息
????????????????????????????if(versionDownload.isEmpty())//本地XML沒有此文件:下載,并放到相應(yīng)的目錄中
????????????????????????????{
????????????????????????????????m_listFileDir.append(dir);
????????????????????????????????m_listFileName.append(name);
????????????????????????????}
????????????????????????????else
????????????????????????????{
????????????????????????????????/**檢查版本,如果本地版本低于下載的版本,則下載**/
????????????????????????????????if(!CheckVersion(version,versionDownload))
???????????????????????? ???????{
????????????????????????????????????m_listFileDir.append(dir);
????????????????????????????????????m_listFileName.append(name);
????????????????????????????????}
????????????????????????????????else
????????????????????????????????{
?????????????????????????????????????qDebug()<<name<<"文件是最新版本,不需要更新";
????????????????????????????????}
????????????????????????????}
????????????????????????}
?
????????????????????????return1;//此時(shí)要退出,避免關(guān)閉程序
????????????????????}
????????????????????else
????????????????????{
????????????????????????m_strTip="XML內(nèi)容錯(cuò)誤!";
????????????????????????return0;
????????????????????}
????????????????}
????????????????else
????????????????{
????????????????????qDebug()<<"setcontenterror...";
????????????????????return0;
????????????????}
?
????????????????file.close();
???????????}
???????????else
???????????{
????????????????m_strTip="不能打開更新文件!";
????????????????return0;
???????????}
???????}
???????else
???????{
???????????m_strTip="下載更新文件錯(cuò)誤!";
???????????return0;
???????}
????}
????else
????{
???????m_strTip="本地的更新文件不存在!";
???????return0;
????}
}
2.2.7?下載文件DownLoadUpdateFiles
? 下載需要的文件,完成后啟動(dòng)主程序 。
/********下載最新的版本的文件,并替換或者增加*********************
?????*舊XML中有的文件,新XML沒有的,此文件不做處理。
?????*下載信息由m_listFileName和m_listFileDir提供
?????*****************************************************/
???voidDownLoadUpdateFiles();
實(shí)現(xiàn):
DownLoadUpdateFiles()
{
????QStringstrServer="http://www.***.com/download/";//需要下載的文件存儲(chǔ)位置
????QStringstrCurrentDir=QDir::currentPath();//當(dāng)前程序運(yùn)行路徑
?
????if(m_listFileDir.isEmpty()||m_listFileDir.isEmpty())
????{
???????qDebug()<<"沒有需要下載的文件1";
???????ExitApp(strCurrentDir+"/main.exe");
???????return;
????}
?
????m_strTip="開始下載更新文件...";
?
?
?
????m_bIsFinished=false;
?
????for(inti=0;i<m_listFileName.size();i++)
????{
???????m_strTip="正在下載文件"+m_listFileName.at(i);
???????m_progUpdate->setValue(100*i/m_listFileName.size());
?
???????/**放置下載的文件的路徑**/
???????QStringstrPlaceDir=strCurrentDir+"/download/"+m_listFileDir.at(i);
???????QDirdirectory(strPlaceDir);//如果路徑不存在,則創(chuàng)建
???????if(!directory.exists())directory.mkpath(strPlaceDir);
?
???????QStringstrFileDirServer=strServer+m_listFileDir.at(i)+"/"+m_listFileName.at(i);//文件在服務(wù)器中的存儲(chǔ)位置
???????CHttpDownloadFile*http=newCHttpDownloadFile(strFileDirServer,"",strPlaceDir,this);//調(diào)用下載文件的類
???????http->DownLoadFile();
???????while(!http->m_bIsFinished)
???????{
???????????if(http->m_nTotal==-1)
???????????{
????????????????m_progDownload->setValue(1);
???????????}
???????????else
???????????{
????????????????m_progDownload->setValue(100*http->m_nReceived/http->m_nTotal);
???????????}
???????????QCoreApplication::processEvents();
???????}
?
???????m_strTip="文件"+m_listFileName.at(i)+"下載完成";
?
?
???????/**將下載好的文件復(fù)制到主目錄中,先刪除原先的文件**/
???????QStringstrLocalFileName=strCurrentDir+"/"+m_listFileDir.at(i)+"/"+m_listFileName.at(i);
???????if(QFile::exists(strLocalFileName))QFile::remove(strLocalFileName);
?
???????QDirdirectory1(strCurrentDir+"/"+m_listFileDir.at(i));//如果路徑不存在,則創(chuàng)建
???????if(!directory1.exists())directory1.mkpath(strCurrentDir+"/"+m_listFileDir.at(i));
?
???????QFile::copy(strPlaceDir+"/"+m_listFileName.at(i),strLocalFileName);
????}
?
????m_bIsFinished=true;
????m_strTip="更新完成!";
?
????/**替換舊的xml文件**/
????QStringstrNewXML=strCurrentDir+"/download/**.xml";//最新的XML文件
????QStringstrOldXML=strCurrentDir+"/"+"**.xml";//舊的XML文件
?
????QFile::remove(strOldXML);
????QFile::copy(strNewXML,strOldXML);
?
????ExitApp(strCurrentDir+"/main.exe");
}
2.2.7?退出當(dāng)前程序,并啟動(dòng)指定的程序
????/********退出當(dāng)前程序,并且啟動(dòng)需要的程序*************************
?????*name:需要啟動(dòng)的程序,可以使用相對(duì)位置
?????*程序不能使用exit(0),會(huì)發(fā)生線程錯(cuò)誤,這里使用this->close()函數(shù)
?????*****************************************************/
實(shí)現(xiàn):
ExitApp(QStringname)
{
????if(!name.isEmpty())
????{
???????/**運(yùn)行主程序,并且退出當(dāng)前更新程序(說明:主程序在上上一級(jí)目錄中)**/
???????if(!QProcess::startDetached(name))//啟動(dòng)主程序,主程序在其上一級(jí)目錄
???????{
???????????QMessageBox::warning(this,"警告信息","啟動(dòng)主程序錯(cuò)誤!\n可能主程序不存在或者被破壞!\n解決辦法:重新安裝程序!");
???????}
????}
?
????this->close();
}
3?更新程序的啟動(dòng)
??? 更新程序是獨(dú)立的可執(zhí)行文件,所以在啟動(dòng)主程序時(shí),首先啟動(dòng)更新程序(注:網(wǎng)絡(luò)檢查放在了更新程序中),然后關(guān)閉主程序,更新完成后,再重新啟動(dòng)主程序。
3.1?從主程序啟動(dòng)更新程序
??? 首先需要判斷是否需要啟動(dòng)更新程序,避免更新后再次啟動(dòng)更新程序;
??? 將是否需要啟動(dòng)更新程序的參數(shù)放在軟件的初始參數(shù)文件中,例如params.txt文件中,初始值為true,表示需要啟動(dòng)更新程序。主程序啟動(dòng)時(shí),先獲取里面的參數(shù),并判斷是否需要啟動(dòng)更新程序。完成更新后,將此參數(shù)設(shè)置為false,表示下次再次啟動(dòng)主程序時(shí)不需更新,當(dāng)點(diǎn)擊關(guān)閉主程序時(shí)再次將此參數(shù)設(shè)置為true,這樣就可以保證每次啟動(dòng)時(shí)都會(huì)檢查更新;
啟動(dòng)更新程序調(diào)用QProcess::startDetached()方法,啟動(dòng)外部程序后立即返回(也就是主程序也運(yùn)行),即使主程序關(guān)閉,啟動(dòng)的程序也會(huì)運(yùn)行,本程序使用這個(gè)方法,因?yàn)楦潞蟆?/p>
注:如果調(diào)用QProcess::execute函數(shù),此方法可以阻塞主程序的運(yùn)行,直到啟動(dòng)的程序關(guān)閉,因?yàn)樾枰P(guān)閉主程序,還要重新啟動(dòng)更新后得程序,所以不能使用這個(gè)方法。
3.2?主程序的關(guān)閉
??? 如果QProcess::startDetached方法返回true,則關(guān)閉主程序,調(diào)用exit(0),或者quit()方法;
3.3?更新程序關(guān)閉時(shí)啟動(dòng)主程序
更新程序結(jié)束時(shí)調(diào)用QProcess::startDetached("main.exe"),主程序和更新程序在同一目錄。但是在關(guān)閉更新程序的時(shí)候使用exit會(huì)發(fā)送錯(cuò)誤,錯(cuò)誤原因:會(huì)出現(xiàn)夸線程發(fā)送信號(hào)的情況,這是不容許的。
當(dāng)所有文件都下載完成時(shí),使用close函數(shù)。
4?程序調(diào)試
需要調(diào)試以下功能:
(1)主程序啟動(dòng)時(shí),檢測(cè)是否需要啟動(dòng)更新程序, 檢測(cè)params.cq文件里面的is_update參數(shù)的值,如果為1則啟動(dòng),否則不啟動(dòng)(代碼在CLoginBox的構(gòu)造函數(shù)中);
(2)如果is_update=1,那么啟動(dòng)更新程序,更新程序啟動(dòng)后,is_update設(shè)置為0;
(3)主程序退出時(shí),將is_update設(shè)置為1,即每次重新啟動(dòng)主程序的時(shí)候都需要檢查更新;
(4)正確下載xml文件,存儲(chǔ)位置:與主程序同目錄下的download文件 夾中(特別提醒:由于更新程序是從主程序中調(diào)用的,所以在更新程序中調(diào)用獲取當(dāng)前運(yùn)行程序的目錄是得到的是主程序的的目錄,但是如果更新程序單獨(dú)運(yùn)行的話,得到的目錄是和更新程序目錄一樣的,所以最好的方式就是講主程序和更新程序放在同一個(gè)目錄中);
(5)是否正確調(diào)用了更新程序里面的CheckUpdateFiles函數(shù),主要是檢查是否輸入正確的xml文件目錄;
(6)下載的更新文件是否正確放置;
(7)下載完后舊的XML是否換成新的XML;
(8)運(yùn)行主程序的電腦或者服務(wù)端沒有網(wǎng)絡(luò)的情況;
版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。 https://blog.csdn.net/hulinhulin/article/details/46839107總結(jié)
以上是生活随笔為你收集整理的软件自动更新解决方案及QT实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Chrome内核解析 -- 背景篇:Ch
- 下一篇: 牛逼!用文言文来编程,97 年 CMU