This article can also be found at
CodeProject    
Introduction
At AutoUpdate+ we create software that manages updates for Win32-based software, which is great for mid to large scale users who need such a solution, but is a bit of overkill for the small developer. Many small developers only require a simple update solution, and frequently it is only required to manage the update of the main project executable. This article will describe an autoupdate class I created, which is very simple to add to a project and which runs a little trick to update the main project exectutable.
Using the code
A class called CAutoUpdater was designed, with the goals that it is
easy to add to any application, fully manages the update process and correctly handles
any errors. To use this class, simply call the CheckForUpdate method
passing in the URL of your update server.
void CMFCUpdaterDlg::OnUpdatecheck()
{
CAutoUpdater updater;
if (CAutoUpdater::Success == updater.CheckForUpdate("http://AutoUpdatePlus.com/test/"))
{
// ... Notify user of success
}
}
The update process consists of the following steps:
1) Ensure that an internet connection is available.
2) Retrieve the config file from the update server.
3) Check the version in the config file. Compare to the existing application version.
4) If an update is required, then download the new application from the update server.
5) Switch in the latest application version with the existing version.
Ensure internet connection exists
The first, and frequently overlooked step, is to ensure that an internet connection is available. This is essential to do because otherwise you may trigger an automatic dial-up to the internet, which is likely to make most of your application users unhappy.
// Important step - ensure we have an internet connection. We don't want to force a dial-up.
DWORD dwType;
if (!InternetGetConnectedState(&dwType, 0))
{
return false;
}
Read config file
Retrieving files from an HTTP server is a simple task using InternetOpenUrl,
but it can fail if the URL supplied is not canonicalized. This simply means that
bad characters, such as spaces, must be converted into escape characters, which
is does using InternetCanonicalizeUrl. The GetSession
method manages this process, returning a handle to a file on the HTTP server for
a give URL. To check for updates we must define an update config file on the server
which lets us know what application version to expect. In our case the update config
file is called update.txt and contained the version of our application
update. You can see it at http://AutoUpdatePlus.com/test/update.txt.
After getting a session handle to the update config file we can retrieve the data
into a buffer using the DownloadConfig method. We now have the update
version available for our use.
HINTERNET CAutoUpdater::GetSession(CString &URL)
{
// Convert unsafe characters into escape character equivalents
TCHAR canonicalURL[1024];
DWORD nSize = 1024;
InternetCanonicalizeUrl(URL, canonicalURL, &nSize, ICU_BROWSER_MODE);
DWORD options = INTERNET_FLAG_RESYNCHRONIZE|INTERNET_FLAG_RELOAD;
HINTERNET hSession = InternetOpenUrl(hInternet, canonicalURL, NULL, NULL, options, 0);
URL = canonicalURL;
return hSession;
}
bool CAutoUpdater::DownloadConfig(HINTERNET hSession, BYTE *pBuf, DWORD bufSize)
{
DWORD dwReadSizeOut;
InternetReadFile(hSession, pBuf, bufSize, &dwReadSizeOut);
if (dwReadSizeOut <= 0)
{
return false;
}
return true;
}
At this point we have retrieved the update config file and must now figure out if
an update is required. The text in the update config file is a simple version tag,
in our case the update version 2.0.0.1. This must be compared against the
version of the executable we are currently running. Surprisingly, getting the version
number from the executable and running a version number comparison is not a trivial
task and can get a bit messy. If it turns out that our existing application version
is out-of-date, we should notify the user and then proceed to download the latest
application executable from the update server. Note that our new executable will
be downloaded to a temporary user directory given by GetTempPath .
Switch in new file
Once the latest executable version is downloaded, it must somehow be switched in
to replace the existing out-of-date application executable. However, a problem exists!
The current executable is locked, as it is in use, and hence cannot be copied over.
Nevertheless, a simple Windows trick does exist. Files in use can still be renamed,
leaving space open for the update executable to be switched in to the application
directory. Note that this update trick may not always be available as some files
can even get locked from renaming. In this case the MoveFileEx with
MOVE_DELAY_UNTIL_REBOOT option can be used, which delays renaming until
a reboot occurs to free the file.
bool CAutoUpdater::Switch(CString executable, CString update, bool WaitForReboot)
{
int type = (WaitForReboot) ? MOVEFILE_DELAY_UNTIL_REBOOT : MOVEFILE_COPY_ALLOWED;
const TCHAR *backup = _T("OldExecutable.bak");
CString directory = executable.Left(executable.ReverseFind(_T('\\')));
CString backupFile = directory + _T('\\') + CString(backup);
DeleteFile(backupFile);
if (!MoveFileEx(executable, backupFile, type))
{
return false;
}
BOOL bMoveOK = (MoveFileEx(update, executable, type) == TRUE);
int i = GetLastError();
return bMoveOK;
}
Points of Interest
The class provided manages updates for a simple application, but has a few draw-backs:
- The update check is a synchronous task which does not provide any user feedback
as to its progress.
- Having the update check within the application limits its capabilities. It is wiser
to have the update check run from an external executable.
- A program that appears trivial quickly becomes complex. The current check cannot manage complex situations, such as multiple file updates.

Home
Download
Purchase