Get VersionInfo from resource file (2)

Roberto Rocco already give us a class to get version information from module resources (.exe, .dll, etc.) it works great for the fixed information but you have to know the language-charset of the module for retrieving language dependant information.

My class, CFileVersion, allow you to get fixed and the language dependant information. The class use the first language-charset available from the module, so you don't have to worry about it.

Some of the most use information have predefined method like GetFileVersion(), GetCompanyName(), etc. You can also use QueryValue() if you need to get uncommon or custom data, or if you really want to get data from a specific language-charset.

You don't have to explicitly add version.lib on your project setting, a pragma directive take care of it.

And now the class:

// FileVersion.h: interface for the CFileVersion class.
// by Manuel Laflamme
//////////////////////////////////////////////////////////////////////

#ifndef __FILEVERSION_H_
#define __FILEVERSION_H_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000

class CFileVersion
{ 
// Construction
public: 
    CFileVersion();

// Operations	
public: 
    BOOL    Open(LPCTSTR lpszModuleName);
    void    Close();

    CString QueryValue(LPCTSTR lpszValueName, DWORD dwLangCharset = 0);
    CString GetFileDescription()  {return QueryValue(_T("FileDescription")); };
    CString GetFileVersion()      {return QueryValue(_T("FileVersion"));     };
    CString GetInternalName()     {return QueryValue(_T("InternalName"));    };
    CString GetCompanyName()      {return QueryValue(_T("CompanyName"));     }; 
    CString GetLegalCopyright()   {return QueryValue(_T("LegalCopyright"));  };
    CString GetOriginalFilename() {return QueryValue(_T("OriginalFilename"));};
    CString GetProductName()      {return QueryValue(_T("ProductName"));     };
    CString GetProductVersion()   {return QueryValue(_T("ProductVersion"));  };

    BOOL    GetFixedInfo(VS_FIXEDFILEINFO& vsffi);
    CString GetFixedFileVersion();
    CString GetFixedProductVersion();

// Attributes
protected:
    LPBYTE  m_lpVersionData; 
    DWORD   m_dwLangCharset; 

// Implementation
public:
    ~CFileVersion(); 
}; 

#endif  // __FILEVERSION_H_




// FileVersion.cpp: implementation of the CFileVersion class.
// by Manuel Laflamme 
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "FileVersion.h"

#pragma comment(lib, "version")

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

//////////////////////////////////////////////////////////////////////

CFileVersion::CFileVersion() 
{ 
    m_lpVersionData = NULL;
    m_dwLangCharset = 0;
}

CFileVersion::~CFileVersion() 
{ 
    Close();
} 

void CFileVersion::Close()
{
    delete[] m_lpVersionData; 
    m_lpVersionData = NULL;
    m_dwLangCharset = 0;
}

BOOL CFileVersion::Open(LPCTSTR lpszModuleName)
{
    ASSERT(_tcslen(lpszModuleName) > 0);
    ASSERT(m_lpVersionData == NULL);

    // Get the version information size for allocate the buffer
    DWORD dwHandle;     
    DWORD dwDataSize = ::GetFileVersionInfoSize((LPTSTR)lpszModuleName, &dwHandle); 
    if ( dwDataSize == 0 ) 
        return FALSE;

    // Allocate buffer and retrieve version information
    m_lpVersionData = new BYTE[dwDataSize]; 
    if (!::GetFileVersionInfo((LPTSTR)lpszModuleName, dwHandle, dwDataSize, 
	                          (void**)m_lpVersionData) )
    {
        Close();
        return FALSE;
    }

    // Retrieve the first language and character-set identifier
    UINT nQuerySize;
    DWORD* pTransTable;
    if (!::VerQueryValue(m_lpVersionData, _T("\\VarFileInfo\\Translation"),
                         (void **)&pTransTable, &nQuerySize) )
    {
        Close();
        return FALSE;
    }

    // Swap the words to have lang-charset in the correct format
    m_dwLangCharset = MAKELONG(HIWORD(pTransTable[0]), LOWORD(pTransTable[0]));

    return TRUE;
}

