在Delphi中列出具有名称和类型的资源
我试图列出我的程序的所有资源,资源名称和资源类型为“RT_位图”或任何其他 守则:在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 +
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
成为有效指针。真是太棒了,哈哈。谢谢大卫·赫弗南