NOTE: This is not an answer to the question of how to determine whether a specific STRINGTABLE resource is included in the final EXE, but an alternate method to resolve the problem posed.
This question is partially based on this answer.
Step 1: Enter your project properties and the Version Info
tab. If version information (such as version numbers or CompanyName
) have been set, copy down all the relevant information. Now turn off Include version information in project
.
Step 2: Create a Version.rc and Version_Alt.rc file. Your exact version may differ, but this is a good starting template:
// Version information resource file
#include "windows.h"
#include "VersionCommon.txt"
1 VERSIONINFO
FILEVERSION VER_NUM_MAJOR, VER_NUM_MINOR, VER_NUM_RELEASE, VER_NUM_BUILD
FILEOS VER_FILEOS
FILETYPE VFT_APP
{
BLOCK "VarFileInfo"
{
VALUE "Translation", TRANSLATION_LANG_ID, TRANSLATION_CHARSET
}
BLOCK "StringFileInfo"
{
// Note: The block address is a concatenation of the locale ID and code page. This would be "040904E4" for English (US).
BLOCK "080904E4"
{
VALUE "CompanyName", STRING_COMPANY_NAME
VALUE "FileDescription", STRING_FILE_DESCRIPTION
VALUE "InternalName", STRING_INTERNAL_NAME_STD
VALUE "LegalCopyright", STRING_LEGAL_COPYRIGHT
VALUE "LegalTrademarks", STRING_LEGAL_TRADEMARKS
VALUE "ProductName", STRING_PRODUCT_NAME
VALUE "ProductVersion", STRING_PRODUCT_VERSION
VALUE "Comments", STRING_COMMENTS
VALUE "Homepage", STRING_HOME_PAGE
}
}
}
This is for the Version.rc file. InternalName
will be STRING_INTERNAL_NAME_ALT for Version_Alt.rc, otherwise everything else is the same.
Step 3: Create VersionCommon.txt which might look like this:
// Common version information (between standard and alternate language)
// Version info
#define VER_NUM_MAJOR 1
#define VER_NUM_MINOR 2
#define VER_NUM_RELEASE 3
#define VER_NUM_BUILD 4
#define VER_FILEOS 0x00000004L // 32-bit Windows
// Translation info
#define TRANSLATION_LANG_ID 0x0809 // Locale: English (UK)
#define TRANSLATION_CHARSET 0x04E4 // Code Page: 1252
// String file info
#define STRING_COMPANY_NAME "YOUR-COMPANY\0"
#define STRING_FILE_DESCRIPTION "Software to do amazing things\0"
#define STRING_INTERNAL_NAME_STD "Standard\0" // ALT_LANG not defined
#define STRING_INTERNAL_NAME_ALT "Alternate\0" // ALT_LANG is defined
#define STRING_LEGAL_COPYRIGHT "Copyright (C) YOUR-COMPANY\0"
#define STRING_LEGAL_TRADEMARKS "LEGALISE STATEMENT?\0"
#define STRING_PRODUCT_NAME "Groovy\0"
#define STRING_PRODUCT_VERSION "SOME-VERSION-INFO\0"
#define STRING_COMMENTS "SOME-COMMENTS\0"
#define STRING_HOME_PAGE "OPTIONAL-YOUR-WEBSITE\0"
Step 4: Write a batch file that compiles your resource scripts. Note that later versions of Delphi can be configured to compile the resources for you. The batch file might look like this:
@echo off
rem Version.rc and Version_Alt.rc are used to create version information that is linked into
rem the main Delphi application. "InternalName" is used to indicate whether ALT_LANG is defined.
echo Setting the program path (change this if your path is different)
set SOURCE_PATH=<PATH-TO-FOLDER-CONTAINING-RC-FILES>
echo .
echo Use Visual Studio tools to generate the version .RES files
@echo on
cd <PATH-TO-VISUAL-STUDIO-BIN-FOLDER-CONTAINING-RC.EXE>
call vcvars32
rc /r %SOURCE_PATH%\Version.rc
rc /r %SOURCE_PATH%\Version_Alt.rc
echo .
@echo off
echo .
rem pause <- uncomment this to debug errors
exit
Step 5: Open your Delphi project (.dpr) in a text editor and link these .RES files into the final EXE:
{$IFDEF ALT_LANG}
{$R 'source\Strings_Alt.res'}
{$R 'source\Version\Version_Alt.res'}
{$ELSE}
{$R 'source\Strings.res'}
{$R 'source\Version\Version.res'}
{$ENDIF}
Step 6: You've now got version information included in your file and just have to read InternalName
(which will be "Standard" or "Alternate"). This can be done as follows:
strLanguage := GetSpecificFileVersionInfo('YOUR-EXE.exe', 'InternalName');
and the code for GetSpecificFileVersionInfo
is:
function GetSpecificFileVersionInfo(szFile: PChar; strInfo: String) : String;
var
pstrBuffer: PChar;
dwSize, dwLength: DWORD;
pVersion: pointer;
strKey: String;
begin
// Return the specified file version information
// Adapted from: http://www.swissdelphicenter.com/en/showcode.php?id=1047
// Typical values in the VERSIONINFO resource of the application include:
// * CompanyName
// * FileDescription
// * InternalName
// * LegalCopyright
// * LegalTrademarks
// * ProductName
// * ProductVersion
// * Comments
// Additional fields may be available if the version information has been updated
Result := '';
dwSize := GetFileVersionInfoSize(szFile, dwSize);
if (dwSize > 0) then
begin
pstrBuffer := AllocMem(dwSize);
try
if ( (GetFileVersionInfo(szFile, 0, dwSize, pstrBuffer)) and
(VerQueryValue(pstrBuffer, '\VarFileInfo\Translation', pVersion, dwLength))) then
begin
strKey := Format('\StringFileInfo\%.4x%.4x\%s', [
LoWord(Integer(pVersion^)),
HiWord(Integer(pVersion^)), strInfo]);
if (VerQueryValue(pstrBuffer, PChar(strKey), pVersion, dwLength)) then
Result := StrPas(pVersion);
end;
finally
FreeMem(pstrBuffer, dwSize);
end;
end;
end;
Job done. Now you've solved two problems. The first is your original one which is to identify how the EXE was compiled (without actually running the EXE). The second is one you probably didn't realise which is your manually entered version information was error-prone...now you have included more automated version information.
GetFileVersionInfo
. – LU RD