c++builderc++builder-10.2-tokyoversioninfo

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();
    }
}
//-----------------------------------------------

Solution

  • 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);
    }
    //-----------------------------------------------