Click here to Skip to main content
15,610,865 members
Articles / Desktop Programming / Win32
Posted 11 Sep 2017


40 bookmarked

An efficient way for automatic updating

Rate me:
Please Sign up or sign in to vote.
5.00/5 (21 votes)
11 Sep 2017CPOL7 min read
A simple way to provide silent automatic updates with no server side code

 CodeProject Best C++ Article of September 2017 First Prize.


Many software developers need to update their software and apply such update to all current users. This article provides a method we developed which allows a fully transparant automatic updates with no action needed from the user (such as start the new version, etc.). It is also unique because it doesn't reuqire any server side code. 

The Problems

I have looked for a way to have our software download updates only when the version  on our web site is newer, and yet, to avoid having to run a server side component. Our goal was to have our AutoUpdate class determine if the version on the web site is indeed newer without downloading it first. We also wanted a clean and smooth solution which won't require installing a new version but will cause a product (i.e software.exe) to replace itself with a new version (also software.exe) transparantly. I learned that there are quite a few steps that has to be taken and scenarios to be addressed but the result is a solid solution and covers all scenarios. 

The Building Blocks

Obtaining the version of a given executable. We use GetFileVersionInfo() to obtain the information. We have developed our own function to convert an executable path into our own version information structure which is:

typedef struct
    int Major;
    int Minor;
    int Revision;
    int SubRevision;
} SG_Version;

so SG_GetVersion goes as follow:

BOOL AutoUpdate::SG_GetVersion(LPWSTR ExeFile, SG_Version *ver)
    BOOL result = FALSE;
    DWORD dwDummy;
    DWORD dwFVISize = GetFileVersionInfoSize(ExeFile, &dwDummy);
    LPBYTE lpVersionInfo = new BYTE[dwFVISize];
    GetFileVersionInfo(ExeFile, 0, dwFVISize, lpVersionInfo);
    UINT uLen;
    VerQueryValue(lpVersionInfo, _T("\\"), (LPVOID *)&lpFfi, &uLen);
    if (lpFfi && uLen)
        DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
        DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;
        delete[] lpVersionInfo;
        ver->Major = HIWORD(dwFileVersionMS);
        ver->Minor = LOWORD(dwFileVersionMS);
        ver->Revision = HIWORD(dwFileVersionLS);
        ver->SubRevision = LOWORD(dwFileVersionLS);
        result = TRUE;
    return result;

Adding the next version to the file name. Next we need a function that will generate the file name which will contain the next version. For example, if our software is "program.exe" and the next version is, then this function will generate the following name and store it in our class's member variable m_NextVersion "program.".

void AutoUpdate::AddNextVersionToFileName(CString& ExeFile, SG_Version ver)
    CString strVer;
    ver.SubRevision += 1;    // For the time being we just promote the subrevision in one but of course
                            // we should build a mechanism to promote the major, minor and revision
    ExeFile = GetSelfFullPath();
    ExeFile = ExeFile.Left(ExeFile.GetLength() - 4);
    ExeFile += L"."+strVer;
    ExeFile += L".exe";
    m_NextVersion = ExeFile;

Downloading the newer version from the web site

After examining several ways to download a file from a URL, here is the best method we have found. Please note that we are using DeleteUrlCacheEntry(). If your software is looking for updates every 2 hours, and only after 6 hours, an update is placed, unless you delete the cache, your browser might not download the newer file as it will have the name of an existing file. That is also important during the QA phase when you try different scenarios.

DeleteUrlCacheEntry(URL); // we need to delete the cache so we always download the real file
HRESULT hr = 0;
hr = URLDownloadToFile(
    NULL,   // A pointer to the controlling IUnknown interface (not needed here)
    ExeName,0,              // Reserved. Must be set to 0.
    &pCallback);           //  A callback function is used to ensure asynchronous download

Then the callback function goes like that:

We define a class named MyCallback. Before calling URLDownloadToFile() we define a local member of this function:

MyCallback pCallback;

The class is define as follow:

using namespace std;

