确定EXE中包含哪个STRINGTABLE [英] Determine which STRINGTABLE is included in EXE

查看:68
本文介绍了确定EXE中包含哪个STRINGTABLE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的Delphi应用程序使用Microsoft资源编译器(rc.exe)来编译字符串列表( .rc 文件中的文本格式),如下所示:

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

放入 .res 文件。所有表都包含相同的ID(例如 cszLanguageName )。我维护两个单独的资源字符串文件。其中一种主要包含欧洲语言(英语,捷克语等),我称之为 Standard.rc。另一个称为 Alternate.rc,包含所有其他语言,如韩语,泰语等。

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.

编译时开关确定将哪个文件链接到EXE:

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!

给定EXE的路径并使用Windows <$之类的东西,是否有可能确定? c $ c> GetFileVersionInfo 方法,哪些STRINGTABLE资源在EXE中?如果可以确定是否:

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

Language LANG_CZECH, SUBLANG_DEFAULT

包括在内,则可以将EXE标识为标准或备用。

was included, then the EXE could be identified as "standard" or "alternate".

当前,没有实际执行EXE,唯一的区别是字节大小,这是不可靠的启发式方法。 C ++或C#很好。我可以适应Delphi或编写从Delphi调用的单独实用程序。

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.

更新

基于LU RD的注释,我创建了以下Version.rc文件:

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

然后将其编译(带有Microsoft Resource Compiler)插入Version.res,并使用 {$ R'source\Version.res'} 链接到应用程序。这将按预期编译,但是当我尝试从EXE读取 InternalName 字段时,该字段为空。如果我在项目属性中手动将 InternalName 设置为 Test,则将其设置为 Test。我在做什么错了,我该如何覆盖在项目属性中手动输入的内容?

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?

推荐答案

注意:这不是有关如何确定最终EXE中是否包含特定STRINGTABLE资源的问题的答案,但是解决此问题的另一种方法。

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.

此问题部分是基于此 answer

第1步:输入项目属性和版本信息标签。如果设置了版本信息(例如版本号或 CompanyName ),请复制所有相关信息。现在关闭在项目中包含版本信息

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.

步骤2:创建一个Version.rc和Version_Alt.rc文件。您的确切版本可能有所不同,但这是一个很好的入门模板:

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
        }
    }
}

Version.rc文件。 InternalName 对于Version_Alt.rc将为STRING_INTERNAL_NAME_ALT,否则其他所有内容都相同。

This is for the Version.rc file. InternalName will be STRING_INTERNAL_NAME_ALT for Version_Alt.rc, otherwise everything else is the same.

步骤3:创建VersionCommon。 txt可能看起来像这样:

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"

步骤4:编写一个用于编译资源脚本的批处理文件。请注意,可以将更高版本的Delphi配置为为您编译资源。批处理文件可能看起来像这样:

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

第5步:在文本编辑器中打开您的Delphi项目(.dpr),并将这些.RES文件链接到最终的EXE:

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}

步骤6:您现在已经在文件中包含了版本信息,只需阅读 InternalName (将为标准或备用)。可以按照以下步骤进行操作:

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');

GetSpecificFileVersionInfo 的代码为:

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;

工作完成。现在,您已经解决了两个问题。第一个是您的原始文件,它用于确定EXE的编译方式(实际上未运行EXE)。第二个是您可能没有意识到的问题,因为您手动输入的版本信息容易出错...现在您包括了更多的自动化版本信息。

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.

这篇关于确定EXE中包含哪个STRINGTABLE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