Automatic Software Update Check
[Mental Studio] blog
In "Pia-myphotogallery", I added the automatic update check function to keep users updated about the software release in time. In view of the practical value of this function, this article describes the implementation of this function.
To implement the update check, two problems need to be solved:
1. obtain the latest version number through the Internet;
2. Obtain the version of the current program and compare it with the latest version.
If you check that a new version is released, the download page is displayed (this article does not discuss direct download and update ).
For the first problem, the simplest solution is to release a file that records the version number while releasing a new version of the software on the website. When the software performs version check (such as when the program starts), download the file over the Internet and read the latest version number.
Note: This method is only applicable to simple updates. This method is not suitable for incremental updates such as antivirus software virus libraries, it usually requires the cooperation of the corresponding server program.
There are many methods to download files over the Internet, such as using wininet APIs or existing controls. This article takes Indy's tidhttp control as an example.
The usage of the tidhttp control is very simple, but directly using it to download may cause a problem: the program will be blocked until the file is downloaded or the connection times out (for example, the network is not connected ). Therefore, it must be put into the thread for processing.
In Pia-myphotogallery, the code I use is as follows:
//---------------------------------------------------------------------------// 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;}//---------------------------------------------------------------------------
This code is simple: Create a thread, create a tidhttp instance in the thread, download the file corresponding to the URL, and read the version number of "piapg. To be lazy, I used the smart pointer -- scoped_ptr In the boost library.
The usage of this thread class is as follows:
// Else // execute when the program starts: If (piapgcfg-> autoupd) // if the "check for updates" option is selected, run the check {If (splashdlg) // If splash exists, the prompt text {splashdlg-> labprogress-> caption = "checking the new version... "; splashdlg-> labprogress-> refresh ();} // create check new version thread tgetnewversionthread * pthread = new tgetnewversionthread (" http://mental.mentsu.com/update.txt "); pthread-> onterminate = getnewversiondone; pthread-> resume ();} // merged // version file download completed or timed out void _ fastcall tmainform: getnewversiondone (tobject * sender) {tgetnewversionthread * pthread = dynamic_cast
(Sender); Boost: scoped_ptr
FV (New tmfileversion (); Fv-> getversionfromfile (Application-> exename); // read the current program version if (pthread-> Version-> compare (FV. get ()> 0) // if a new version is available, the system prompts & (Application-> MessageBox ("check whether the updated program is updated now? "," New Version Check ", mb_yesno | mb_iconinformation) = idyes) {ShellExecute (null," open "," http://mental.mentsu.com ", null, null, sw_show ); postquitmessage (0 );}}//---------------------------------------------------------------------------
For more information about the functions of this Code, see annotations.
Let's take a look at the second question: the program version.
In the above Code, a class: tmfileversion is used. This is a class I previously wrote using Delphi to process the version number of executable files. The implementation code is as follows:
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;
These two problems are solved, and the automatic update check function is also solved.
BTW: For ease of use, you have used Delphi to rewrite and encapsulate it as a VCL control.
[Mental Studio] .octoct.30-04