// 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 ( _T( "%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 ( _T( "%u,%u,%u,%u" ),
							HIWORD( vsffi.dwProductVersionMS ),
							LOWORD( vsffi.dwProductVersionMS ),
							HIWORD( vsffi.dwProductVersionLS ),
							LOWORD( vsffi.dwProductVersionLS ) );
    }

    return strVersion;
}
