【发布时间】:2014-09-09 15:09:01
【问题描述】:
在 Windows 文档中,我没有看到对可以使用 UpdateResource 添加的资源的大小限制的引用,但我似乎偶然发现了一个 - 而且它很小!
我正在开发一个 Windows 功能区应用程序,并希望以编程方式构建和附加资源。使用 $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 表单),所以我肯定遗漏了一些东西。
我尝试了以下方法,尽管不认为它们会有所作为(他们没有):
- 仅使用大内存缓冲区而不是字符串
- 使用 Ansi 版本的 UpdateResource 函数
- 许多不同的资源类型 - 我真正需要的是 UIFILE
- 在 API 中寻找其他函数(我没有找到)
- 1、2 和 3 的组合
有什么想法吗?
更新: 受到 cmets 和 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 Xs 时,我仍然遇到同样的问题。当然,我现在使用的是单字节字符,这就是为什么它是双字节的。但我有完全相同的问题。
我确实注意到 TDUMP 输出中的版本之间存在差异。对于版本 1(字符串)和 2(复制到缓冲区的字符串),当我使用 1991 个字符时,我的资源大小突然显示为 FFFFFF90。对于版本 3(无字符串),大小是我使用的任何大小的实际十六进制值。
【问题讨论】:
-
请记住我对 Delphi 知之甚少,
string是一个“窄”字符串吗? UpdateResource 的文档指出lpData不能指向 ANSI 数据,它必须是 Unicode。所以也许使用WideString可能是一个想法?查看here 表明String默认为AnsiString。 -
@icabod 在现代 Delphi 中
string是 UTF-16UnicodeString。 -
@DavidHeffernan:有一个现代德尔福!?!
-
@icabod 有。听起来你落后于时代了。使用古老的德尔福基础知识网站也是一个大错误。 Delphi 文档齐全,文档在线。请跟上! ;-)
-
无法复制,用 XE2 测试了 50000 次重复。