还是在“pia-myphotogallery”中,为了能让使用者及时知道软件的更新版本发布,我增加了自动更新检查功能。鉴于这种功能具有很好的实用价值,所以写本文说明此功能的实现。
要实现更新检查,需要解决两个方面的问题:
1、通过internet获取最新发布的版本号;
2、取得当前程序的版本,并与取得的最新版本相比较。
如果检查到有新版本发布,则打开下载页面(至于直接下载更新本文暂不讨论)。
对于第一个问题,最简单的解决办法就是在网站上发布新版本软件的同时,发布一个记录着版本号的文件。在软件进行版本检查时(比如程序启动时),通过internet下载此文件,并读出最新的版本号。
注意:此方法仅适用于简单更新的情况,对于像杀毒软件的病毒库这样增量更新的情况,这种简单方法是不合适的,通常还需要有相应的服务端程序配合才行。
要通过internet下载文件有很多方法,比如用wininet api或现成的控件都可以。本文以indy的tidhttp控件为例。
tidhttp控件的用法非常简单,但是直接使用它下载会有一个问题:程序会被阻塞着,直到文件被下载或连接超时(比如网络未连接)。所以必须将它放到线程中处理。
在pia-myphotogallery中,我用的代码如下:
//---------------------------------------------------------------------------
// get new version thread
class tgetnewversionthread : public tthread
{
private:
ansistring furl;
tmfileversion * fver;
protected:
void __fastcall execute( );
public:
__fastcall tgetnewversionthread( ansistring aurl )
: tthread( true ), furl( aurl ), fver( new tmfileversion( ) )
{
freeonterminate = true;
}
__fastcall ~tgetnewversionthread( ) { delete fver; }
__property tmfileversion * version = { read=fver };
};
//---------------------------------------------------------------------------
// tgetnewversionthread
//---------------------------------------------------------------------------
void __fastcall tgetnewversionthread::execute( )
{
boost::scoped_ptr webconn( new tidhttp( null ) );
boost::scoped_ptr ss( new tstringlist( ) );
try {
ss->text = webconn->get( furl );
}
catch ( ... )
{
ss->text = "";
}
ansistring s = ss->values["piapg"];
if ( s != "" )
fver->verstr = s;
}
//---------------------------------------------------------------------------
这段代码很简单:创建一个线程,在线程里创建一个tidhttp实例,然后下载url对应的文件,最后从中读出“piapg”的版本号。为了偷懒,我用了boost库里的smart pointer--scoped_ptr。
这个线程类的使用方法如下:
//---------------------------------------------------------------------------
// 在程序启动时执行:
if ( piapgcfg->autoupd ) // 如果选择了“检查更新”选项则执行检查
{
if ( splashdlg ) // 如果有splash,则在其中显示提示文本
{
splashdlg->labprogress->caption = "正在检查新版本...";
splashdlg->labprogress->refresh( );
}
// 创建检查新版本的线程
tgetnewversionthread * pthread = new tgetnewversionthread( "http://mental.mentsu.com/update.txt" );
pthread->onterminate = getnewversiondone;
pthread->resume( );
}
//---------------------------------------------------------------------------
// 版本文件下载完成或超时
void __fastcall tmainform::getnewversiondone(tobject * sender)
{
tgetnewversionthread * pthread = dynamic_cast( sender );
boost::scoped_ptr fv( new tmfileversion( ) );
fv->getversionfromfile( application->exename ); // 读取当前程序的版本
if ( ( pthread->version->compare( fv.get( ) ) > 0 ) // 如果有新版本,则提示
&& ( application->messagebox( "发现更新版本的程序,是否现在更新?",
"新版本检查", mb_yesno | mb_iconinformation ) == idyes ) )
{
shellexecute( null, "open", "http://mental.mentsu.com", null, null, sw_show );
postquitmessage( 0 );
}
}
//---------------------------------------------------------------------------
此代码的功能详见其中的注释。
再来看第二个问题:程序版本的问题。
在上面的代码中,用到了一个类:tmfileversion。这是我以前用delphi写的一个用于处理可执行文件版本号的类。实现代码如下: