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

时间:2016-03-24 15:00:51

标签: delphi winapi resources

我试图用资源和资源类型的名称列出我的程序的所有资源,如#34; RT_BITMAP"或任何其他。

代码:

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;

代码工作正常但从未显示资源类型,问题是什么?

1 个答案:

答案 0 :(得分:2)

您的代码的第一个问题是回调函数具有错误的调用约定和错误的签名。它应该像这样声明:

function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar; 
  lParam: LONG_PTR): BOOL; stdcall;

您的代码生成的输出完全是偶然的。让这些函数的签名正确是非常重要的。我不知道你的签名来自哪里。看起来你刚刚成功了! MSDN上的文档具有正确的签名。 Embarcadero通过声明接受回调的API函数使得事情变得艰难,这意味着忽略了对签名的类型检查。因此责任落在你的身上。请仔细阅读文档。

一旦解决了这个问题,还有很多工作要做。资源类型,实际上是资源名称,可以是整数或字符串。惯例是值< 65536被解释为整数,否则该值是指向以null结尾的字符数组的指针。您可以改为调用Is_IntResource,即Windows宏IS_INTRESOURCE的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.