1

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();
    }
}
//-----------------------------------------------
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • 2
    `VerQueryValue()` is the correct way to go. If you are getting errors/exceptions with it, then you are using it wrong. Please show your actual code. And do note that BCB6 defaulted to using the Win32 API in ANSI mode, whereas Tokyo defaults to UNICODE mode instead. Are you accounting for that difference? – Remy Lebeau Dec 01 '18 at 01:22
  • Hi Remy that is my problem I am not familiar with UNICODE types and I do not know how to convert the old code to accomplish to UNICODE. I am using the class @SAM has posted and it is working fine. I will use it until I can learn how deal with UNICODE. Thank you very much. – Jayme Jeffman Dec 03 '18 at 13:15
  • 1
    if you want help porting code, please show the actual code – Remy Lebeau Dec 03 '18 at 16:18
  • I have added the actual code as suggested by @Remmy Lebeau. – Jayme Jeffman Dec 03 '18 at 20:25

2 Answers2

3

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);
}
//-----------------------------------------------
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
0

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;
}
Sam
  • 2,473
  • 3
  • 18
  • 29
  • Thank you very much. I have added the properties I need to get the infos I have added to the VersionInfo table and it is working fine. Later I will try to use the class inside a Windows service. – Jayme Jeffman Nov 30 '18 at 19:00