class MyCallback : public IBindStatusCallback
    MyCallback() {}

    ~MyCallback() { }

    // This one is called by URLDownloadToFile
    STDMETHOD(OnProgress)(/* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR wszStatusText)
        // You can use your own logging function here
        // Log(L"Downloaded %d of %d. Status code", ulProgress, ulProgressMax, ulStatusCode);
        return S_OK;

    STDMETHOD(OnStartBinding)(/* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR *pib)
        return E_NOTIMPL;

    STDMETHOD(GetPriority)(/* [out] */ LONG __RPC_FAR *pnPriority)
        return E_NOTIMPL;

    STDMETHOD(OnLowResource)(/* [in] */ DWORD reserved)
        return E_NOTIMPL;

    STDMETHOD(OnStopBinding)(/* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError)
        return E_NOTIMPL;

    STDMETHOD(GetBindInfo)(/* [out] */ DWORD __RPC_FAR *grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo)
        return E_NOTIMPL;

    STDMETHOD(OnDataAvailable)(/* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ STGMEDIUM __RPC_FAR *pstgmed)
        return E_NOTIMPL;

    STDMETHOD(OnObjectAvailable)(/* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk)
        return E_NOTIMPL;

    // IUnknown stuff
        return 0;

    STDMETHOD_(ULONG, Release)()
        return 0;

    STDMETHOD(QueryInterface)(/* [in] */ REFIID riid, /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject)
        return E_NOTIMPL;

The SG_Run function

The SG_Run function is the optimal way we have found to start a new process. There are various ways such as ShellExecute() but that would be the most efficient one:

    wprintf(L"Called SG_Run '%s'", FileName);
    PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter

    STARTUPINFO StartupInfo; //This is an [in] parameter

    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
    StartupInfo.cb = sizeof StartupInfo; //Only compulsory field

    if (CreateProcess(FileName, NULL,
        NULL, NULL, FALSE, 0, NULL,
        NULL, &StartupInfo, &ProcessInfo))
        //WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
        return TRUE;
        return FALSE;


The Solution

Before you start coding, remember to make sure your project has a version string. To add a version string, right click the project name in the Solution Explorer and select Add -> Resource. Image 1Image 2

The flow

The solution can be described with the following steps:

