How to Read from a Version Resource in Visual C++

How do I read from a version resource in Visual C++

This is an edited version of my original answer.

bool GetProductAndVersion(CStringA & strProductName, CStringA & strProductVersion)
{
// get the filename of the executable containing the version resource
TCHAR szFilename[MAX_PATH + 1] = {0};
if (GetModuleFileName(NULL, szFilename, MAX_PATH) == 0)
{
TRACE("GetModuleFileName failed with error %d\n", GetLastError());
return false;
}

// allocate a block of memory for the version info
DWORD dummy;
DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
if (dwSize == 0)
{
TRACE("GetFileVersionInfoSize failed with error %d\n", GetLastError());
return false;
}
std::vector<BYTE> data(dwSize);

// load the version info
if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0]))
{
TRACE("GetFileVersionInfo failed with error %d\n", GetLastError());
return false;
}

// get the name and version strings
LPVOID pvProductName = NULL;
unsigned int iProductNameLen = 0;
LPVOID pvProductVersion = NULL;
unsigned int iProductVersionLen = 0;

// replace "040904e4" with the language ID of your resources
if (!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductName"), &pvProductName, &iProductNameLen) ||
!VerQueryValue(&data[0], _T("\\StringFileInfo\\040904e4\\ProductVersion"), &pvProductVersion, &iProductVersionLen))
{
TRACE("Can't obtain ProductName and ProductVersion from resources\n");
return false;
}

strProductName.SetString((LPCSTR)pvProductName, iProductNameLen);
strProductVersion.SetString((LPCSTR)pvProductVersion, iProductVersionLen);

return true;
}

How to get version info from resources?

VerQueryValue() cannot access version info from the original resource directly. You must make a copy of the resource in memory, then pass that memory to VerQueryValue() instead. The reason is because VerQueryValue() is designed to work with GetFileVersionInfo(), which requires a user-allocated block of writable memory and performs certain fixups within that memory. Accessing the VS_FIXEDFILEINFO struct does not require the fixups, but the memory block must still be writable. You cannot pass the original resource directly to VerQueryValue() because it is read-only memory.

Try this instead:

HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
LPVOID pRes, pResCopy;
UINT uLen;
VS_FIXEDFILEINFO *lpFfi;

hResInfo = FindResource(hInst, MAKEINTRESOURCE(100), RT_VERSION);
dwSize = SizeofResource(hInst, hResInfo);
hResData = LoadResource(hInst, hResInfo);
pRes = LockResource(hResData);
pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
CopyMemory(pResCopy, pRes, dwSize);
FreeResource(hResData);

VerQueryValue(pResCopy, TEXT("\\"), (LPVOID*)&lpFfi, &uLen);

DWORD dwFileVersionMS = lpFfi->dwFileVersionMS;
DWORD dwFileVersionLS = lpFfi->dwFileVersionLS;

DWORD dwLeftMost = HIWORD(dwFileVersionMS);
DWORD dwSecondLeft = LOWORD(dwFileVersionMS);
DWORD dwSecondRight = HIWORD(dwFileVersionLS);
DWORD dwRightMost = LOWORD(dwFileVersionLS);

LocalFree(pResCopy);

UPDATE: this only works if you access the VS_FIXEDFILEINFO struct only. If you need to access any other values, you must use GetFileVersionInfo(). Per Raymond Chen's blog:

The first parameter to VerQueryValue really must be a buffer you obtained from GetFileVersionInfo

The documentation says that the first parameter to VerQueryValue must be a buffer returned by the GetFileVersionInfo function for a reason. The buffer returned by GetFileVersionInfo is an opaque data block specifically formatted so that VerQueryValue will work. You're not supposed to look inside that buffer, and you certainly can't try to "obtain the data some other way". Because if you do, VerQueryValue will look for something in a buffer that is not formatted in the manner the function expects.

read FILEVERSION value in code

Using GetFileVersionInfo() and VerQueryValue() is the safe and official way to read any file's version data. The DLL can get its own path + filename by calling GetModuleFileName() with the HINSTANCE provided to its DllMain() entry point.

That being said, it is more efficient for the DLL to just read the version data out of its own version resource directly, using (Find|Load|Lock)Resource() instead of GetFileVersionInfo(). However, there are caveats with doing this:

  • it is not an approach that is officially supported by Microsoft.

  • the memory pointer that is obtained from LockResouce() cannot be passed to VerQueryValue(). You must allocate a copy of the resource block, and then you can pass the copy to VerQueryValue().

  • however, the only version data that you can safely query from the copied resource block using VerQueryValue() is the root VS_FIXEDFILEINFO structure, which is good enough to get the FileVersion and ProductVersion fields. Querying any of the localized version data requires fixups that are normally performed by GetFileVersionInfo(), and even VerQueryValue() itself in coordination with GetFileVersionInfo().

There are several answers on StackOverflow that explain how to use this approach, and some of them have code snippets, including:

