5,317,598 members and growing! (24,258 online)
Email Password   helpLost your password?
Languages » C / C++ Language » General     Intermediate

Retrieving version information from your local application's resource

By luetz

Sample code to retrieve version information from your local application
VC6, C++Windows, NT4, Win2K, WinXP, Win2003VS6, Visual Studio, Dev

Posted: 22 Oct 2004
Updated: 22 Oct 2004
Views: 34,572
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
20 votes for this Article.
Popularity: 5.23 Rating: 4.02 out of 5
1 vote, 5.0%
1
3 votes, 15.0%
2
1 vote, 5.0%
3
3 votes, 15.0%
4
12 votes, 60.0%
5

Sample Image - Version.gif

Introduction

This application contains a small class supporting access to the version information stored in YOUR OWN Win32 application.

Background

There is a lot code around the Internet, showing how easy it is to retrieve version information from any EXE or DLL. I never really liked the idea, opening my own application's file again (using GetFileVersionInfo()) simply to be able to access my local version data.

It took me quite some searching and other people's free source code to understand how this information may be retrieved from the local application's resource (equivalent to CString::LoadString() etc.).

Using the code

First of all: Be happy to use this code to your convenience and modify/enhance it as you like.

This is what you have to do 1. Add version.lib to your project's libraries 2. Add "#include <winver.h>" to your stdafx.h (could also be included to CGlobalFunctions.cpp instead) 3. Add GlobalFunctions.h and CGlobalFunctions.cpp to your project 4. Call any of the static functions from anywhere in your application

GlobalFunctions.h:

class CGlobalFunctions  : public CObject
{
public:
    CGlobalFunctions();
    virtual ~CGlobalFunctions();
public:
    static CString GetFileVersionX();
    static CString GetProductVersionX();
    static CString GetVersionInfo(HMODULE hLib, CString csEntry);
    static CString FormatVersion(CString cs);

private:
    static CString m_csFileVersion;
    static CString m_csProductVersion;
};

GlobalFunctions.cpp: (see source code for more detailed description of the methods)

String CGlobalFunctions::m_csFileVersion;
CString CGlobalFunctions::m_csProductVersion;

CGlobalFunctions::CGlobalFunctions()
{

}

CGlobalFunctions::~CGlobalFunctions()
{

}
// This is the key method

CString CGlobalFunctions::GetVersionInfo(HMODULE hLib, CString csEntry)
{
  CString csRet;

  if (hLib == NULL)
    hLib = AfxGetResourceHandle();
  
  HRSRC hVersion = FindResource( hLib, 
    MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION );
  if (hVersion != NULL)
  {
    HGLOBAL hGlobal = LoadResource( hLib, hVersion ); 
    if ( hGlobal != NULL)  
    {  
  
      LPVOID versionInfo  = LockResource(hGlobal);  
      if (versionInfo != NULL)
      {
        DWORD vLen,langD;
        BOOL retVal;    
    
        LPVOID retbuf=NULL;
    
        static char fileEntry[256];

        sprintf(fileEntry,"\\VarFileInfo\\Translation");
        retVal = VerQueryValue(versionInfo,fileEntry,&retbuf,(UINT *)&vLen);
        if (retVal && vLen==4) 
        {
          memcpy(&langD,retbuf,4);            
          sprintf(fileEntry, "\\StringFileInfo\\%02X%02X%02X%02X\\%s",
                  (langD & 0xff00)>>8,langD & 0xff,(langD & 0xff000000)>>24, 
                  (langD & 0xff0000)>>16, csEntry);            
        }
        else 
          sprintf(fileEntry, "\\StringFileInfo\\%04X04B0\\%s", 
            GetUserDefaultLangID(), csEntry);

        if (VerQueryValue(versionInfo,fileEntry,&retbuf,(UINT *)&vLen)) 
          csRet = (char*)retbuf;
      }
    }

    UnlockResource( hGlobal );  
    FreeResource( hGlobal );  
  }

  return csRet;
}

// Re-formats a string formatted as "m,n,o,p" to format as "m.nop"

CString CGlobalFunctions::FormatVersion(CString cs)
{
  CString csRet;
  if (!cs.IsEmpty())
  {
    cs.TrimRight();
    int iPos = cs.Find(',');
    if (iPos == -1)
      return "";
    cs.TrimLeft();
    cs.TrimRight();
    csRet.Format("%s.", cs.Left(iPos));

    while (1)
    {
      cs = cs.Mid(iPos + 1);
      cs.TrimLeft();
      iPos = cs.Find(',');
      if (iPos == -1)
      {
        csRet +=cs;
        break;
      }
      csRet += cs.Left(iPos);
    }
  }

  return csRet;
}

// Loads "FileVersion" from resource formats it and keeps it in mind

