Version Checking of Redistributable Files
Important This document may not represent best practices for current development, links to downloads and other resources may no longer be valid. Current recommended version can be found here. ArchiveDisclaimer

Version Checking of Redistributable Files

It is important to install a newer version of a file and not an older one. For example, you will want to install a newer version of a DLL or component on top of an older version, but not an older version on top of a newer version. System DLLs (for example, Kernel32.dll, User32.dll, Ole32.dll, ShDocVW.dll, and so on) are not to be redistributed. If you have to redistribute any files, make sure to read the corresponding license agreements and ensure that the files can be redistributed for corresponding OS versions and location of the installation. Typically, version checking is the responsibility of the Setup program.

If you write your own custom Setup program, it needs to manually check the version when installing redistributable files. This topic includes a sample program that checks for version numbers or, if version numbers are missing from a file, timestamps.

Version Checking Sample

// checkversion.cpp
// compile with: /link version.lib

#include <windows.h>
#include <stdio.h>

void EmitErrorMsg (HRESULT hr);
HRESULT GetFileVersion (char *filename, VS_FIXEDFILEINFO *vsf);
HRESULT GetFileDate (char *filename, FILETIME *pft);
HRESULT LastError();
int WhichIsNewer (char *fname1, char *fname2);

void printtime (FILETIME *t) {

   FILETIME lft;
   FILETIME *ft = &lft;
   printf("%08x %08x",ft->dwHighDateTime,ft->dwLowDateTime); {
      SYSTEMTIME stCreate;
      BOOL bret = FileTimeToSystemTime(ft,&stCreate);
      printf("    %02d/%02d/%d  %02d:%02d:%02d\n",
      stCreate.wMonth, stCreate.wDay, stCreate.wYear,
      stCreate.wHour, stCreate.wMinute, stCreate.wSecond);

int main(int argc, char* argv[]) {
    printf("usage: checkversion file1 file2\n"
      "\tReports which file is newer, first by checking the file version in "
      "\tthe version resource, then by checking the date\n\n" );

   if (argc != 3) 
      return 1;

   int newer = WhichIsNewer(argv[1],argv[2]);
   switch(newer) {
      case 1:
      case 2: printf("%s is newer\n",argv[newer]); break;
      case 3: printf("they are the same version\n"); break;
      case 0:
      default: printf("there was an error\n"); break;

   return !newer;

int WhichIsNewer (char *fname1, char *fname2) {
   // 1 if argv[1] is newer
   // 2 if argv[2] is newer
   // 3 if they are the same version
   // 0 if there is an error

   int ndxNewerFile;
   HRESULT ret;
   VS_FIXEDFILEINFO vsf1,vsf2;

   if ( SUCCEEDED((ret=GetFileVersion(fname1,&vsf1))) && SUCCEEDED((ret=GetFileVersion(fname2,&vsf2)))) {
      // both files have a file version resource
      // compare by file version resource
      if (vsf1.dwFileVersionMS > vsf2.dwFileVersionMS) {
         ndxNewerFile = 1;
         if (vsf1.dwFileVersionMS < vsf2.dwFileVersionMS) {
            ndxNewerFile = 2;
         else {   // if (vsf1.dwFileVersionMS == vsf2.dwFileVersionMS)
            if (vsf1.dwFileVersionLS > vsf2.dwFileVersionLS) {
               ndxNewerFile = 1;
            else if (vsf1.dwFileVersionLS < vsf2.dwFileVersionLS) {
               ndxNewerFile = 2;
            else {   // if (vsf1.dwFileVersionLS == vsf2.dwFileVersionLS)
               ndxNewerFile = 3;

   else {
      // compare by date
      FILETIME ft1,ft2;
      if (SUCCEEDED((ret=GetFileDate(fname1,&ft1))) && SUCCEEDED((ret=GetFileDate(fname2,&ft2))))
         LONG x = CompareFileTime(&ft1,&ft2);
         if (x == -1) 
            ndxNewerFile = 2;
            if (x == 0) 
               ndxNewerFile = 3;
               if (x == 1) ndxNewerFile = 1;
               else {
                  return 0;
      else {
         return 0;
   return ndxNewerFile;

HRESULT GetFileDate (char *filename, FILETIME *pft) {
   // we are interested only in the create time
   // this is the equiv of "modified time" in the 
   // Windows Explorer properties dialog
   FILETIME ct,lat;
   if (hFile == INVALID_HANDLE_VALUE) 
      return LastError();
   BOOL bret = GetFileTime(hFile,&ct,&lat,pft);
   if (bret == 0) 
      return LastError();
   return S_OK;

// This function gets the file version info structure
HRESULT GetFileVersion (char *filename, VS_FIXEDFILEINFO *pvsf) {
   DWORD dwHandle;
   DWORD cchver = GetFileVersionInfoSize(filename,&dwHandle);
   if (cchver == 0) 
      return LastError();
   char* pver = new char[cchver];
   BOOL bret = GetFileVersionInfo(filename,dwHandle,cchver,pver);
   if (!bret) 
      return LastError();
   UINT uLen;
   void *pbuf;
   bret = VerQueryValue(pver,"\\",&pbuf,&uLen);
   if (!bret) 
      return LastError();
   delete[] pver;
   return S_OK;

HRESULT LastError () {
   HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
   if (SUCCEEDED(hr)) 
      return E_FAIL;
   return hr;

// This little function emits an error message based on WIN32 error messages
void EmitErrorMsg (HRESULT hr) {
   char szMsg[1024];

See Also

Redistributing a Native C++ Application

© 2015 Microsoft