My Delphi application uses the Microsoft Resource Compiler (rc.exe) to compile a list of strings (text format in a .rc file) like this:
Language LANG_KOREAN, SUBLANG_KOREAN
STRINGTABLE
BEGIN
cszLanguageName "Korean"
<etc>
END
into a .res file. All tables contains the same IDs (such as cszLanguageName). I maintain two separate resource string files. One contains mostly European languages (English, Czech, etc) which I call "Standard.rc". The other is called "Alternate.rc" and contains all other languages like Korean, Thai, etc.
A compile-time switch determines which file is linked into the EXE:
{$IFDEF ALT_LANG}
{$R 'source\Alternate.res'}
{$ELSE}
{$R 'source\Standard.res'}
{$ENDIF}
That was background, now to the question!
Is it possible to determine, given the path to an EXE and using something like the Windows GetFileVersionInfo method, which STRINGTABLE resources are in the EXE? If it were possible to determine whether:
Language LANG_KOREAN, SUBLANG_KOREAN
or
Language LANG_CZECH, SUBLANG_DEFAULT
was included, then the EXE could be identified as "standard" or "alternate".
Currently, without actually executing the EXE, the only difference is size in bytes which is an unreliable heuristic. C++ or C# is fine. I can adapt to Delphi or write a separate utility which is called from Delphi.
UPDATE
Based on the comment from LU RD, I created the following Version.rc file:
// Version information resource file
VS_VERSION_INFO VERSIONINFO
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "080904b0"
BEGIN
VALUE "InternalName", "Standard"
END
END
END
This was then compiled (with the Microsoft Resource Compiler) into Version.res and linked into the application using {$R 'source\Version.res'}. This compiles as expected, but when I try to read the InternalName field from the EXE it is blank. If I manually set InternalName in the project properties to "Test", then it is set out as "Test". What am I doing wrong and how do I overwrite what has been manually entered in the project properties?
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 Infotab. If version information (such as version numbers orCompanyName) have been set, copy down all the relevant information. Now turn offInclude 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:
This is for the Version.rc file.
InternalNamewill 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:
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:
Step 5: Open your Delphi project (.dpr) in a text editor and link these .RES files into the final EXE:
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:and the code for
GetSpecificFileVersionInfois: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.