在Delphi中列出具有名称和类型的资源

在Delphi中列出具有名称和类型的资源,delphi,winapi,resources,Delphi,Winapi,Resources,我试图列出我的程序的所有资源,资源名称和资源类型为“RT_位图”或任何其他 守则: var Form1: TForm1; list_resources: string; function EnumResNameProc(lpszName: PChar; lParam: integer; lpszType: PChar; hModule: Cardinal): BOOL; begin list_resources := list_resources + sLineBreak +

我试图列出我的程序的所有资源,资源名称和资源类型为“RT_位图”或任何其他

守则:

var
  Form1: TForm1;
  list_resources: string;

function EnumResNameProc(lpszName: PChar; lParam: integer; lpszType: PChar;
  hModule: Cardinal): BOOL;
begin
  list_resources := list_resources + sLineBreak + lpszName + ' - ' + lpszType;
  Result := True;
end;

procedure TForm1.btnListResourcesClick(Sender: TObject);
begin
  EnumResourceNames(0, RT_RCDATA, @EnumResNameProc, 0);
  Memo1.Lines.Add(list_resources);
end;

代码运行良好,但从未显示资源的类型,问题是什么?

代码的第一个问题是回调函数的调用约定和签名错误。应该这样宣布:

function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar; 
  lParam: LONG_PTR): BOOL; stdcall;
代码生成的输出完全是偶然的。获得这些函数的正确签名非常重要。我不知道你的签名来自哪里。看起来是你编的!MSDN上的文档具有正确的签名。Embarcadero以一种忽略签名类型检查的方式声明接受回调的API函数,这让事情变得困难。所以责任落在你的头上。仔细阅读文档

一旦你解决了这个问题,还有更多的工作要做。资源类型和资源名称可以是整数或字符串。约定是<65536的值被解释为整数,否则该值是指向以null结尾的字符数组的指针。您可以调用Windows宏的Delphi翻译,而不是硬编码这个神奇常量

在本例中,您将接收命名资源,但资源类型实际上是整数值。从Windows单元:

const
  RT_CURSOR       = MakeIntResource(1);
  RT_BITMAP       = MakeIntResource(2);
  RT_ICON         = MakeIntResource(3);
  RT_MENU         = MakeIntResource(4);
  RT_DIALOG       = MakeIntResource(5);
  RT_STRING       = MakeIntResource(6);
  RT_FONTDIR      = MakeIntResource(7);
  RT_FONT         = MakeIntResource(8);
  RT_ACCELERATOR  = MakeIntResource(9);
  RT_RCDATA       = System.Types.RT_RCDATA; //MakeIntResource(10);
  DIFFERENCE = 11;
  RT_GROUP_CURSOR = MakeIntResource(DWORD(RT_CURSOR) + DIFFERENCE);
  RT_GROUP_ICON   = MakeIntResource(DWORD(RT_ICON) + DIFFERENCE);
  RT_VERSION      = MakeIntResource(16);
  RT_DLGINCLUDE   = MakeIntResource(17);
  RT_PLUGPLAY     = MakeIntResource(19);
  RT_VXD          = MakeIntResource(20);
  RT_ANICURSOR    = MakeIntResource(21);
  RT_ANIICON      = MakeIntResource(22);
  RT_HTML         = MakeIntResource(23);
  RT_MANIFEST     = MakeIntResource(24);
另一个惯例是使用
#
符号表示数字标识符。因此,您可以采取以下政策:

  • 如果
    Is_IntResource
    返回
    True
    ,则将数值转换为字符串和前缀
  • 否则,将其视为指向以null结尾的字符数组的指针
代码非常简单:

function ResourceNameToString(lpszName: PChar): string;
begin
  if Is_IntResource(lpszName) then
    Result := '#' + IntToStr(NativeUInt(lpszName))
  else
    Result := lpszName;
end;
对于名称和类型,您必须这样做。否则,当代码尝试取消引用实际表示整数的指针时,它将失败并出现运行时访问冲突错误。如果您修复了回调签名,但没有进一步的更改,那么问题中的代码将以这种方式失败

如果您希望您的代码更有用,您将检测预定义的资源类型并对其进行特殊处理

function ResourceTypeToString(lpszType: PChar): string;
begin
  case NativeUInt(lpszType) of
  NativeUInt(RT_CURSOR):
    Result := 'RT_CURSOR';
  NativeUInt(RT_BITMAP):
    Result := 'RT_BITMAP';
  NativeUInt(RT_RCDATA):
    Result := 'RT_RCDATA';
  // etc.
  else
    Result := ResourceNameToString(lpszType);
  end;
end;
我将让您填写缺少的值

把它们放在一起,就像这样:

{$APPTYPE CONSOLE}

uses
  SysUtils, Windows;

function ResourceNameToString(lpszName: PChar): string;
begin
  if Is_IntResource(lpszName) then
    Result := '#' + IntToStr(NativeUInt(lpszName))
  else
    Result := lpszName;
end;

function ResourceTypeToString(lpszType: PChar): string;
begin
  case NativeUInt(lpszType) of
  NativeUInt(RT_CURSOR):
    Result := 'RT_CURSOR';
  NativeUInt(RT_BITMAP):
    Result := 'RT_BITMAP';
  NativeUInt(RT_RCDATA):
    Result := 'RT_RCDATA';
  // etc.
  else
    Result := ResourceNameToString(lpszType);
  end;
end;

function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar; 
  lParam: LONG_PTR): BOOL; stdcall;
begin
  Writeln(ResourceTypeToString(lpszType) + ' - ' + ResourceNameToString(lpszName));
  Result := True;
end;

begin
  EnumResourceNames(0, RT_RCDATA, @EnumResNameProc, 0);
  Readln;
end.

这段代码不应该因为segfault而崩溃吗?我不会有任何错误,它显示的是名称,但不是类型,我用Delphi在Windows7 64位上进行了尝试XE2@Free错误的呼叫约定和错误的签名的结合意味着,令人惊讶的是,它没有区分错误。@DavidHeffernan,噢,没有注意到由于签名不正确,
lpszType
成为有效指针。真是太棒了,哈哈。谢谢大卫·赫弗南