Click here to Skip to main content
15,868,016 members
Articles / Desktop Programming / MFC

CFileVersionInfo - Getting the File Version Information

Rate me:
Please Sign up or sign in to vote.
4.84/5 (52 votes)
29 Mar 2004CPOL5 min read 2.3M   8.7K   107   25
Class for getting file version information
This class wraps the GetFileVersionInfo, GetFileVersionInfoSize, VerQueryValue, and VerLanguageName API functions and can be used to determine full file version information.

Introduction

You can use this class to determine a full file version information, in any file that has version information resource, such as dynamic-link libraries (DLLs), executable files, font files, OCX files, etc., including version information blocks in multiple languages. This class wraps the GetFileVersionInfo, GetFileVersionInfoSize, VerQueryValue, and VerLanguageName API functions. See sample image below:

Background

Once developing a DLL file, I wanted to implement DllGetVersion function in it (it returns the version of the DLL, if requested, see Platform SDK). Of course, I could return fixed version numbers from my implementation of it, but in that case, they would become wrong even after a single rebuild (I used version auto increment in that project). So I decided to use the API version information functions - i.e., read version information from the file version information resource and return it every time it was requested - and implemented CFileVersionInfo class.

Sample Usage

In this sample, we query the Shell32.dll version information (we'll get something in this format: "6.0.2600.0") and its company name string (we'll get something like "Microsoft Corporation"):

C++
//...
#ifndef __VERINFO_H__
    #include < verinfo.h >
#endif
//...