https://stackoverflow.com/a/48577200/65863

https://stackoverflow.com/a/13942403/65863

Getting FILEVERSION from Visual C++ Resource File

The preprocessor runs on the .RC file as well. Define the shared data in a header that is included by both the .RC and your source code.

i.e., in foo.h:

#define MY_PRODUCT_NAME Foo

Then in the foo.rc:

#include "foo.h"

VS_VERSION_INFO VERSIONINFO
// Many lines omitted
VALUE "ProductName", MY_PRODUCT_NAME

Then in foo.cpp:

#include "foo.h"

cout << MY_PRODUCT_NAME;

c++ get version from .rc into code

Windows provides a set of API calls for retrieving the version information from executable files. The following snippet of code should help you get started.

bool GetVersionInfo(
LPCTSTR filename,
int &major,
int &minor,
int &build,
int &revision)
{
DWORD verBufferSize;
char verBuffer[2048];

// Get the size of the version info block in the file
verBufferSize = GetFileVersionInfoSize(filename, NULL);
if(verBufferSize > 0 && verBufferSize <= sizeof(verBuffer))
{
// get the version block from the file
if(TRUE == GetFileVersionInfo(filename, NULL, verBufferSize, verBuffer))
{
UINT length;
VS_FIXEDFILEINFO *verInfo = NULL;

// Query the version information for neutral language
if(TRUE == VerQueryValue(
verBuffer,
_T("\\"),
reinterpret_cast<LPVOID*>(&verInfo),
&length))
{
// Pull the version values.
major = HIWORD(verInfo->dwProductVersionMS);
minor = LOWORD(verInfo->dwProductVersionMS);
build = HIWORD(verInfo->dwProductVersionLS);
revision = LOWORD(verInfo->dwProductVersionLS);
return true;
}
}
}

return false;
}

Visual Studio c++ how to add version info read from .rc or .h to targetname?

You can use Property Macros. So if you were to bring up Property Manager (View > Property Manager) and right-click a configuration and choose Add New Property Sheet... then edit that property sheet by right-clicking on it and choosing properties. Then under Common Properties and then User Macros make a new macro with the Add Macro button.

Say you called it Version with value 1.0.0 then you can OK out of the dialogs and go to the project properties and for the Target Name have it be $(ProjectName)_$(Version) and build your project and that will work.

The property sheet is plain text so your automated script could edit this file on each build. You might need to delete a hidden file, the .suo file, if VS isn't picking up the changes from one build to the next.

Though if I may suggest a few other approaches.

  • Perhaps your build script could rename the output file?

  • Within VS you could have a post-build step that can read the version information from the executable and rename the file. Here is a function call that can be used to read the version information: http://msdn.microsoft.com/en-us/library/windows/desktop/ms647003%28v=vs.85%29.aspx It could be done all from a script instead.

  • Try CMake. CMake allows you to generate your VS solution and project files and can do some extraordinary things.

Hope that was helpful!

How to read a resource file in C#

Check your Resources.Designer.cs file. You should have there static string property named stop_words_utf8 (or whatever name for the file you choose). You use it like this:

Resources.stop_words_utf8

It is static string property

VC++ 2012: How to include version info from version.inc (maintained separately) into the .rc file

Here is the way to do it via Visual Studio 2012 (C++, IDE). Firstly, it seems that all the files (app.rc, version.rc2 with the version section to be included into app.rc, and also the version.inc with the values maintained separately [included into version.rc2]) must be stored in UTF-16 -- unlike in the earlier versions of Visual Studio. Then I was able to repeat the same approach also in Visual Studio 2012.

However, you do not need to edit the app.rc file manually. You can use the following steps using the IDE:

  • Open the project (App) and switch to the Resource View tab.
  • Unfold the App project, unfold its app.rc, and unfold the Version folder. You can see the VS_VERSION_INFO item.
  • Mark the VS_VERSION_INFO item and pres Delete key on the keyboard. The item and its upper Version folder disappear.
  • Mouse right-click the app.rc folder, and select the Resource Includes.... The dialog with the same name and with three input panes appear.

Resourde Includes dialog

  • Focus on the bottom pane named Compile-time directives:, and write the #include "version.rc2" there. (The file must not have the .rc extension, but the .rc2 is fine and recommended elsewhere in the MSDN doc.)
  • Press OK, and save all files (to save also the modified app.rc).

The result of the steps is that you will not see the Version folder and the VS_VERSION_INFO item in the resource tree (see Resource View tab); however, the above mentioned constructed Version section (stored inside the version.rc2) is compiled into the application resources.

Technically, the following parts of the app.rc file can be found after the steps:

3 TEXTINCLUDE 
BEGIN
"#include ""version.rc2""\r\n"
"\0"
END

...

#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
#include "version.rc2"

/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

Any constructive comments to enhance the topic are welcome and will be +1-ed :)

Have a nice time,

Petr



Related Topics



Leave a reply



Submit