軟體的版本更新檢查實現

來源:互聯網
上載者:User
軟體的自動更新檢查

[Mental Studio]猛禽[Blog]

還是在“PIA-MyPhotoGallery”中,為了能讓使用者及時知道軟體的更新版本發布,我增加了自動更新檢查功能。鑒於這種功能具有很好的實用價值,所以寫本文說明此功能的實現。

要實現更新檢查,需要解決兩個方面的問題:

1、通過Internet擷取最新發行的版本號碼;

2、取得當前程式的版本,並與取得的最新版本相比較。

如果檢查到有新版本發布,則開啟下載頁面(至於直接下載更新本文暫不討論)。

對於第一個問題,最簡單的解決辦法就是在網站上發布新版本軟體的同時,發布一個記錄著版本號碼的檔案。在軟體進行版本檢查時(比如程式啟動時),通過Internet下載此檔案,並讀出最新的版本號碼。

注意:此方法僅適用於簡單更新的情況,對於像殺毒軟體的病毒庫這樣累加式更新的情況,這種簡單方法是不合適的,通常還需要有相應的服務端程式配合才行。

要通過Internet下載檔案有很多方法,比如用WinINet API或現成的控制項都可以。本文以Indy的TIdHTTP控制項為例。

TIdHTTP控制項的用法非常簡單,但是直接使用它下載會有一個問題:程式會被阻塞著,直到檔案被下載或連線逾時(比如網路未串連)。所以必須將它放到線程中處理。

在PIA-MyPhotoGallery中,我用的代碼如下:

//---------------------------------------------------------------------------//  Get new version threadclass 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寫的一個用於處理可執行檔版本號碼的類。實現代碼如下:

    TMFileVersion = class    private        FMajor   : Integer;        FMinor   : Integer;        FRelease : Integer;        FBuild   : Integer;        Function  GetVerStr : String;        Procedure SetVerStr( aVerStr : String );    public        constructor Create;        destructor Destroy; override;        Procedure GetVersionFromFile( aFileName : String );        Function  Compare( aVer : TMFileVersion ) : Integer;        Property VerStr : String read GetVerStr write SetVerStr;    End;{ TMFileVersion }//  initconstructor TMFileVersion.Create;Begin    Inherited;    FMajor   := 0;    FMinor   := 0;    FRelease := 0;    FBuild   := 0;End;destructor TMFileVersion.Destroy;Begin    Inherited;End;//  Get version info from a fileProcedure TMFileVersion.GetVersionFromFile( aFileName : String );Type    PVS_FIXEDFILEINFO = ^VS_FIXEDFILEINFO;Var    h : Cardinal;        // a handle, ignore    nSize : Cardinal;    // version info size    pData : Pointer;     // version info data    pffiData : PVS_FIXEDFILEINFO;  // fixed file info data    nffiSize : Cardinal; // fixed file info sizeBegin    FMajor   := 0;    FMinor   := 0;    FRelease := 0;    FBuild   := 0;    If ( FileExists( aFileName ) ) Then        FBuild := 1;    nSize := GetFileVersionInfoSize( PChar( aFileName ), h );    If ( nSize = 0 ) Then        Exit;    GetMem( pData, nSize );    Try        GetFileVersionInfo( PChar( aFileName ), h, nSize, pData );        If ( VerQueryValue( pData, '/', Pointer( pffiData ), nffiSize ) ) Then        Begin            FMajor   := ( pffiData^.dwFileVersionMS ) SHR 16;            FMinor   := ( pffiData^.dwFileVersionMS ) AND $FFFF;            FRelease := ( pffiData^.dwFileVersionLS ) SHR 16;            FBuild   := ( pffiData^.dwFileVersionLS ) AND $FFFF;        End;    Finally        FreeMem( pData );    End;End;//  Compare two version infoFunction TMFileVersion.Compare( aVer : TMFileVersion ) : Integer;Var    n1, n2 : Cardinal;Begin    n1 := ( FMajor SHL 16 ) OR FMinor;    With aVer Do        n2 := ( FMajor SHL 16 ) OR FMinor;    If ( n1 > n2 ) Then        Result := 1    Else If ( n1 < n2 ) Then        Result := -1    Else    Begin        n1 := ( FRelease SHL 16 ) OR FBuild;        With aVer Do            n2 := ( FRelease SHL 16 ) OR FBuild;        If ( n1 > n2 ) Then            Result := 1        Else IF ( n1 < n2 ) Then            Result := -1        Else            Result := 0;    End;End;//  Get/Set property - VerStrFunction TMFileVersion.GetVerStr : String;Begin    Result := Format( '%d,%.02d,%d,%.02d', [FMajor, FMinor, FRelease, FBuild] );End;Procedure TMFileVersion.SetVerStr( aVerStr : String );Var    sTemp : TStrings;Begin    FMajor   := 0;    FMinor   := 0;    FRelease := 0;    FBuild   := 0;    sTemp := TStringList.Create;    Try        sTemp.CommaText := aVerStr;        Try            FMajor   := StrToInt( sTemp.Strings[0] );            FMinor   := StrToInt( sTemp.Strings[1] );            FRelease := StrToInt( sTemp.Strings[2] );            FBuild   := StrToInt( sTemp.Strings[3] );        Except            //  Do nothing        End;    Finally        sTemp.Free;    End;End;

解決了這兩個問題,自動更新檢查的功能也就解決了。

BTW:為方便使用,已經改用DELPHI重寫並封裝為一個VCL控制項。

[Mental Studio]猛禽 Oct.30-04

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.