CString CGlobalFunctions::GetFileVersionX()
{
  if (m_csFileVersion.IsEmpty())
  {
    CString csVersion = FormatVersion(GetVersionInfo(NULL, "FileVersion"));
    m_csFileVersion.Format("Version %s (Build %s)", 
      csVersion, GetVersionInfo(NULL, "SpecialBuild"));
  }

  return m_csFileVersion;
}

// Loads "ProductVersion" from resource formats it and keeps it in mind

CString CGlobalFunctions::GetProductVersionX()
{
  if (m_csProductVersion.IsEmpty())
    m_csProductVersion = FormatVersion(GetVersionInfo(NULL, "ProductVersion"));

  return m_csProductVersion;
}

Using it anywhere in the application: (e.g. in CGetVersionApp::InitInstance())

....
  CString cs;
  cs.Format("FileVersion: %s\nProductVersion: %s\nMyPrivateInfo: %s", 
             CGlobalFunctions::GetFileVersionX(), 
             CGlobalFunctions::GetProductVersionX(),
             CGlobalFunctions::GetVersionInfo(NULL, "MyPrivateInfo"));
 AfxMessageBox(cs);
....

Points of Interest

Well, if you take a close look (while debuging) at fileEntry your will notify it's containig "\StringFileInfo\040704B0\ProductVersion". Compare this path with the structure of Version in the *.rc-file. This makes clear how the access of the version information works:

GetVersion.rc:

... 
BEGIN
    BLOCK "StringFileInfo"
        BEGIN
        BLOCK "040704b0"
        BEGIN
            VALUE "Comments", "\0"
            VALUE "CompanyName", "\0"
            VALUE "FileDescription", "MFC-Anwendung GetVersion\0"
            VALUE "FileVersion", "1, 2, 3, a\0"
            VALUE "InternalName", "GetVersion\0"
            VALUE "LegalCopyright", "Copyright (C) 2004\0"
            VALUE "LegalTrademarks", "\0"
            VALUE "OriginalFilename", "GetVersion.EXE\0"
            VALUE "PrivateBuild", "\0"
            VALUE "ProductName", "Anwendung GetVersion\0"
            VALUE "ProductVersion", "1, 0, 0, a\0"
            VALUE "SpecialBuild", "2\0"
            VALUE "MyPrivateInfo", 
              "This is an privately defined version information\0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x407, 1200
    END
END

NOTE: I have extended the version information structure by an own entry ("MyPrivateInfo"). You may retrieve this information in the same way as you can using all the predefined entries.

List of predefined entries within the version information structure: Comments CompanyName FileDescription FileVersion InternalName LegalCopyright LegalTrademarks OriginalFilename PrivateBuild ProductName ProductVersion SpecialBuild

Further recommendation

As you know from Microsoft products, beside the version information they specify a build code e.g. (Build 1376). There is a free add-in for Visual C++ that automatically increments the "SpecialBuild" entry within your *.rc file. It has been developed by Mihai Filimon and is called IncPrivateBuild. Click here for more information. It comes with the source code an is a really cool tool.

Cheers and enjoy this code, Hartmut

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

About the Author

luetz



Occupation: Web Developer
Location: Germany Germany

Other popular C / C++ Language articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 17 of 17 (Total in Forum: 17) (Refresh)FirstPrevNext
Subject  Author Date 
News.NET Version for the samememberdB.9:55 30 Jun '08  
GeneralWrong method to get the version info that generates Access violationmemberalegall6664:33 13 Mar '08  
GeneralThanks a lotmember723Alex8:19 22 May '07  
GeneralAccess Violation::memberzwu_ca15:12 15 May '07  
GeneralRe: Access Violation::memberluetz21:53 15 May '07  
GeneralRe: Access Violation::memberKaniSDragon20:45 19 Oct '07  
GeneralThanks!memberentec_nhan19:09 2 May '07  
GeneralRe: Thanks!memberluetz22:03 15 May '07  
GeneralVerQueryValue failsmemberrumblef6:29 23 Jun '05  
GeneralAdd the logic of removing trailing zeros from version in FormatVersionmembersonawane ajay21:39 7 Mar '05  
GeneralRe: Add the logic of removing trailing zeros from version in FormatVersionmembert0671dl6:43 20 Jun '05  
GeneralRe: Add the logic of removing trailing zeros from version in FormatVersionmembersonawane ajay19:37 20 Jun '05  
GeneralWow!suss309DA944-69E5-4f18-9E33-56D805BE5BD110:05 13 Jan '05  
GeneralMemory Faultmembercoferm6:39 28 Oct '04  
GeneralRe: Memory Faultmemberfazorin1:27 2 Nov '04  
GeneralNicememberJiju George T16:01 27 Oct '04  
GeneralThanks for the code!memberRolando E. Cruz-Marshall3:40 26 Oct '04  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

PermaLink | Privacy | Terms of Use
Last Updated: 22 Oct 2004
Editor: Nishant Sivakumar
Copyright 2004 by luetz
Everything else Copyright © CodeProject, 1999-2008
Web19 | Advertise on the Code Project