Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 为什么将大型资源添加到exe会很慢,有时会损坏exe?_Delphi_Delphi Xe2 - Fatal编程技术网

Delphi 为什么将大型资源添加到exe会很慢,有时会损坏exe?

Delphi 为什么将大型资源添加到exe会很慢,有时会损坏exe?,delphi,delphi-xe2,Delphi,Delphi Xe2,我正在自己的代码中尝试Mad集合(用于添加/删除或更新exe中资源的单元)中Madres单元的不同功能。这对于较小的资源(小于50MB)很好,但对于较大的资源(大于50MB)通常会失败 下面代码的主要问题是:应用程序冻结数分钟,有时会崩溃并创建损坏的exe 有谁能提出更好的方法来解决这个问题吗 //add resource procedure UpdateExeResource(Const Source,Dest:string); var Stream : TFileStream;

我正在自己的代码中尝试Mad集合(用于添加/删除或更新exe中资源的单元)中Madres单元的不同功能。这对于较小的资源(小于50MB)很好,但对于较大的资源(大于50MB)通常会失败

下面代码的主要问题是:应用程序冻结数分钟,有时会崩溃并创建损坏的exe

有谁能提出更好的方法来解决这个问题吗

//add resource
procedure UpdateExeResource(Const Source,Dest:string);
var
  Stream     : TFileStream;
  hDestRes   : DWORD;
  lpData     : Pointer;
  cbData     : DWORD;
begin
  Stream := TFileStream.Create(Source,fmOpenRead or fmShareDenyNone);
  try
    Stream.Seek(0, soFromBeginning);
    cbData:=Stream.Size;
    if cbData>0 then
    begin
      GetMem(lpData,cbData);
      try
        Stream.Read(lpData^, cbData);
        hDestRes:= BeginUpdateResourceW(PChar(Dest), False);
        if hDestRes <> 0 then

          if UpdateResourceW(hDestRes, RT_RCDATA,'DATA',0,lpData,cbData) then
          begin
            if not EndUpdateResourceW(hDestRes,FALSE) then RaiseLastOSError
          end
          else
          RaiseLastOSError
        else
        RaiseLastOSError;
      finally
        FreeMem(lpData);
      end;
    end;
  finally
    Stream.Free;
  end;
end;

//Add or update resource
procedure TForm1.Button1Click(Sender: TObject);
begin
  UpdateExeResource('asd.txt', 'copy.exe');
end;
//添加资源
过程UpdateExeResource(常量源,Dest:string);
变量
流:TFileStream;
hDestRes:DWORD;
lpData:指针;
cbData:DWORD;
开始
Stream:=TFileStream.Create(源、fmOpenRead或fmsharedynone);
尝试
Stream.Seek(0,sopromseagin);
cbData:=Stream.Size;
如果cbData>0,则
开始
GetMem(lpData,cbData);
尝试
Stream.Read(lpData^,cbData);
hDestRes:=BeginUpdateResource(PChar(Dest),False);
如果hDestRes为0,则
如果UpdateResourceW(hDestRes,RT_RCDATA,'DATA',0,lpData,cbData),则
开始
如果不是EndUpdateResourceW(hDestRes,FALSE),则为RAISELASTERROR
结束
其他的
赖斯
其他的
赖斯·塞罗;
最后
FreeMem(lpData);
结束;
结束;
最后
免费;
结束;
结束;
//添加或更新资源
程序TForm1.按钮1单击(发送方:TObject);
开始
UpdateExeResource('asd.txt','copy.exe');
结束;

您使用Madres单元的理由是什么?Madres单元只不过是对Windows API调用函数的欺骗,并且是为了增加对旧Windows 9x系列(Win95、98、ME)的支持

我建议您(正确地)修改您的过程以引用实际的Winapi.Windows函数调用,方法是从uses节中删除Madres unit,或者在调用函数时向其添加前缀,如下所示:

  Winapi.Windows.BeginUpdateResourceW(...);
  Winapi.Windows.UpdateResourceW(...);
  Winapi.Windows.EndUpdateResourceW(...);
如果您需要对9x系列的支持,那么只需创建一个单独的方法来使用madresapi调用,并在实际需要时使用它


还要注意的是,UpdateResourceW希望它的字符串参数是Unicode格式。

如果这是MadCode,您是否在Madshis论坛上询问过?这是一个自定义代码,但使用madres。此处的代码不使用madres。它使用原始Win32。你的病毒扫描器会碍事吗?当你关闭它时会发生什么?关闭主题,但你的共享模式是错误的。您需要
fmShareDenyWrite
。另外,我会使用内存流来加载文件。创建内存流,调用
LoadFromFile
,然后将指向内存的指针传递到
UpdateResourceW
@jimsweb:理论上,Windows可以根据需要将.exe的一部分分页到内存中——因此,在加载资源之前,大型资源根本不会影响程序加载。实际上,你的病毒扫描器在让Windows执行之前会扫描整个.exe,所以除非有很好的理由,否则不要在你的exe中嵌入额外的资源,如果这样做的话,请将它们保持在较小的范围内。数字签名的可执行文件在签名被验证时也会被全部扫描——我不知道Windows是否或何时会自动进行扫描。根据madres帮助:NT API也不像你想象的那么可靠。如果在Delphi二进制文件(其中包含TD32调试信息)上使用资源更新API,则该二进制文件随后将完全无效。Windows甚至不再将其识别为有效的PE文件。NT资源更新API的另一个缺点是,如果删除资源,资源部分的大小通常不会调整。所以你的二进制文件比它必须的要大这就是我坚持使用madresWindows API ResourceUpdate方法的原因。更新“Delphi”二进制可执行文件中的资源没有问题,您得到损坏二进制文件的唯一原因是您错误地使用了这些函数,有关Win Api UpdateResource方法的示例实现,请参阅超链接或搜索。
UpdateResourceW
不需要Unicode格式的数据。它希望其参数是Unicode字符串而不是ANSI字符串。数据就是数据。如果需要,可以使用
UpdateResourceA
编写Unicode编码的数据。您不能给资源一个Unicode名称。@Nortd:如果在发布模式下编译我的应用程序,即没有任何调试信息,您的建议就可以了