Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / MFC

Effective online update checking mechanism using PAD / XML files

4.35/5 (8 votes)
21 Dec 20066 min read 1   357  
How to check for new program versions using XML / PAD files.

Example

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.

XML
<?xml version="1.0" encoding="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:

// Get root node
TiXmlNode* pDIZ = xmlDoc.FirstChild( "XML_DIZ_INFO" );

if( NULL == pDIZ )
    return;

// Get the program info node (parent node is root node above)
TiXmlNode* pPInfo = pDIZ->FirstChild( "Program_Info" );

if( NULL == pPInfo )
    return;

// Get the version node (parent node is program info above)
TiXmlNode* pPVer = pPInfo->FirstChild( "Program_Version" );

if( NULL == pPInfo )
    return;

// Cast our version node to an element
TiXmlElement* pPVerEl = pPVer->ToElement();
ASSERT( NULL != pPVerEl );

// Extract the text of this node into a CString object
CString strVer = pPVerEl->GetText();

DWORD dwFileMajor = 0;
DWORD dwFileMinor = 0;
DWORD dwFileBuild = 0;

// Extract the version information parts into separate variables
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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here