Jayme Jeffman
Jayme Jeffman

Reputation: 53

How to get Version Info entries using C++ Builder

The thread at How to get version info shows the code to get FileVersion, I need to get other values, includuing some I myself have added to VersionInfo table.

How can I get them using C++Builder 10.2 (Tokyo) ?

I used to get them in C++Builder 6.0 using the VerQueryValue method but it is raising too many exception on types.

I do not know how to change the code to C++Builder 10.2.

Bellow is the actual code I am using:

class.h

struct TransArray
{
    WORD LanguageID, CharacterSet;
};
DWORD VerInfo, VerSize;
HANDLE MemHandle;
LPVOID MemPtr, BufferPtr;
UINT BufferLength;
TransArray *Array;
char QueryBlock[255];
String FFileVersion ;

class.cpp

// this one of the methods which have errors
String __fastcall TAppVersion::GetFileVersion(void)
{
    String Result ;
    BufferPtr = NULL ;

    // Get the product version.
    wsprintf(QueryBlock, "\\StringFileInfo\\%04x%04x\\FileVersion",
                    Array[0].LanguageID, Array[0].CharacterSet);
    VerQueryValue(MemPtr, QueryBlock, &BufferPtr, &BufferLength);

    if(BufferPtr) Result = (char *)BufferPtr;

    return(Result);
}
//---------------------------------------------------
__fastcall TAppVersion::TAppVersion()
{
    FFileName = Application->ExeName ;
    VerSize = GetFileVersionInfoSize(FFileName.c_str(), &VerInfo);
    if (VerSize > 0) {
        MemHandle = GlobalAlloc(GMEM_MOVEABLE, VerSize);
        MemPtr = GlobalLock(MemHandle);
        GetFileVersionInfo(FFileName.c_str(), VerInfo, VerSize, MemPtr);
        VerQueryValue(MemPtr, "\\VarFileInfo\\Translation", &BufferPtr,
                                &BufferLength);
        Array = (TransArray *)BufferPtr;

        FFileVersion = GetFileVersion();
    }
}
//-----------------------------------------------

Upvotes: 1

Views: 1906

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 595981

Your code is mixing ANSI and UNICODE logic incorrectly. VerQueryValue() is a preprocessor macro that maps to either VerQueryValueW() or VerQueryValueA() depending on whether UNICODE is defined or not, respectively. Your code is assuming VerQueryValueA() is being used, but that is not always the case. In modern versions of C++Builder, VerQueryValueW() would be used instead, by default.

Try something more like this instead:

struct TransArray
{
    WORD LanguageID, CharacterSet;
};

DWORD VerInfo, VerSize;
LPVOID MemPtr, BufferPtr;
UINT BufferLength;
TransArray *Array;
String FFileName, FFileVersion;

...

#include <tchar.h>

