使用UpdateResource添加大型资源

时间:2014-09-09 15:09:02

标签: delphi winapi resources

在Windows文档中,我没有看到对使用UpdateResource可以添加的资源的大小限制的引用,但似乎我偶然发现了一个 - 而且它很小!

我正在开发一个Windows Ribbon应用程序,并希望以编程方式构建和附加资源。使用$ R指令链接资源只是花花公子,但是当从代码中附加相同的东西时,我一直得到内存垃圾。

我已设法使用字符串资源将其简化为一个简单示例:

  Handle := BeginUpdateResource(PChar(DestFileName), True);
  try
    AddResource(Handle, 'STRING', 'ManyXs', StrUtils.DupeString('X', 1000));
  finally
    EndUpdateResource(Handle, False);
  end;

AddResource定义为:

procedure TForm2.AddResource(Handle: NativeUInt; ResType, ResName, Value: string);
begin
  if not UpdateResource(Handle, PChar(ResType), PChar(ResName), 1033,
    PChar(Value), Value.Length * SizeOf(Char)) then
    RaiseLastOSError;
end;

暂时请忽略我的硬编码语言。

当我在调用它之后检查资源时,我看到了一千个X.美妙。

我可以将资源更改为1990 Xs,这很好。它到1991年的那一刻,我得到写入DLL的废话。资源的大小正确表示为3982(1991 * 2,因为它是Unicode),但内容只是从内存中转储的东西。

我可以使用我的资源编辑器查看更大的资源,并且IDE通常会插入更大的资源(例如Delphi表单),所以我肯定错过了一些东西。

我尝试了以下内容,尽管没有想到它们会有所作为(它们没有):

  1. 仅使用大内存缓冲区而不是字符串
  2. 使用Ansi版本的UpdateResource函数
  3. 许多不同的资源类型 - 我真正需要工作的是UIFILE
  4. 寻找API中的其他功能(我找不到)
  5. 1,2和3的组合
  6. 有什么想法吗?

    更新 受到评论和Jolyon的回答的启发,尝试了一些其他的东西。

    首先,我尝试了Delphi XE7和XE5(原版在XE6中)。我没有安装XE2,所以我无法确认Sertak所说的内容。我会发现我办公室里的其他人是否还安装了它。

    其次,这是内存缓冲区版本:

    procedure TForm2.AddResource(Handle: NativeUInt; const ResType, ResName, Value: string);
    var
      Buffer: Pointer;
      BuffLen: Integer;
    begin
      BuffLen := Value.Length * SizeOf(Char);
      GetMem(Buffer, BuffLen);
      try
        StrPCopy(PChar(Buffer), Value);
    
        if not UpdateResource(Handle, PChar(ResType), PChar(ResName), 1033,
          Buffer, BuffLen) then
          RaiseLastOSError;
      finally
        FreeMem(Buffer);
      end;
    end;
    

    我实际上有这个代码的先前版本,我在调用UpdateResource之前将该指针的内容转储到文件中,并且文件正确保存但资源仍然保存了垃圾。然后我做了这个版本,根本不涉及字符串:

    procedure TForm2.AddResource(Handle: NativeUInt; const ResType, ResName: string; 
      C: AnsiChar; Len: Integer );
    var
      Buffer: Pointer;
      BuffLen: Integer;
    begin
      BuffLen := Len;
      GetMem(Buffer, BuffLen);
      try
        FillMemory(Buffer, Len, Byte(C));
    
        if not UpdateResource(Handle, PChar(ResType), PChar(ResName), 1033,
          Buffer, BuffLen) then
          RaiseLastOSError;
      finally
        FreeMem(Buffer);
      end;
    end;
    

    使用这个版本,当我使用3882 X时,我仍然遇到同样的问题。当然,我现在使用单字节字符,这就是为什么它是双倍的。但我有完全相同的问题。

    我确实注意到TDUMP输出中的版本之间存在差异。对于版本1(字符串)和2(字符串复制到缓冲区),当我使用1991个字符时,我的资源大小突然显示为FFFFFF90。对于版本3(无字符串),大小是我使用的任何大小的实际十六进制值。

1 个答案:

答案 0 :(得分:0)

你得到的事实"垃圾"数据但是 size 的数据导致我怀疑 PChar()转换字符串值会产生错误的地址。这通常应该不是问题,但我想知道问题是否是一个奇怪的行为,因为将函数的结果直接传递给方法的参数?出于某种奇怪的原因只会在涉及的字符串达到一定大小时触发的行为,可能表示某些边缘情况优化行为。

如果某些特定版本的Delphi中存在优化(和/或其他编译器设置)的某种组合,这也可能解释了重现问题的困难。

我建议尝试通过在显式变量中创建新资源字符串并将其传递给 AddResource()方法来消除这种可能性。我还建议你明确你的参数语义,因为所涉及的字符串没有修改,也没有打算修改,在 AddResource()方法中,将它声明为正式的 const 参数。

你确实提到过使用"内存缓冲区"尝试了另一种方法。如果上述建议无法解决问题,那么发布一个使用这些问题再现问题的最小例子可能会有所帮助,以消除因更加异乎寻常的字符串而导致的任何可能的影响。类型。