Delphi 使用UpdateResource添加大型资源

Delphi 使用UpdateResource添加大型资源,delphi,winapi,resources,Delphi,Winapi,Resources,在Windows文档中,我看不到对可以使用UpdateResource添加的资源的大小限制的引用,但似乎我偶然发现了一个,而且它很小 我正在开发一个Windows Ribbon应用程序,并希望以编程方式构建和附加资源。使用$R指令链接资源非常有效,但是当从代码中附加同样的内容时,我总是收到内存垃圾 我已使用字符串资源将其简化为一个简单的示例: Handle := BeginUpdateResource(PChar(DestFileName), True); try AddReso

在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;
请暂时忽略我的硬编码语言

当我在调用此函数之后检查资源时,我看到了1000个X。太棒了

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

我可以用我的资源编辑器查看较大的资源,而IDE通常会插入较大的资源(例如Delphi表单),因此我肯定遗漏了一些东西

我尝试了以下方法,尽管我认为它们中的任何一个都不会有什么不同(它们没有):

  • 只使用大内存缓冲区而不是字符串
  • 使用Ansi版本的UpdateResource函数
  • 许多不同的资源类型——我真正需要的是UIFILE
  • 在API中寻找其他函数(我没有找到)
  • 1、2和3的组合
  • 有什么想法吗

    更新: 受到这些评论和乔里恩回答的启发,他尝试了更多的事情

    首先,我也尝试了DelphiXe7和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 Xs时仍然存在同样的问题。当然,我现在使用单字节字符,这就是为什么它是双字节的。但我有完全相同的问题


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

    事实上,您得到的是“垃圾”数据,但数据大小正确,这让我怀疑字符串值的转换产生了错误的地址。这通常不应该是一个问题,但我想知道问题是否是由于将函数的结果直接传递到方法的参数中而导致的某种奇怪行为?一种行为,由于某种奇怪的原因,只有当所涉及的字符串达到一定大小时才会触发,这可能表明某些边缘情况优化行为

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

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


    您确实提到尝试过使用“内存缓冲区”的替代方法。如果上述建议不能解决问题,那么发布一个使用这些建议再现问题的最小示例可能会有所帮助,以消除更奇特的“字符串”类型对事物可能产生的任何影响。

    请记住,我对德尔福知之甚少,
    string
    是“窄”字符串吗?有关的文档说明,
    lpData
    不得指向ANSI数据,它必须是Unicode。因此,使用
    WideString
    可能是个好主意?查找表明
    String
    默认为
    AnsiString
    @icabod在现代Delphi中
    String
    是UTF-16
    UnicodeString
    @DavidHeffernan:有一个现代Delphi@伊卡博德在那里。听起来你好像落伍了。使用古老的delphi基础网站也是一个很大的错误。Delphi有很好的文档记录,文档是在线的。请跟上!;-)无法复制,使用XE2测试,重复50000次。这听起来更像是一个注释。我当然不知道有这样的虫子。我们现在已经注意到了。你会惊讶于臭虫能被忽视多久。我能想到在Delphi中至少有两个在野外出现之前经过了很长时间(以及在被修复之前更长时间)。我还建议进一步简化,。也许认为这抵消了所有应该回答的意见:(fwiw我确实犹豫是否将其作为答案发布,但评论不够多)