String __fastcall TAppVersion::GetFileVersion(void)
{
    String Result;

    if (MemPtr && Array)
    {
        // Get the product version.
        TCHAR QueryBlock[40];
        _stprintf(QueryBlock, _T("\\StringFileInfo\\%04x%04x\\FileVersion"), Array[0].LanguageID, Array[0].CharacterSet);
        if (VerQueryValue(MemPtr, QueryBlock, &BufferPtr, &BufferLength)) {
            Result = String(static_cast<TCHAR*>(BufferPtr), BufferLength).Trim();
        }
    }

    return Result;
}
//---------------------------------------------------
__fastcall TAppVersion::TAppVersion()
{
    MemPtr = NULL;
    Array = NULL;

    FFileName = Application->ExeName;

    DWORD Unused;
    VerSize = GetFileVersionInfoSize(FFileName.c_str(), &Unused);
    if (VerSize == 0) return;

    MemPtr = new BYTE[VerSize];
    if (GetFileVersionInfo(FFileName.c_str(), Unused, VerSize, MemPtr)) {
        if (VerQueryValue(MemPtr, TEXT("\\VarFileInfo\\Translation"), &BufferPtr, &BufferLength) {
            Array = (TransArray *) BufferPtr;
            FFileVersion = GetFileVersion();
        }
    }
}
//-----------------------------------------------
__fastcall TAppVersion::~TAppVersion()
{
    delete[] static_cast<BYTE*>(MemPtr);
}
//-----------------------------------------------

Though really, you shouldn't rely on TCHAR at all in modern code:

struct TransArray
{
    WORD LanguageID, CharacterSet;
};

DWORD VerInfo, VerSize;
LPVOID MemPtr, BufferPtr;
UINT BufferLength;
TransArray *Array;
UnicodeString FFileName, FFileVersion;

...

UnicodeString __fastcall TAppVersion::GetFileVersion(void)
{
    UnicodeString Result;

    if (MemPtr && Array)
    {
        // Get the product version.
        WCHAR QueryBlock[40];
        swprintf(QueryBlock, L"\\StringFileInfo\\%04x%04x\\FileVersion", Array[0].LanguageID, Array[0].CharacterSet);
        if (VerQueryValueW(MemPtr, QueryBlock, &BufferPtr, &BufferLength)) {
            Result = UnicodeString(static_cast<WCHAR*>(BufferPtr), BufferLength).Trim();
        }
    }

    return Result;
}
//---------------------------------------------------
__fastcall TAppVersion::TAppVersion()
{
    MemPtr = NULL;
    Array = NULL;

    FFileName = Application->ExeName;

    DWORD Unused;
    VerSize = GetFileVersionInfoSizeW(FFileName.c_str(), &Unused);
    if (VerSize == 0) return;

    MemPtr = new BYTE[VerSize];
    if (GetFileVersionInfoW(FFileName.c_str(), Unused, VerSize, MemPtr)) {
        if (VerQueryValueW(MemPtr, L"\\VarFileInfo\\Translation", &BufferPtr, &BufferLength) {
            Array = (TransArray *) BufferPtr;
            FFileVersion = GetFileVersion();
        }
    }
}
//-----------------------------------------------
__fastcall TAppVersion::~TAppVersion()
{
    delete[] static_cast<BYTE*>(MemPtr);
}
//-----------------------------------------------

Upvotes: 3

Sam
Sam

Reputation: 2552

A while ago I did some playing with this. It is not complete and I would call it beta 1. But here it goes.

The header:

class TAppVerInfo
{
public:
    __fastcall TAppVerInfo(const wchar_t* pModPath);
    __fastcall virtual ~TAppVerInfo(void);

    __property System::String LanguagesCodePage                         = {read = GetCodePage};
    __property System::String Comments[System::String LanId]            = {read = GetComments};
    __property System::String InternalName[System::String LanId]        = {read = GetInternalName};
    __property System::String ProductName[System::String LanId]         = {read = GetProductName};
    __property System::String CompanyName[System::String LanId]         = {read = GetCompanyName};
    __property System::String LegalCopyright[System::String LanId]      = {read = GetLegalCopyright};
    __property System::String ProductVersion[System::String LanId]      = {read = GetProductVersion};
    __property System::String FileDescription[System::String LanId]     = {read = GetFileDescription};
    __property System::String LegalTrademarks[System::String LanId]     = {read = GetLegalTrademarks};
    __property System::String PrivateBuild[System::String LanId]        = {read = GetPrivateBuild};
    __property System::String FileVersion[System::String LanId]         = {read = GetFileVersion};
    __property System::String OriginalFilename[System::String LanId]    = {read = GetOriginalFilename};
    __property System::String SpecialBuild[System::String LanId]        = {read = GetSpecialBuild};

protected:
    void *VerInfo;

    System::String __fastcall GetCodePage(void);
    System::String __fastcall GetComments(System::String LanId);
    System::String __fastcall GetInternalName(System::String LanId);
    System::String __fastcall GetProductName(System::String LanId);
    System::String __fastcall GetCompanyName(System::String LanId);
    System::String __fastcall GetLegalCopyright(System::String LanId);
    System::String __fastcall GetProductVersion(System::String LanId);
    System::String __fastcall GetFileDescription(System::String LanId);
    System::String __fastcall GetLegalTrademarks(System::String LanId);
    System::String __fastcall GetPrivateBuild(System::String LanId);
    System::String __fastcall GetFileVersion(System::String LanId);
    System::String __fastcall GetOriginalFilename(System::String LanId);
    System::String __fastcall GetSpecialBuild(System::String LanId);
    System::String __fastcall GetValue(const System::String& LanId, const wchar_t* pName);
};

and the CPP:

__fastcall TAppVerInfo::TAppVerInfo(const wchar_t* pModPath)
{
    DWORD dwUnused;
    DWORD VerInfoSize = GetFileVersionInfoSize(pModPath, &dwUnused);

    VerInfo = malloc(VerInfoSize);
    if(VerInfo)
    {
        if(0 == GetFileVersionInfo(pModPath, 0, VerInfoSize, VerInfo))
        {
            free(VerInfo);
            VerInfo = NULL;
            throw Exception(SysErrorMessage(GetLastError()));
        }
    } //040904E4
}
//---------------------------------------------------------------------------
__fastcall TAppVerInfo::~TAppVerInfo(void)
{
    if(VerInfo)
        free(VerInfo);
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetCodePage(void)
{
    System::String retVal;

    if(VerInfo)
    {
        struct LANGANDCODEPAGE
        {
            WORD wLanguage;
            WORD wCodePage;
        } *lpTranslate;
        UINT cbTranslate;
        TAutoStringList tStr(new TStringList);
        UINT i;

        VerQueryValue(VerInfo,L"\\VarFileInfo\\Translation", (LPVOID*)&lpTranslate, &cbTranslate);
        for(i = 0; i < (cbTranslate/sizeof(LANGANDCODEPAGE)); i++)
            tStr->Add(System::String().sprintf(L"%04x%04x", lpTranslate[i].wLanguage, lpTranslate[i].wCodePage));
        retVal = tStr->CommaText;
    }
    return retVal;
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetComments(System::String LanId)
{
    return GetValue(LanId, L"Comments");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetInternalName(System::String LanId)
{
    return GetValue(LanId, L"InternalName");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetProductName(System::String LanId)
{
    return GetValue(LanId, L"ProductName");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetCompanyName(System::String LanId)
{
    return GetValue(LanId, L"CompanyName");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetLegalCopyright(System::String LanId)
{
    return GetValue(LanId, L"LegalCopyright");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetProductVersion(System::String LanId)
{
    return GetValue(LanId, L"ProductVersion");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetFileDescription(System::String LanId)
{
    return GetValue(LanId, L"FileDescription");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetLegalTrademarks(System::String LanId)
{
    return GetValue(LanId, L"LegalTrademarks");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetPrivateBuild(System::String LanId)
{
    return GetValue(LanId, L"PrivateBuild");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetFileVersion(System::String LanId)
{
    return GetValue(LanId, L"FileVersion");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetOriginalFilename(System::String LanId)
{
    return GetValue(LanId, L"OriginalFilename");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetSpecialBuild(System::String LanId)
{
    return GetValue(LanId, L"SpecialBuild");
}
//---------------------------------------------------------------------------
System::String __fastcall TAppVerInfo::GetValue(const System::String& LanId, const wchar_t* pName)
{
    System::String retVal;

    if(VerInfo)
    {
        System::String aPath(System::String().sprintf(L"\\StringFileInfo\\%s\\%s", LanId.c_str(), pName));
        wchar_t *pBuf;
        UINT uLen;

        if(VerQueryValue(VerInfo, aPath.c_str(), (void**)&pBuf, &uLen))
            retVal = System::String(pBuf);
    }
    return retVal;
}

Upvotes: 0

Related Questions