Win32 VS file information helper class

CFileVerHelper.h

#pragma once

#include <wtypesbase.h>
#include <string>
#include <tchar.h>

#ifdef_UNICODE
using _tstring = std::wstring;
#else
using _tstring = std::string;
#endif

//
//typedef struct tagVS_FIXEDFILEINFO {
// DWORD dwSignature; // Contains the value 0xFEEF04BD. This is used in conjunction with the szKey member of the VS_VERSIONINFO structure when searching for the VS_FIXEDFILEINFO structure.
// DWORD dwStrucVersion; // The high-order word of this member contains the major version number, and the low-order word contains the minor version number
// DWORD dwFileVersionMS; // The file version number is 32 bits higher
// DWORD dwFileVersionLS; // File version number lower 32 bits
// DWORD dwProductVersionMS; // Higher 32 digits of the product version number
// DWORD dwProductVersionLS; // Product version number lower 32 bits
// DWORD dwFileFlagsMask; // Bitmask containing the valid bits in specified dwFileFlags. Defined bits are only valid when creating a file.
// DWORD dwFileFlags; // bitmask containing boolean attributes for the specified file
// DWORD dwFileOS; // bitmask containing boolean attributes for the specified file
// DWORD dwFileType; // General type of file
// DWORD dwFileSubtype; // The subtype of the file
// DWORD dwFileDateMS; // file date timestamp high 32 bits
// DWORD dwFileDateLS; // File date timestamp lower 32 bits
//} VS_FIXEDFILEINFO;

typedef struct _VS_VERSIONINFO
{
    WORD wLength; //The length of the VS_VERSIONINFO structure (in bytes)
    WORD wValueLength; //The length of the Value member (in bytes)
    WORD wType; //The data type in the version resource. This member is 1 if the version resource contains text data; it is 0 if the version resource contains binary data.
    WCHAR szKey[16]; //Unicode string L"VS_VERSION_INFO".
    WORD Padding1; // Contains any zero WORDs needed to align the Value member on a 32-bit boundary.
    VS_FIXEDFILEINFO Value; //Any data associated with this VS_VERSIONINFO structure, the wValueLength member specifies the length of this member; if wValueLength is zero, this member does not exist.
    WORD Padding2; // Any zero word required to align the Children member on a 32-bit boundary
    WORD Children; // an array of zero or one StringFileInfo structures

    _VS_VERSIONINFO()
    {
        ZeroMemory(this, sizeof(_VS_VERSIONINFO));
    }

} VS_VERSIONINFO, * PVS_VERSIONINFO;

typedef CONST PVS_VERSIONINFO PCVS_VERSIONINFO;

class CFileVerHelper
{
    struct LANGANDCODEPAGE {
        WORD wLanguage;
        WORD wCodePage;
    };

public:
    CFileVerHelper();
    CFileVerHelper(const _tstring & strFile);
    ~CFileVerHelper();

    CFileVerHelper operator = (const CFileVerHelper & r) = delete;

    static _tstring GetCurrentExeVersion();

public:
    bool LoadFile(const _tstring & amp; strFile); //load file information
    bool IsValid() const;
    void Close();
    
    bool GetComments(_tstring & amp; strRes) const; //File comments
    bool GetInternalName(_tstring & amp; strRes) const; //internal name
    bool GetProductName(_tstring & amp; strRes) const; //product name
    bool GetCompanyName(_tstring & amp; strRes) const; //company name
    bool GetLegalCopyright(_tstring & amp; strRes) const; //legal copyright
    bool GetProductVersion(_tstring & amp; strRes) const; //Product version
    bool GetFileDescription(_tstring & amp; strRes) const; //file description
    bool GetLegalTrademarks(_tstring & amp; strRes) const; //Legal Trademarks
    bool GetPrivateBuild(_tstring & amp; strRes) const; //private version
    bool GetFileVersion(_tstring & amp; strRes) const; //file version
    bool GetOriginalFilename(_tstring & amp; strRes) const; //Original file name
    bool GetSpecialBuild(_tstring & amp; strRes) const; //special build

    PCVS_VERSIONINFO GetVersionInfo() const;
private:
    bool QueryInfo(const _tstring strName, _tstring & amp; strRes) const; //query file information

    PVS_VERSIONINFO m_lpVerData = nullptr; //file information data pointer
    DWORD m_dwVerSize = 0; //file information data size
    LANGANDCODEPAGE *m_lpTranslate = nullptr; //language code page
};

CFileVerHelper.cpp

#include "CFileVerHelper.h"
#include <tchar.h>
#include <strsafe.h>

#pragma comment(lib, "Version. lib")

CFileVerHelper::CFileVerHelper()
{

}

CFileVerHelper::CFileVerHelper(const _tstring & strFile)
{
    (void)this->LoadFile(strFile);
}

CFileVerHelper::~CFileVerHelper()
{
    this->Close();
}

