【问题标题】:How to Change StringTable Values stored in a .exe file如何更改存储在 .exe 文件中的 StringTable 值
【发布时间】:2014-09-28 17:46:45
【问题描述】:

我编写了 2 个程序,它们都经过编译,并且都包含通过 .rc 文件添加的“STRINGTABLES”资源。

所以,我们将 App #1 称为“app1.exe”,将 App #2 称为“app2.exe”。

这是我的问题。在 app2.exe 中,我有一个如下所示的字符串表:

STRINGTABLE
{
1000, "Hello"
1001, "There"
}

当我运行 app1.exe 时,我试图通过 Win32 API UpdateResource() 函数更新存储在 app2.exe 中的资源。

我可以使用Delphi的LoadStr()函数从stringtable中加载字符串就好了。

我的问题是我需要了解如何使用 UpdateResource() 来更改该字符串表中的 JUST THE STRINGS。因此,例如,我希望 app1.exe 将 app2.exe 的字符串表从您在上面看到的内容更改为:

STRINGTABLE
{
1000, "Thank"
1001, "You!"
}

对不起,我没有任何源代码,但是我从头开始,似乎无法弄清楚。

我正在使用 RAD Studio XE7。

如果你们需要更多继续,请直说,我会尽可能更新,但就像我说的,我刚刚开始学习 TResourceStream 和所有这些资源,所以我没有很多东西要展示。我只能告诉你,我对编程并不陌生。我很快就掌握了东西。我已经创建了一个THandle 并让 app1.exe 查看 app2.exe 的资源。我可以向其中添加内容,但似乎当我尝试从TEditTMemo 组件添加String 数据时,它在app2.exe 的资源中显示为一些奇怪的奇怪中文字母。所以我想知道如何格式化这些字符串,以便它们正确显示在资源和内容中。

为了更清楚地说明这一点,当我运行 app1.exe 并尝试将字符串 "Hello" 输入到 app2.exe 的字符串表中时,它给了我这个:

00230BF8  00 00 00 00                                       ••••

任何线索为什么?

我正在使用一个名为“Resource Hacker”的应用程序在运行程序后检查资源。

【问题讨论】:

  • 搜索有关执行此操作的教程。有人想知道,如果您希望字符串是可变的,为什么要将它们放入可执行文件中。
  • 否则,如果您需要代码方面的帮助,您需要展示它
  • 没关系。如果您无法在问题中显示代码,那么我将无能为力。
  • 感谢 Remy 编辑我的问题 :) 现在至少人们可以更好地理解它了,哈哈……抱歉格式很糟糕。
  • @Remy 你的标签编辑不好。请不要删除应包含在所有 delphi 问题中的 delphi 标签。

标签: delphi winapi delphi-xe7


【解决方案1】:

字符串表资源存储在 16 个块中,每个项目都写有一个字大小的长度标记,然后是 UTF-16 编码字符。如果块中的项目没有在原始 RC 文件中明确定义,那么它仍然存在于编译资源中,但长度为 0。

因此,假设您已仔细选择您的 ID 与 16 个相同的组。我会坚持使用您提供的 ID,并假设您要更新名为 TestLib.dll 的 DLL与EXE相同的目录;我还将假设我自己的语言环境(英式英语) - 您需要根据需要更改 MAKELANGID 参数:

const
  LibName = 'TestLib.dll';
  ID_FIRST  = 1000;
  ID_SECOND = 1001;

function StringIDToGroupID(ID: UINT): UINT; inline;
begin
  Result := (ID shr 4) + 1;
end;

procedure UpdateStrings(const NewFirst, NewSecond: string);
var
  Handle: THandle;
  GroupID: UINT;
  Stream: TCustomMemoryStream;
  GroupStrings: array[0..15] of string;
  StrLen: Word;
  I: Integer;
begin
  GroupID := StringIDToGroupID(ID_FIRST);
  //get existing data...
  Handle := LoadLibraryEx(LibName, 0, LOAD_LIBRARY_AS_DATAFILE);
  if Handle = 0 then RaiseLastOSError;
  try
    Stream := TResourceStream.CreateFromID(Handle, GroupID, RT_STRING);
    try
      for I := Low(GroupStrings) to High(GroupStrings) do
      begin
        Stream.ReadBufferData(StrLen);
        SetLength(GroupStrings[I], StrLen);
        Stream.ReadBuffer(PChar(GroupStrings[I])^, StrLen * SizeOf(Char));
      end;
    finally
      Stream.Free;
    end;
  finally
    FreeLibrary(Handle);
  end;
  //update the strings we're interested in...
  GroupStrings[ID_FIRST mod Length(GroupStrings)] := NewFirst;
  GroupStrings[ID_SECOND mod Length(GroupStrings)] := NewSecond;
  Stream := TMemoryStream.Create;
  try
    for I := Low(GroupStrings) to High(GroupStrings) do
    begin
      StrLen := Length(GroupStrings[I]);
      Stream.WriteData(StrLen);
      Stream.WriteBuffer(PChar(GroupStrings[I])^, StrLen * SizeOf(Char));
    end;
    //update DLL...
    Handle := BeginUpdateResource(LibName, False);
    if Handle = 0 then RaiseLastOSError;
    try
      UpdateResource(Handle, RT_STRING, PChar(GroupID),
        MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_UK), Stream.Memory, Stream.Size);
    finally
      EndUpdateResource(Handle, False);
    end;
  finally
    Stream.Free;
  end;
end;

【讨论】:

  • 非常感谢您的详细解释 :) 我得到了它的工作并根据我的喜好进行了编辑。我现在就接受你的回答,伙计,我感激不尽!非常感谢:)
猜你喜欢
  • 2010-10-06
  • 1970-01-01
  • 2013-01-15
  • 2018-09-14
  • 2011-02-28
  • 1970-01-01
  • 1970-01-01
  • 2019-11-06
  • 1970-01-01
相关资源
最近更新 更多