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

将资源正确地包含到Delphi包中,delphi,embedded-resource,Delphi,Embedded Resource,我编写了一个Delphi包,其中两个组件使用相同的PNG资源,我使用以下脚本将其放入GraphContour.res文件中: 编译_res.bat: @brcc32 GraphContour.rc GraphContour.rc: GRAPH_CONTOUR RCDATA GraphContour.png 如果组件的两个单元都包含{$R GraphContour.res}指令,则组件可以工作,但我得到一个编译器警告: [dcc32提示]H2161警告:重复资源:类型10(RCDATA),ID

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

编译_res.bat:

@brcc32 GraphContour.rc
GraphContour.rc:

GRAPH_CONTOUR RCDATA GraphContour.png
如果组件的两个单元都包含
{$R GraphContour.res}
指令,则组件可以工作,但我得到一个编译器警告:

[dcc32提示]H2161警告:重复资源:类型10(RCDATA),ID图\u轮廓;保存文件C:\Borland\Components\MyControls\GraphContour.res资源;文件C:\Borland\Components\MyControls\GraphContour.res资源已丢弃

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

{$R *.res}
{$R GraphContour.res}
警告消失,我可以编译包,资源在设计时显示,但在运行时出现错误:

Project ComponentTest.exe引发异常类EResNotFound,消息为“未找到资源图”

这两个控件之一的一位代码:

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;
我用binary viewer查看BPL文件,发现GRAPH_轮廓字符串名就在那个里


我尝试使用
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.

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

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

一些选择:

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

  • FindClassHInstance
    工作正常。我们看不到使用它的代码。我们也不知道
    TMyDisplay
    驻留在哪里。在包含两个控件的包中?在这种情况下,
    HInstance
    是正确的。因此HInstance是正确的。不,它不包含垃圾。我在WriteFile中错误地使用了指针。现在我已经更新了这个问题。所以我想你的下一个调试任务是理解为什么你的代码会产生
    EResNotFound
    。一种可能是您没有使用运行时包。也许您正在将组件的源代码直接编译到可执行文件中。您不需要任何文章。只需创建一个不包含代码,但链接资源的单元。从两个组件源文件中使用该单元。在包和可执行文件中包含该单元。好吗?如果您需要将组件注册到IDE中,以便在设计时将它们添加到窗体和其他设计表面,那么您需要将它们编译到设计时包中,并向IDE注册。对于运行时,您可以直接包含源文件,也可以链接到运行时包。在后一种情况下,您需要同时拥有运行时和设计时包。后者需要(取决于)前者。这是一个重要的话题,一个不经得起如此评论的文档的话题!