_tstring CFileVerHelper::GetCurrentExeVersion()
{
    TCHAR szBuf[MAX_PATH] = { 0 };
    GetModuleFileName(NULL, szBuf, _countof(szBuf));

    CFileVerHelper obj;
    obj.LoadFile(szBuf);
    _tstring strVer;
    obj. GetFileVersion(strVer);
    return strVer;
}

bool CFileVerHelper::LoadFile(const _tstring & strFile)
{
    BOOL isDisableWow64Fs = FALSE;
    PVOID OldValue = NULL;
    BOOL isSuccess = FALSE;
    UINT cbTranslate = 0;

    if (strFile. empty())
    {
        goto L_Cleanup;
    }

    this->Close();

    isDisableWow64Fs = Wow64DisableWow64FsRedirection( & amp;OldValue);

    m_dwVerSize = GetFileVersionInfoSize(strFile.c_str(), 0);
    if (0 == m_dwVerSize)
    {
        goto L_Cleanup;
    }

    m_lpVerData = (PVS_VERSIONINFO)::HeapAlloc(::GetProcessHeap(), 0, m_dwVerSize);
    if (!m_lpVerData)
    {
        goto L_Cleanup;
    }

    if (!GetFileVersionInfo(strFile.c_str(), 0, m_dwVerSize, m_lpVerData))
    {
        goto L_Cleanup;
    }

    if (!VerQueryValue(m_lpVerData, _T("\VarFileInfo\Translation"), (LPVOID*) & amp;m_lpTranslate, & amp;cbTranslate))
    {
        goto L_Cleanup;
    }
    
    isSuccess = TRUE;

L_Cleanup:

    if (!isSuccess)
    {
        this->Close();
    }

    if (isDisableWow64Fs)
    {
        Wow64RevertWow64FsRedirection(OldValue);
    }

    return isSuccess;
}

bool CFileVerHelper::IsValid() const
{
    return nullptr != m_lpVerData;
}

void CFileVerHelper::Close()
{
    if (m_lpVerData)
    {
        ::HeapFree(::GetProcessHeap(), 0, m_lpVerData);
        m_lpVerData = nullptr;
        m_dwVerSize = 0;
    }
}

bool CFileVerHelper::QueryInfo(const _tstring strName, _tstring & amp; strRes) const
{
    TCHAR strQuery[MAX_PATH] = { 0 };
    HRESULT hr = S_OK;
    BOOL isSuccess = FALSE;
    LPCTSTR lpQueryRes = NULL;
    UINT uQueryCchSize;

    strRes. clear();

    if (!m_lpVerData || !m_lpTranslate)
    {
        goto L_Cleanup;
    }

    hr = StringCchPrintf(strQuery, _countof(strQuery),
        _T("\StringFileInfo\ x x\%s"),
        m_lpTranslate[0].wLanguage,
        m_lpTranslate[0].wCodePage,
        strName.c_str());
    if (FAILED(hr))
    {
        goto L_Cleanup;
    }

    if (!VerQueryValue(m_lpVerData, strQuery, (LPVOID*) & amp;lpQueryRes, & amp;uQueryCchSize))
    {
        goto L_Cleanup;

    }

    strRes = lpQueryRes;
    isSuccess = TRUE;

L_Cleanup:

    return isSuccess;
}

bool CFileVerHelper::GetComments(_tstring & amp; strRes) const
{
    return QueryInfo(_T("Comments"), strRes);
}

bool CFileVerHelper::GetInternalName(_tstring & amp; strRes) const
{
    return QueryInfo(_T("InternalName"), strRes);
}

bool CFileVerHelper::GetProductName(_tstring & strRes) const
{
    return QueryInfo(_T("ProductName"), strRes);
}

bool CFileVerHelper::GetCompanyName(_tstring & strRes) const
{
    return QueryInfo(_T("CompanyName"), strRes);
}

bool CFileVerHelper::GetLegalCopyright(_tstring & strRes) const
{
    return QueryInfo(_T("LegalCopyright"), strRes);
}

bool CFileVerHelper::GetProductVersion(_tstring & amp; strRes) const
{
    return QueryInfo(_T("ProductVersion"), strRes);
}

bool CFileVerHelper::GetFileDescription(_tstring & amp; strRes) const
    {
        return QueryInfo(_T("FileDescription"), strRes);
    }

bool CFileVerHelper::GetLegalTrademarks(_tstring & amp; strRes) const
{
    return QueryInfo(_T("LegalTrademarks"), strRes);
}

bool CFileVerHelper::GetPrivateBuild(_tstring & strRes) const
{
    return QueryInfo(_T("PrivateBuild"), strRes);
}

bool CFileVerHelper::GetFileVersion(_tstring & amp; strRes) const
{
    return QueryInfo(_T("FileVersion"), strRes);
}

bool CFileVerHelper::GetOriginalFilename(_tstring & amp; strRes) const
{
    return QueryInfo(_T("OriginalFilename"), strRes);
}

bool CFileVerHelper::GetSpecialBuild(_tstring & strRes) const
{
    return QueryInfo(_T("SpecialBuild"), strRes);
}

PCVS_VERSIONINFO CFileVerHelper::GetVersionInfo() const
{
    return m_lpVerData;
}