Given that the current version of a product (software.exe) is, we would like it to download the replace itself with a newer version if this version is We name version of software.exe software. We place this version in our web site where it can be downloaded freely with no need to interact with the server or to log in. For example:
  1. Software.exe should faetch its own version and periodically try to download its next version if that is possible. If there is no newer version nothing will be downloaded.
  2. When there is a newer version it will be downloaded to a temporary file (for example _software.exe). 
  3. _software.exe will be examined to assure that its version string matches the original file name on the server, (i.e., if not, it will be deleted and ignored.
  4. software.exe will now start _software.exe as a new process.
  5. software.exe quits.
  6. _software.exe copies itself to software.exe, which is possible since software.exe quitted.
  7. _software.exe starts software.exe as a new process.
  8. _sotware.exe quits.
  9. software.exe deletes _software.exe.


We need to link our software with the following libraries:

urlmon.lib and version.lib.

Remember to set the Language of your code snippet using the Language dropdown.

Use the "var" button to to wrap Variable or class names in <code> tags like this.

The Magic

I have placed an identical copy of this program in my server, with one change: the version string in the code that is included in this article is and the one on my server is If you download the source code and compile it, you will get SG_AutoUpdate.exe. If you run it, it should automatically update itself within seconds.

The original executable looks like this:

Image 3

After running it, you will see the same file but in fact it is a different one. Its the newer version:

Image 4

You can of course use your own web site. 

Right now, the download link is composed using this constant:

CString m_DownloadLink = _T("");

AutoUpdate.h line 43.

You can replace it to any other address. Then here are the instructions for testing this mechanism: 

  1. Build the source code and keep SG_AutoUpdate.exe somewhere (or rename it temporarily).
  2. Go to the project's resources, find the version string, and change it to
  3. Build the source code again.
  4. You will get the more recent version under the name SG_AutoUpdate.exe. Upload it to your server and rename it SG_AutoUpdate.
  5. All names are case sensitive.
  6. Now, go to the backup you have made, delete the file you have just uploaded and rename the backup back to SG_AutoUpdate.exe. Delete all other files. You should have one file named SG_AutoUpdate.exe and if you hoover the mouse over it, you should see the "BEFORE" image, maning the version should show:
  7. Double click it and after a few seconds you will find out it was updated to You can check the version string to verify that. 

But let's make sure the new version isn't downloaded again and won't cause endless "false positive" updates.

Now run the current SG_AutoUpdate.exe again. You will find that it reports that there isn't an update in the server. We are done.

I made a small video showing the entire process. Please take a close look at the "Program Version" column in the File Explorer.


Update (Supports UAC)

Following a questions by David Zaccanti, this method of automatic updating supports applications that require elevation, i.e. prompting the user to approve Administration Privileges. I have updated the source code and the new version on the server (which the program updates to) so they both require Administration privileges. When you compile the source code and running version it will display the UAC Prompt, however after silently updating to version, no elevation prompt will appear, as an elevated process can start another elevated process using CreateProcess() with no elevation prompt.

Left to be done...

There are several enhancements which aren't part of this code but can be developed:

- Adding a Log() function to allow you to redirect all "wprintf" calls into one log file shared by all variants of the program during the auto update process. 

- Allowing automatic update to a version that comes after the next one, for example going from to 

- Adding an automatic version updater to the post-build section of the project, which will allow an automatic promotion of the current version.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
CEO Secured Globe, Inc.
United States United States
Michael Haephrati is a music composer, an inventor and an expert specializes in software development and information security, who has built a unique perspective which combines technology and the end user experience. He is the author of a the book Learning C++ , which teaches C++ 20, and was published in August 2022.

He is the CEO of Secured Globe, Inc., and also active at Stack Overflow.

Read our Corporate blog or read my Personal blog.

Comments and Discussions

PraiseWell done ! Pin
RickZeeland16-Sep-17 8:18
mveRickZeeland16-Sep-17 8:18 
GeneralRe: Well done ! Pin
Michael Haephrati18-Sep-17 3:28
mvaMichael Haephrati18-Sep-17 3:28 
GeneralRe: Well done ! Pin
ehaerim19-Mar-19 18:37
ehaerim19-Mar-19 18:37 
AnswerRe: Well done ! Pin
Michael Haephrati19-Mar-19 19:03
mvaMichael Haephrati19-Mar-19 19:03 
Questionis it feasible for .NET application? Pin
Southmountain15-Sep-17 8:17
Southmountain15-Sep-17 8:17 
AnswerRe: is it feasible for .NET application? Pin
Michael Haephrati18-Sep-17 3:28
mvaMichael Haephrati18-Sep-17 3:28 
AnswerRe: is it feasible for .NET application? Pin
Michael Haephrati21-Mar-19 17:13
mvaMichael Haephrati21-Mar-19 17:13 
QuestionUser right Pin
Davide Zaccanti13-Sep-17 19:45
Davide Zaccanti13-Sep-17 19:45 
Do you have a solution (like running the new temp instance with admin rights using a user created for the software that can have admin privileges on c:\program files\mysoftwaredir) in case (mosto often) when the users have no write rights on dirs and in OS like W10 where you need always elevation even if part of admin Group ?

all our users run at user level with UAC

AnswerRe: User right Pin
Michael Haephrati14-Sep-17 12:51
mvaMichael Haephrati14-Sep-17 12:51 
AnswerRe: User right Pin
Theo Buys18-Sep-17 5:12
Theo Buys18-Sep-17 5:12 
GeneralRe: User right Pin
Michael Haephrati18-Sep-17 23:54
mvaMichael Haephrati18-Sep-17 23:54 
AnswerRe: User right Pin
Michael Haephrati19-Sep-17 0:03
mvaMichael Haephrati19-Sep-17 0:03 
GeneralMy vote of 5 Pin
Kewin Rausch12-Sep-17 20:59
professionalKewin Rausch12-Sep-17 20:59 
GeneralRe: My vote of 5 Pin
Michael Haephrati13-Sep-17 0:14
mvaMichael Haephrati13-Sep-17 0:14 
GeneralMy vote of 5 Pin
Jim Forst11-Sep-17 20:03
Jim Forst11-Sep-17 20:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.