CString CFileVersion::QueryValue(LPCTSTR lpszValueName, 
                                 DWORD dwLangCharset /* = 0*/)
{
    // Must call Open() first
    ASSERT(m_lpVersionData != NULL);
    if ( m_lpVersionData == NULL )
        return (CString)_T("");

    // If no lang-charset specified use default
    if ( dwLangCharset == 0 )
        dwLangCharset = m_dwLangCharset;

    // Query version information value
    UINT nQuerySize;
    LPVOID lpData;
    CString strValue, strBlockName;
    strBlockName.Format(_T("\\StringFileInfo\\%08lx\\%s"), 
	                     dwLangCharset, lpszValueName);
    if ( ::VerQueryValue((void **)m_lpVersionData, strBlockName.GetBuffer(0), 
	                     &lpData, &nQuerySize) )
        strValue = (LPCTSTR)lpData;

    strBlockName.ReleaseBuffer();

    return strValue;
}

BOOL CFileVersion::GetFixedInfo(VS_FIXEDFILEINFO& vsffi)
{
    // Must call Open() first
    ASSERT(m_lpVersionData != NULL);
    if ( m_lpVersionData == NULL )
        return FALSE;

    UINT nQuerySize;
	VS_FIXEDFILEINFO* pVsffi;
    if ( ::VerQueryValue((void **)m_lpVersionData, _T("\\"),
                         (void**)&pVsffi, &nQuerySize) )
    {
        vsffi = *pVsffi;
        return TRUE;
    }

    return FALSE;
}

CString CFileVersion::GetFixedFileVersion()
{
    CString strVersion;
	VS_FIXEDFILEINFO vsffi;

    if ( GetFixedInfo(vsffi) )
    {
        strVersion.Format ("%u,%u,%u,%u",HIWORD(vsffi.dwFileVersionMS),
            LOWORD(vsffi.dwFileVersionMS),
            HIWORD(vsffi.dwFileVersionLS),
            LOWORD(vsffi.dwFileVersionLS));
    }
    return strVersion;
}

CString CFileVersion::GetFixedProductVersion()
{
    CString strVersion;
	VS_FIXEDFILEINFO vsffi;

    if ( GetFixedInfo(vsffi) )
    {
        strVersion.Format ("%u,%u,%u,%u", HIWORD(vsffi.dwProductVersionMS),
            LOWORD(vsffi.dwProductVersionMS),
            HIWORD(vsffi.dwProductVersionLS),
            LOWORD(vsffi.dwProductVersionLS));
    }
    return strVersion;
}

Last updated: 2 April 1998



Comments

  • Unfortunately, this doesn't work if version info is broken.

    Posted by vsoft44 on 08/03/2004 12:53pm

    There exists at least one exception: Windows Media Player Ver 7.10.00.3059 which is installed in my PC. Its StringInfoSection contains 040904E4 language-codepack tag, while Translation section claims that another character set is used: 040904B0. Then QueryValue returns an empty string. At the same time, Windows Explorer shows Product Description string in file properties dialog. How?

    Reply
  • Very good job!!! Very good class!!!

    Posted by Legacy on 02/20/2003 12:00am

    Originally posted by: danman

    Very good job!!! Very good class!!!
    Thanx!!!

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Custom applications deliver significant value. With the right tools, organizations can maximize the value of custom applications by accelerating and simplifying their development, and enabling IT to manage them in close alignment with business decision-makers. And by using a platform optimized for the development of custom applications, businesses can reduce costs, lower TCO, enhance agility, and accelerate the time to value for new business services. Read this white paper to learn how your organization can …

  • At present, the most commonly deployed parallel file system is Lustre, and its adoption is growing across the HPC industry. According to Intersect 360 Research, "Through its leadership and involvement with OpenSFS, Cray advocates for the development of features that drive efficient performance at scale." Moreover, with help from Cray and OpenSFS, Lustre is gaining greater adoption across broader commercial application categories. As data and I/O requirements grow in commercial markets, technology vendors -- …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date