Introduction
This article describes how to implement an effective online update checking mechanism using PAD files in MFC and TinyXML. You need at least basic knowledge of XML and a basic understanding of the MFC libraries.
What are PAD files?
PAD is an abbreviation for "Portable Application Description", and is a machine-readable document format designed by the Association of Shareware Professionals. It allows authors to provide product descriptions and specifications to online sources in a standard way, using a standard data format that will allow webmasters and program librarians to automate program listings. PAD saves time for both authors and webmasters. To find out more about PAD files, please visit this website. The text above was bought from Association of Shareware Professionals and was slightly modified.
Why just PAD files?
Most big download sites on the net provide two ways to submit your application: either you type in all the required data (version, application name, description, ... ) into a special form, or you can provide a link to a PAD file that lies on a webspace you provide. If you want to submit your application to lots of sites, the first way is quite a time eater.
Or just imagine you want to tell all the sites that there's an update for your program. Same game: visit all the sites, login to your account, change the version, add new feature texts, ...
Since software developers often are very lazy (hey, just speaking for me! *g*), it would be better to provide one area where to change all the information above and let all the sites on the net grab them automatically.
Well, maybe you already guessed it, this place is your PAD file. You only have to create it once, upload it to your web space, let all the sites know that there's your file at this URL, and you're done. Almost. If you have an update for your application, simply change that file - most download sites have a so-called "robot" that checks all PAD files periodically and updates the site's content with no interaction required.
Now think a step further: if we already have a PAD file for all the sites, why can't we use the same file for our own purposes? Most programs today have a feature that checks for a new version at program startup. The easiest method would be a simple text file with a version string, of course. But wait! This version string is already present in a PAD file.
So with this PAD file, you can do three things with only one effort:
- Submit new programs to today's most known download sites
- Let all the download sites do the updating and maintenance of your product on their sites
- Let your program check for updates / new versions
Implementation
Our implementation consists of three steps:
- Step 1: Get the version information of you local .exe file.
- Step 2: Download the current PAD file from the internet to your local machine.
- Step 3: Parse the PAD file for the version information.
- Step 4: Compare both versions against each other, and notify the user about a potential update.
Step 1: Get the version information of you local .exe file
To get the current version of an .exe file - there are numerous routines and / or classes that provide this functionality already on CodeProject! For this tutorial, I'm using a class called CFileVersionInfo
(CFileVersionInfo - Getting the file version information) written by Armen Hakobyan. This pretty piece of code does exactly the job we want: extract various version information from a local file.
Here's the code:
CFileVersionInfo fVer;
if( FALSE == fVer.Open( "your_exe_file.exe" ) )
return;
DWORD dwExeMajor = fVer.GetFileVersionMajor();
DWORD dwExeMinor = fVer.GetFileVersionMinor();
DWORD dwExeBuild = fVer.GetFileVersionBuild();
Note: Major, Minor, Build, and QFE values are parts of the whole version number. Version 1.2.40 means Major="1", Minor="2", Build="40". If you always want to get the version of the executable file you're calling the CFileVersionInfo
object from, then you use the function GetModuleFileName()
to retrieve the file name.
Step 2: Download the current PAD file from the internet to your local machine
For downloading files from the internet, there are numerous possible ways. I decided to use some good old standard classes to do the job: CInternetSession
and CHttpFile
. My function awaits an URL as parameter, downloads this file in text mode into a CString
object, and returns this object for further processing. For implementation details, please have a look at the provided source code.
Step 3: Parse the PAD file for the version information
Now, let's have a look at a snippet of a PAD file. It would be too much overhead to show a complete PAD file here, since there're very much information we don't need for our online update checking routine.
="1.0"="UTF-8"
<XML_DIZ_INFO>
.
.
<Program_Info>
.
.
<Program_Name>UpdateCheck_Example</Program_Name>
<Program_Version>0.1.0</Program_Version>
.
.
</Program_Info>
.
.
</XML_DIZ_INFO>
As you can see, the container "Program_Info
" has an element called "Program_Version
". The value of it states the current published version of your program. Now, all you have to do is to read this string out and compare it later to the version on the currently installed .exe file.
Well, so we need a simple solution to parse the XML file. Sure, it would be an easy task to search for the phrases <Program_Version>
and </Program_Version>
and cut out the middle part (which contains the version string). I'm not a fan of such hacks, so I decided to use the TinyXML library for this tutorial. This library is very fast and easy to use; and it's open source! You can get TinyXML here.
Here's how I've done it:
TiXmlNode* pDIZ = xmlDoc.FirstChild( "XML_DIZ_INFO" );
if( NULL == pDIZ )
return;
TiXmlNode* pPInfo = pDIZ->FirstChild( "Program_Info" );
if( NULL == pPInfo )
return;
TiXmlNode* pPVer = pPInfo->FirstChild( "Program_Version" );
if( NULL == pPInfo )
return;
TiXmlElement* pPVerEl = pPVer->ToElement();
ASSERT( NULL != pPVerEl );
CString strVer = pPVerEl->GetText();
DWORD dwFileMajor = 0;
DWORD dwFileMinor = 0;
DWORD dwFileBuild = 0;
char szBuf[ 32 ];
sprintf( szBuf, "%s", strVer.GetBuffer( 1 ) );
sscanf( szBuf, "%d.%d.%d", &dwFileMajor, &dwFileMinor, &dwFileBuild );
Step 4: Compare both versions against each other and notify the user about a potential update
Okay, we got our two versions - one version of the PAD file, one version of our .exe file. Since a version consists of three parts (major, minor, build), how can we compare these values against each other? The solution: just add them!
Here's some code that should make it clear:
DWORD dwExeSum = ( dwExeMajor * 100 ) + ( dwExeMinor * 10 ) + dwExeBuild;
DWORD dwFileSum = ( dwFileMajor * 100 ) + ( dwFileMinor * 10 ) + dwFileBuild;
if( dwFileSum > dwExeSum )
{
m_strVer.Format( "%d.%d.%d", dwFileMajor, dwFileMinor, dwFileBuild );
bUpdate = true;
}
if( bUpdate )
{
MessageBox()
}
Please note the multipliers: they make sure that a lower major version has still a higher count compared to just a higher minor version, e.g., 4.6.1 is greater than 3.7.2.
Improvements / Ideas
The routines are pretty straightforward; I don't think that there's much room for improvement, since there's no real need for speeding something up. But one thing you should keep in mind: to download a file from the internet and communicate with a web server takes time. Maybe the server is down for some reason? Maybe a firewall blocks the current function call for some time? To prevent the application from hanging - especially the GUI itself - you should consider putting all the version checking routines in a separate thread, and notify the main application window when the job is done with a simple window message.
About the demo
As default, the provided demo loads its PAD file from the executable's directory. If you have already got another PAD file on the web, just change the default URL and version text fields to fit your needs.