Click here to Skip to main content
15,867,704 members
Articles / Programming Languages / C++
Article

Determining the version number of a DLL or Executable

,
Rate me:
Please Sign up or sign in to vote.
4.56/5 (10 votes)
10 Jan 2000 167.5K   43   10
A class that allows you to determine the version of a DLL or EXE at run-time

Introduction

There are many instances where it is necessary to know which version of a DLL you are using. For instance, the commctrl32.dll that drives the main Windows GUI is notorious for changing with every incarnation of Internet Explorer. While it is nice to be able to use the new features of the updated DLL, it is wise to check that the particular version of that DLL is on the machine before you start using it. This will avoid embarrassing crashes in your programs.

The following class retrieves the DLL versions. It is based on the original code by Eran Yariv, and has been updated by Kenneth Lea (with help from John Allen Booth so that it will work with Executables as well

Header File

// DLLVersion.h: interface for the CDLLVersion class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_DLLVERSION_H__88B3F8C1_27F2_11D3_80A3_0090276F9F55__INCLUDED_)
#define AFX_DLLVERSION_H__88B3F8C1_27F2_11D3_80A3_0090276F9F55__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
/*  For some odd reason, Microsoft published a sample code that uses shlwapi.h 
    (and shlwapi.lib)
    to tinker file versions.

    This header file could not be found anywhere !!!
    Not in Visual C++ 4.2, Visual C++ 5.0 or MSDN versions up to July 97`.

    So, I just took out the interesting structures from scraps I found 
    and re-defined them here.
*/


//  Remember: You must link version.lib to the project for this class to work !!


#ifndef _DLL_VERSION_H_
#define _DLL_VERSION_H_

#ifndef DLLVERSIONINFO
typedef struct _DllVersionInfo
{
    DWORD cbSize;
    DWORD dwMajorVersion;
    DWORD dwMinorVersion;
    DWORD dwBuildNumber;
    DWORD dwPlatformID;
}DLLVERSIONINFO;
 
#endif

#ifndef DLLGETVERSIONPROC
typedef int (FAR WINAPI *DLLGETVERSIONPROC) (DLLVERSIONINFO *);
#endif

class CDLLVersion
{
    typedef enum {  WIN_DIR, // Windows directory (e.g.: "C:\Windows\")
                    SYS_DIR, // Windows system directory (e.g.: "C:\Windows\System")
                    CUR_DIR, // Current directory (e.g.: ".")
                    NO_DIR}  // No directory (path in file name)
    FileLocationType;        // Possible ways to add a path prefix to a file

public:
    
    CDLLVersion (LPSTR szDLLFileName) :
        m_dwMajor (0),
        m_dwMinor (0),
        m_dwBuild (0)
    {
        m_bValid = GetDLLVersion (szDLLFileName, m_dwMajor, m_dwMinor, m_dwBuild);
    }
        

    virtual ~CDLLVersion () {};

    DWORD GetMajorVersion ()
    {
        return m_dwMajor;
    }

    DWORD GetMinorVersion ()
    {
        return m_dwMinor;
    }

    DWORD GetBuildNumber ()
    {
        return m_dwBuild;
    }

    BOOL IsValid ()
    {
        return m_bValid;
    }

    CString GetFullVersion()
    {
        return m_stFullVersion;
    }

private:

    char *getVersion(char *fileName);
    
    BOOL GetDLLVersion (LPSTR szDLLFileName, 
                        DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);

    BOOL CheckFileVersion (LPSTR szFileName, int FileLoc, 
                           DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);

    BOOL ParseVersionString (LPSTR lpVersion, 
                             DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber);
    BOOL ParseVersionString1 (LPSTR lpVersion, 
                              DWORD &dwMajor, DWORD &dwMinor, 
                              DWORD &dwBuildNumber);

    BOOL FixFilePath (char * szFileName, int FileLoc);

    DWORD   m_dwMajor,      // Major version number
            m_dwMinor,      // Minor version number
            m_dwBuild;      // Build number
    BOOL    m_bValid;       // Is the DLL version information valid ?
    CString m_stFullVersion;
};

#endif

#endif // !defined(AFX_DLLVERSION_H__88B3F8C1_27F2_11D3_80A3_0090276F9F55__INCLUDED_)

The Version cpp file

// DLLVersion.cpp: implementation of the CDLLVersion class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "DLLVersion.h"
#include "Global.h"
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

/***************************************************************************

   Function:   GetDLLVersion

   Purpose:    Retrieves DLL major version, minor version and build numbers

   Input:      DLL file name
               Reference to Major number 
               Reference to Minor number 
               Reference to Build number 

   Output:     TRUE only if successful

   Remarks:    This function first tries to get the DLL version the nice way,
               that is, call the DllGetVersion function in the DLL.

               If this fails, it tries to located the DLL file in the file system,
               read the file information block and retrieve the file version.

****************************************************************************/
BOOL CDLLVersion::GetDLLVersion (LPSTR szDLLFileName, 
                                 DWORD &dwMajor, DWORD &dwMinor, DWORD &dwBuildNumber)
{
HINSTANCE   hDllInst;           // Instance of loaded DLL
char szFileName [_MAX_PATH];    // Temp file name

BOOL bRes = TRUE;               // Result


    lstrcpy (szFileName, szDLLFileName);    // Save a file name copy for the loading
    
    
    hDllInst = LoadLibrary(TEXT(szFileName));   //load the DLL


    if(hDllInst)   // Could successfully load the DLL
    {
        DLLGETVERSIONPROC pDllGetVersion;
        /*
        You must get this function explicitly because earlier versions of the DLL 
        don't implement this function. That makes the lack of implementation of the 
        function a version marker in itself.
        */
        pDllGetVersion = (DLLGETVERSIONPROC) GetProcAddress(hDllInst,
                          TEXT("DllGetVersion"));
   
        if(pDllGetVersion)     // DLL supports version retrieval function
        {
            DLLVERSIONINFO    dvi;

            ZeroMemory(&dvi, sizeof(dvi));
            dvi.cbSize = sizeof(dvi);
            HRESULT hr = (*pDllGetVersion)(&dvi);

            if(SUCCEEDED(hr))  // Finally, the version is at our hands
            {
                dwMajor = dvi.dwMajorVersion;
                dwMinor = dvi.dwMinorVersion;
                dwBuildNumber = dvi.dwBuildNumber;
            }
            else
                bRes = FALSE;   // Failure
        } 
        else  // GetProcAddress failed, the DLL cannot tell its version
            bRes = FALSE;       // Failure

        FreeLibrary(hDllInst);  // Release DLL
    }
    else  
        bRes = FALSE;   // DLL could not be loaded

    if (!bRes) // Cannot read DLL version the nice way
    {
        for(int iDir = WIN_DIR; iDir <= NO_DIR; iDir++) // loop for each possible directory
        {
            lstrcpy (szFileName, szDLLFileName);    // Save a file name copy for the loading
            bRes = CheckFileVersion (szFileName, iDir, 
                                     dwMajor, dwMinor, dwBuildNumber); // Try the ugly way
            if(bRes)
                break;
        };
    return bRes;
    }
    else
        return TRUE;
}

/***************************************************************************

   Function:   CheckFileVersion

   Purpose:    Check the version information of a given file

   Input:      File name
               File location (Windows dir, System dir, Current dir or none)
               Reference to Major number 
               Reference to Minor number 
               Reference to Build number 

   Output:     TRUE only if successful

   Remarks:    Trashes original file name

****************************************************************************/
BOOL CDLLVersion::CheckFileVersion (LPSTR szFileName, int FileLoc, 
                                    DWORD &dwMajor, DWORD &dwMinor, 
                                    DWORD &dwBuildNumber)
{
LPSTR   lpVersion;                        // String pointer to 'version' text
//UINT    uVersionLen;
DWORD   dwVerHnd=0;                        // An 'ignored' parameter, always '0'
//VS_FIXEDFILEINFO vsFileInfo;

    FixFilePath (szFileName, FileLoc);  // Add necessary path prefix to file name

    DWORD dwVerInfoSize = GetFileVersionInfoSize (szFileName, &dwVerHnd);
    if (!dwVerInfoSize)     // Cannot reach the DLL file
        return FALSE;

    LPSTR lpstrVffInfo = (LPSTR) malloc (dwVerInfoSize);  // Alloc memory for file info
    if (lpstrVffInfo == NULL)
        return FALSE;   // Allocation failed

        // Try to get the info
    if (!GetFileVersionInfo(szFileName, dwVerHnd, dwVerInfoSize, lpstrVffInfo)) 
    {
        free (lpstrVffInfo);
        return FALSE;   // Cannot read the file information - 
                        // wierd, since we could read the information size
    }

    /* The below 'hex' value looks a little confusing, but
       essentially what it is, is the hexidecimal representation
       of a couple different values that represent the language
       and character set that we are wanting string values for.
       040904E4 is a very common one, because it means:
       US English, Windows MultiLingual characterset
       Or to pull it all apart:
       04------        = SUBLANG_ENGLISH_USA
       --09----        = LANG_ENGLISH
       ----04E4 = 1252 = Codepage for Windows:Multilingual
    */
    /*static char fileVersion[256];
    LPVOID version=NULL;
    DWORD vLen,langD;
    BOOL retVal;

    sprintf(fileVersion,"\\VarFileInfo\\Translation");
    retVal = VerQueryValue ( lpstrVffInfo,  
                             fileVersion, &version, (UINT *)&uVersionLen);
    if (retVal && vLen==4)
    {
        memcpy(&langD,version,4);
        sprintf(fileVersion, "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion",
                (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24, 
                (langD & 0xff0000)>>16);            
    }
    else 
        sprintf(fileVersion,"\\StringFileInfo\\%04X04B0\\FileVersion",GetUserDefaultLangID());

    if (!VerQueryValue (    lpstrVffInfo, fileVersion, 
                (LPVOID *)&lpVersion, (UINT *)&uVersionLen))
        {    
        free (lpstrVffInfo);
        return FALSE;     // Query was unsuccessful    
        }
    */
    // Now we have a string that looks like this :
    // "MajorVersion.MinorVersion.BuildNumber", so let's parse it
    lpVersion = getVersion(szFileName);
    m_stFullVersion = getVersion(szFileName);
    BOOL bRes = ParseVersionString (lpVersion, dwMajor, dwMinor, dwBuildNumber);
    if(!bRes)
        // Lets try for commas
        bRes = ParseVersionString1 (lpVersion, dwMajor, dwMinor, dwBuildNumber);
    free (lpstrVffInfo);
    return bRes;
}

/***************************************************************************

   Function:   ParseVersionString

   Purpose:    Parse version information string into 3 different numbers

   Input:      The version string formatted as "MajorVersion.MinorVersion.BuildNumber"
               Reference to Major number 
               Reference to Minor number 
               Reference to Build number 

   Output:     TRUE only if successful

   Remarks:    

****************************************************************************/
BOOL CDLLVersion::ParseVersionString (LPSTR lpVersion, 
                                      DWORD &dwMajor, DWORD &dwMinor, 
                                      DWORD &dwBuildNumber)
{
    // Get first token (Major version number)
    LPSTR token = strtok( lpVersion, TEXT (".") );  
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwMajor = atoi (token);

    token = strtok (NULL, TEXT ("."));  // Get second token (Minor version number)
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwMinor = atoi (token);

    token = strtok (NULL, TEXT ("."));  // Get third token (Build number)
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwBuildNumber = atoi (token);

    return TRUE;
}


/***************************************************************************

   Function:   FixFilePath

   Purpose:    Adds the correct path string to a file name according 
               to given file location 

   Input:      Original file name
               File location (Windows dir, System dir, Current dir or none)

   Output:     TRUE only if successful

   Remarks:    Trashes original file name

****************************************************************************/
BOOL CDLLVersion::FixFilePath (char * szFileName, int FileLoc)
{
    char    szPathStr [_MAX_PATH];      // Holds path prefix
   
    switch (FileLoc) 
    {
        case WIN_DIR:
            // Get the name of the windows directory
            if (GetWindowsDirectory (szPathStr, _MAX_PATH) ==  0)  
                return FALSE;   // Cannot get windows directory
            break;

        case SYS_DIR:
            // Get the name of the windows SYSTEM directory
            if (GetSystemDirectory (szPathStr, _MAX_PATH) ==  0)  
                return FALSE;   // Cannot get system directory
            break;

        case CUR_DIR:
            // Get the name of the current directory
            if (GetCurrentDirectory (_MAX_PATH, szPathStr) ==  0)  
                return FALSE;   // Cannot get current directory
            break;

        case NO_DIR:
            lstrcpy (szPathStr,"");
            break;

        default:
            return FALSE;
    }
    lstrcat (szPathStr, _T("\\"));
    lstrcat (szPathStr, szFileName);
    lstrcpy (szFileName, szPathStr);
    return TRUE;
}            



/***************************************************************************

   Function:   ParseVersionString

   Purpose:    Parse version information string into 3 different numbers

   Input:      The version string formatted as "MajorVersion.MinorVersion.BuildNumber"
               Reference to Major number 
               Reference to Minor number 
               Reference to Build number 

   Output:     TRUE only if successful

   Remarks:    

****************************************************************************/
BOOL CDLLVersion::ParseVersionString1 (LPSTR lpVersion, 
                                      DWORD &dwMajor, DWORD &dwMinor, 
                                      DWORD &dwBuildNumber)
{
    // Get first token (Major version number)
    LPSTR token = strtok( lpVersion, TEXT (",") );  
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwMajor = atoi (token);

    token = strtok (NULL, TEXT (","));  // Get second token (Minor version number)
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwMinor = atoi (token);

    token = strtok (NULL, TEXT (","));  // Get third token (Build number)
    if (token == NULL)  // End of string
        return FALSE;       // String ended prematurely
    dwBuildNumber = atoi (token);

    return TRUE;
}



// a static buffer is used to hold the version, calling this function
// a second time will erase previous information.
// long paths may be used for this function.
char *CDLLVersion::getVersion(char *fileName)
{
    DWORD vSize;
    DWORD vLen,langD;
    BOOL retVal;    
    
    LPVOID version=NULL;
    LPVOID versionInfo=NULL;
    static char fileVersion[256];
    bool success = true;
    vSize = GetFileVersionInfoSize(fileName,&vLen);
    if (vSize) 
    {
        versionInfo = malloc(vSize+1);
        if (GetFileVersionInfo(fileName,vLen,vSize,versionInfo))
        {            
            sprintf(fileVersion,"\\VarFileInfo\\Translation");
            retVal = VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen);
            if (retVal && vLen==4) 
            {
                memcpy(&langD,version,4);            
                sprintf(fileVersion, "\\StringFileInfo\\%02X%02X%02X%02X\\FileVersion",
                        (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24, 
                        (langD & 0xff0000)>>16);            
            }
            else 
                sprintf(fileVersion, "\\StringFileInfo\\%04X04B0\\FileVersion",
                        GetUserDefaultLangID());
            retVal = VerQueryValue(versionInfo,fileVersion,&version,(UINT *)&vLen);
            if (!retVal) success = false;
        }
    else 
            success = false;
    }
    else 
        success=false;    
    
    if (success) 
    {
        if (vLen<256)
            strcpy(fileVersion,(char *)version);
        else 
        {
            strncpy(fileVersion,(char *)version,250);
            fileVersion[250]=0;            
        }
        if (versionInfo) free(versionInfo);
        versionInfo = NULL;
        return fileVersion;
    }
    else 
    {
        if (versionInfo) free(versionInfo);
        versionInfo = NULL;
        return NULL;    
    }
}

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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionWhat if the DLL has more than three number in version info Pin
Thuc.Nguyen6-Nov-03 16:01
professionalThuc.Nguyen6-Nov-03 16:01 
Hi man,
I noticed that you just get the first three numbers in the version string. An official application/DLL normally has 4 number. So I don't know if you consider this.

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.