CFileVersionInfo fvi;
if( fvi.Open( _T( "shell32.dll" ) )
{
    TCHAR szVer[ 512 ] = { 0 };
    ::wsprintf( szVer, 
        _T( "%d.%d.%d.%d" ),
        fvi.GetFileVersionMajor(),  // Major version
        fvi.GetFileVersionMinor(),  // Minor version
        fvi.GetFileVersionBuild(),  // Build number
        fvi.GetFileVersionQFE()     // QFE
    );

    /*
    VS_FIXEDFILEINFO vsffi = m_fvi.GetVSFFI();
    ::wsprintf( szVer, 
        _T( "%d.%d.%d.%d" ),
        HIWORD( vsffi.dwFileVersionMS ),  // Major version
        LOWORD( vsffi.dwFileVersionMS ),  // Minor version
        HIWORD( vsffi.dwFileVersionLS ),  // Build number
        LOWORD( vsffi.dwFileVersionLS )   // QFE
    );
    */
    
    ::SetWindowText( hWndVersion, szVer );

    if( fvi.QueryStringValue( VI_STR_COMPANYNAME, szVer, 512 ) )
        ::SetWindowText( hWndCompName, szVer );

//...

    fvi.Close();
}
//...

Translation Support

If application or DLL supports a list of languages (multi-language version info blocks), instead of using multiple version resources (for each language), you can use this class to get data from them separately, depending on the language identifier and code page:

In the sample application, three different language and code page string table version blocks are provided, you can test them all. See the image before selection (above) and after it (below):

Class Members

Base Class

  • Does not have a base class

Construction

  • CFileVersionInfo( void ) - Constructs a CFileVersionInfo object

Operations

  • BOOL Open( IN LPCTSTR lpszFileName ) - Opens the file version information by its name specified in lpszFileName
  • BOOL Open( IN HMODULE hModule )- Opens the file version information by its handle specified in hModule
  • void Close( void ) - Closes the specified module and frees the resources, loaded by Open method(s)
  • BOOL IsValid( void ) - Queries, whether the class internal data is valid

Version Information Retrieval

  • BOOL QueryStringValue( IN LPCTSTR lpszString, OUT LPTSTR lpszValue, IN INT nBuf ) const - Retrieves a value in a StringTable structure, and returns it in the nBuf size lpszValue buffer. The lpszString name must be one of the predefined strings, enumerated in the next function description. For example: m_ver.QueryStringValue( _T( "Comments" ), szBuf, 512 );.
    NOTE: It is better you use the second version of this function, explained below.
  • BOOL QueryStringValue( IN INT nIndex, OUT LPTSTR lpszValue, IN INT nBuf ) const - Retrieves a value in a StringTable structure, and returns it in the nBuf size lpszValue buffer. The nIndex name must be one of the following predefined constants:
    • VI_STR_COMMENTS - Comments
    • VI_STR_COMPANYNAME - CompanyName
    • VI_STR_FILEDESCRIPTION - FileDescription
    • VI_STR_FILEVERSION - FileVersion
    • VI_STR_INTERNALNAME - InternalName
    • VI_STR_LEGALCOPYRIGHT - LegalCopyright
    • VI_STR_LEGALTRADEMARKS - LegalTrademarks
    • VI_STR_ORIGINALFILENAME - OriginalFilename
    • VI_STR_PRIVATEBUILD - PrivateBuild
    • VI_STR_PRODUCTNAME - ProductName
    • VI_STR_PRODUCTVERSION - ProductVersion
    • VI_STR_SPECIALBUILD - SpecialBuild
    • VI_STR_OLESELFREGISTER - OLESelfRegister

    For example: m_ver.QueryStringValue( VI_STR_SPECIALBUILD, szBuf, 512 );

  • const VS_FIXEDFILEINFO& GetVSFFI( void ) const - Retrieves the reference to the VS_FIXEDFILEINFO structure of the open file version information.
  • LPCTSTR GetVerStringName( IN INT nIndex ) - Returns the version string name for the nIndex parameter from the array - the class holds a static array of version information strings, each value of which can be accessed by index. For example: m_ver.GetVerStringName( VI_STR_PRODUCTNAME )will return a pointer to _T( "ProductName" ) string.
  • GetVersionMajor( void ) const - get major version
  • GetVersionMinor( void ) const - get minor version
  • GetVersionBuild( void ) const - get build version
  • GetVersionQFE( void ) const - get QFE version

Static Members

  • BOOL GetLIDName( IN WORD wLID, OUT LPTSTR lpszName, IN INT nBuf ) - Retrieves a description string for the wLID language identifier and returns it in the lpszName buffer of nBuf size.
  • BOOL GetCPName( IN WORD wCP, OUT LPCTSTR* ppszName ) - Retrieves a description string for the wCP code page identifier and returns it in the lpszName buffer of nBuf size.

Translation Methods

  • BOOL SetTrans ( IN LANGID wLID /*= LANG_NEUTRAL*/, IN WORD wCP /*= VI_CP_UNICODE*/ ) - Sets the Language Identifier and Code Page to use in the version information data (if any)
  • INT FindTrans( IN LANGID wLID, IN WORD wCP ) const - Finds the translation (the Language Identifier and Code Page) in the version information data, if any
  • BOOL SetTransIndex( IN UINT nIndex /*= 0*/ ) - Sets the translation to use in the version information data by index (if any)
  • DWORD GetTransByIndex( IN UINT nIndex ) const - Extracts the translation (the Language Identifier and Code Page) at the specified index in the translation array (if any)

Inline Translation Methods

  • UINT GetTransCount( void ) const - Returns the number of translations, i.e., number of concatenations of a language and code page identifies pairs found in the translation array for the resource.
  • UINT GetCurTransIndex( void ) const - Returns the current index of the translation index in the translation array of the version resource.
  • LANGID GetLIDByIndex( IN UINT nIndex ) const - Extracts the Language Identifier from the langid-codepage translation pair at the specified index in the array (if any).
  • WORD GetCPByIndex( IN UINT nIndex ) const - Extracts the Code Page identifier from the langid-codepage translation pair at the specified index in the array (if any).
  • DWORD GetCurTrans( void ) const - Returns the langid-codepage translation pair currently set as default in the class.
  • LANGID GetCurLID( void ) const - Returns the Language Identifier currently set as default in the class.
  • WORD GetCurCP( void ) const - Returns the Code Page currently set as default in the class.

Global Functions

  • STDAPI_( HRESULT ) DllGetVersion( IN HMODULE hModule, OUT DLLVERSIONINFO* lpDVI ) - You can use this function in the exported DllGetVersion of any of your DLLs to do the black work - return the pointer to DLLVERSIONINFO structure filled with your app version data. It uses the CFileVersionInfo class. See its implementation:
    C++
    //...
    #ifndef __VERINFO_H__
        #include < verinfo.h >
    #endif
    //...
    
    HRESULT STDAPICALLTYPE DllGetVersion( IN  HMODULE hModule, 
                                          OUT DLLVERSIONINFO* lpDVI )
    {
        if( hModule == NULL || 
            ::IsBadReadPtr( lpDVI, sizeof( DLLVERSIONINFO* ) ) )
        {
            ASSERT_RETURN( S_FALSE );
        }
        
        const DWORD cbSize = lpDVI->cbSize;
        
        if(
    #ifdef DLLVERSIONINFO2
            (
    #endif
            cbSize != sizeof( DLLVERSIONINFO  )
    #ifdef DLLVERSIONINFO2
            && cbSize != sizeof( DLLVERSIONINFO2 ) ) 
    #endif
            || ::IsBadWritePtr( lpDVI, cbSize ) )
        {
            ASSERT_RETURN( S_FALSE );
        }
        
        ::ZeroMemory( lpDVI, cbSize );
        lpDVI->cbSize = cbSize;
        
        CFileVersionInfo fvi;
        if( fvi.Open( hModule ) )
        {
            VS_FIXEDFILEINFO vsffi = fvi.GetVSFFI();
        
            if( vsffi.dwFileType == VFT_DLL ||
                vsffi.dwFileType == VFT_STATIC_LIB )
            {
                switch( vsffi.dwFileOS )
                {            
                case VOS__WINDOWS32:
                case VOS_NT_WINDOWS32:
                    lpDVI->dwPlatformID = DLLVER_PLATFORM_WINDOWS;
                    break;
                case VOS_NT:
                    lpDVI->dwPlatformID = DLLVER_PLATFORM_NT;
                    break;            
                default:
                    return ( S_FALSE );
                }
        
                lpDVI->dwMajorVersion = HIWORD( vsffi.dwFileVersionMS );
                lpDVI->dwMinorVersion = LOWORD( vsffi.dwFileVersionMS );
                lpDVI->dwBuildNumber  = HIWORD( vsffi.dwFileVersionLS );
        
            #ifdef DLLVERSIONINFO2
    
                if( cbSize == sizeof( DLLVERSIONINFO2 ) )
                {
                    DLLVERSIONINFO2* lpDVI2 = (DLLVERSIONINFO2*)lpDVI;
                    lpDVI2->ullVersion = MAKEDLLVERULL( 
                        lpDVI->dwMajorVersion,
                        lpDVI->dwMinorVersion,
                        lpDVI->dwBuildNumber ,
                        LOWORD( vsffi.dwFileVersionLS )
                    );
                }
        
            #endif
        
                return ( S_OK );
            }
        #ifdef _DEBUG
            else
                ASSERT( 0 );
        #endif
        
            fvi.Close();
        }
        
        return ( S_FALSE );
    }
    
    //...

Notes

This class is a generic class - you can include it in any type of project - in MFC/ATL/WTL/API EXE or DLL or some other type applications, it has no dependencies. It compiles with both ANSI and UNICODE at warning level 4.

History

  • 15th July, 2003
    • Posted article
  • 27th July, 2003
    • Removed VOS_DOS_WINDOWS32 from DllGetVersion file type detection
    • Updated DllGetVersion to support DLLVERSIONINFO2 structure
  • 21st January, 2004
    • Added GetFileVersionMajor, GetFileVersionMinor, GetFileVersionBuild, GetFileVersionQFE functions
  • 29th March, 2004
    • Added GetProductVersionMajor, GetProductVersionMinor, GetProductVersionBuild, GetProductVersionQFE functions

License

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


Written By
Software Developer (Senior) SafeNet Inc
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

 
Bugcan not work for some file Pin
xk8888888823-Jun-12 22:31
xk8888888823-Jun-12 22:31 
GeneralThanks Pin
dennislx10-Aug-10 11:53
professionaldennislx10-Aug-10 11:53 
GeneralThanks Pin
User 126615730-Oct-07 0:03
User 126615730-Oct-07 0:03 
Generalthanks Pin
Le Thanh Cong16-Apr-06 22:53
Le Thanh Cong16-Apr-06 22:53 
Generalthank you Pin
msanchezv30-Jan-06 1:19
msanchezv30-Jan-06 1:19 
Generalthanks! Pin
Ohad Redlich15-Jan-06 23:57
Ohad Redlich15-Jan-06 23:57 
GeneralLoading ALL strings from my stringtable Pin
Alex Evans4-May-05 15:04
Alex Evans4-May-05 15:04 
GeneralRe: Loading ALL strings from my stringtable Pin
Armen Hakobyan5-May-05 19:31
professionalArmen Hakobyan5-May-05 19:31 
GeneralRe: Loading ALL strings from my stringtable Pin
mmatitya12-Sep-06 4:16
mmatitya12-Sep-06 4:16 
GeneralRe: Loading ALL strings from my stringtable Pin
m.vinod8511-Jan-10 7:06
m.vinod8511-Jan-10 7:06 
GeneralRe: Loading ALL strings from my stringtable Pin
Armen Hakobyan13-Jan-10 3:52
professionalArmen Hakobyan13-Jan-10 3:52 
Generalread file attribute Pin
soccers30-Dec-04 18:57
soccers30-Dec-04 18:57 
GeneralRe: read file attribute Pin
Armen Hakobyan3-Jan-05 21:23
professionalArmen Hakobyan3-Jan-05 21:23 
GeneralRe: read file attribute Pin
germanrose22-Aug-06 23:47
germanrose22-Aug-06 23:47 
Generalgreat code Pin
Oleg Bykov24-Nov-03 23:02
Oleg Bykov24-Nov-03 23:02 
GeneralNot very pratical Pin
Xiaotian Guo29-Aug-03 21:08
Xiaotian Guo29-Aug-03 21:08 
GeneralRe: Not very pratical Pin
Armen Hakobyan30-Aug-03 1:01
professionalArmen Hakobyan30-Aug-03 1:01 
GeneralRe: Not very pratical Pin
Dheht4-Dec-03 12:28
Dheht4-Dec-03 12:28 
GeneralRe: Not very pratical Pin
Karl Josefsson5-Mar-04 7:14
Karl Josefsson5-Mar-04 7:14 
GeneralRe: Not very pratical Pin
Pete Goodsall8-Apr-04 9:41
Pete Goodsall8-Apr-04 9:41 
GeneralRe: Not very pratical AT ALL [modified] Pin
DennisKuhn4-Jul-06 12:55
DennisKuhn4-Jul-06 12:55 
Oh my god, it was so unpractical. I had to add ALL of the following lines of code by myself (to my app) !!

#include "FileVersionInfo.h"

void CPChamberDlg::setApplicationVersion()
{
CString sVersion;

CUtilsPackage::Version_u Version( 0 );

CFileVersionInfo VerInfo;

VerInfo.Open( AfxGetInstanceHandle() );

Version.nMajor = VerInfo.GetFileVersionMajor();
Version.nMinor = VerInfo.GetFileVersionMinor();
Version.nSub = VerInfo.GetFileVersionBuild();
Version.nPatch = VerInfo.GetFileVersionQFE();

sVersion.Format( "%d.%d.%d.%d",
Version.nMajor,
Version.nMinor,
Version.nSub,
Version.nPatch );

CUtilsPackage::setVersion( Version, m_AppCrypter.encrypt( sVersion ) );
}

Honestly, I am very pleased with this implementation. Very good and absolutly practical. Saved me a lot of boring time reading msdn.

Thanks a a lot for that

-- modified at 19:35 Tuesday 4th July, 2006
GeneralRe: Not very pratical AT ALL Pin
FS345984395810-Sep-06 7:08
FS345984395810-Sep-06 7:08 
Generalconst_cast -&gt; dangerous (crashes?) Pin
Karl98025-Aug-03 1:07
Karl98025-Aug-03 1:07 
GeneralNice! Pin
Robert Buldoc25-Jul-03 9:08
Robert Buldoc25-Jul-03 9:08 
GeneralVERY Nice! Pin
Snyp26-Jul-03 3:22
Snyp26-Jul-03 3:22 

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.