正确地将资源包含到Delphi包中

时间:2017-09-11 11:44:24

标签: delphi embedded-resource

我编写了一个Delphi软件包,其中两个组件使用相同的PNG资源,我使用以下脚本将其放在GraphContour.res文件中:

compile_res.bat:

@brcc32 GraphContour.rc

GraphContour.rc:

GRAPH_CONTOUR RCDATA GraphContour.png

如果两个组件单元都包含{$R GraphContour.res}指令,那么组件可以工作,但我收到编译器警告:

  

[dcc32提示] H2161警告:资源重复:输入10(RCDATA),ID GRAPH_CONTOUR;保存文件C:\ Borland \ Components \ MyControls \ GraphContour.res资源;文件C:\ Borland \ Components \ MyControls \ GraphContour.res资源被丢弃。

如果我从将它放入DPK文件的单位中删除{$R GraphContour.res}指令:

{$R *.res}
{$R GraphContour.res}

警告消失,我可以编译包,资源在设计时显示,但在运行时我收到错误:

  

Project ComponentTest.exe引发了异常类EResNotFound,并显示消息“未找到资源GRAPH_CONTOUR”。

来自这两个控件之一的一些代码:

procedure TMyDisplay.CreateWnd();
var png: TPngImage;
begin
  inherited;
  //......................
  png := TPngImage.Create;
  try
    png.LoadFromResourceName(HInstance, 'GRAPH_CONTOUR'); //Error is here
    _knob.Center.Picture.Graphic := png;
  finally
    png.Free();
  end;
  //......................
end;

我用二进制查看器查看了BPL文件,发现GRAPH_CONTOUR字符串名称就在那里。

我尝试使用FindClassHInstance代替HInstance。它没有帮助。

png.LoadFromResourceName(FindClassHInstance(Self.ClassType), 'GRAPH_CONTOUR');

如何正确地将资源包含在BPL中?

更新

以下是我用来检查资源可用性的测试应用程序:

program Loadres;

uses Winapi.Windows;

procedure PrintLastError();
var
  cchMsg, code: Cardinal;
  buf: array[0..512] of WideChar;
begin
  code := GetLastError();
  cchMsg := FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM or FORMAT_MESSAGE_IGNORE_INSERTS,
    nil, code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), @buf, SizeOf(buf), nil);
  MessageBoxW(0, @buf, 'Error', MB_ICONERROR);
end;

var
  hm, hResInfo, hResData, hPngFile: NativeUInt;
  rp: Pointer;
  wb, rs: Cardinal;

begin
  hm := LoadLibrary('C:\Documents and Settings\All Users\Documents\Embarcadero\Studio\17.0\Bpl\MyControls.bpl');
  if hm = 0 then begin PrintLastError(); Exit; end;
  try
    hResInfo := FindResource(hm, 'GRAPH_CONTOUR', RT_RCDATA);
    if hResInfo = 0 then begin PrintLastError(); Exit; end;
    hResData := LoadResource(hm, hResInfo);
    if hResData = 0 then begin PrintLastError(); Exit; end;
    rs := SizeofResource(hm, hResInfo);
    rp := LockResource(hResData);
    try
      hPngFile := CreateFile('TheContour.png', GENERIC_WRITE, 0, nil, CREATE_ALWAYS,
        FILE_ATTRIBUTE_NORMAL, 0);
      try
        WriteFile(hPngFile, rp^, rs, wb, nil);
      finally
        CloseHandle(hPngFile);
      end;
    finally
      UnlockResource(hResData);
    end;
  finally
    FreeLibrary(hm);
  end;
end.

它查找资源,报告正确的资源大小,并将资源写入文件。该文件与原始文件匹配。

1 个答案:

答案 0 :(得分:3)

根据您所做的调试并在注释中进行了描述,问题是您的可执行程序未使用运行时包。相反,它直接将源文件编译为可执行文件。由于它们不再链接资源,因此它不存在于可执行文件中。

一些选项:

  1. 使用运行时包。这可能需要您将当前包拆分为设计时和运行时包。
  2. 将资源放入一个单独的单元(不需要任何代码,只需要链接的资源)。在您的designtime包和可执行文件中包含该单元。如果您安排组件源文件使用该资源单元,那么它将被强制包含在需要资源的任何模块中。