List Resources with name and type in Delphi
I'm trying to list all the resources of my program with the name of the resource and resource type as "RT_BITMAP" or any other.
The code :
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;
The code work good but never show the type of resource , what is the problem ?
delphi winapi resources
add a comment |
I'm trying to list all the resources of my program with the name of the resource and resource type as "RT_BITMAP" or any other.
The code :
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;
The code work good but never show the type of resource , what is the problem ?
delphi winapi resources
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
1
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@DavidHeffernan, oh, didn't noticed that due incorrect signaturelpszType
becomes a valid pointer. Truly amazing case, LOL.
– Free Consulting
Mar 25 '16 at 8:16
add a comment |
I'm trying to list all the resources of my program with the name of the resource and resource type as "RT_BITMAP" or any other.
The code :
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;
The code work good but never show the type of resource , what is the problem ?
delphi winapi resources
I'm trying to list all the resources of my program with the name of the resource and resource type as "RT_BITMAP" or any other.
The code :
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;
The code work good but never show the type of resource , what is the problem ?
delphi winapi resources
delphi winapi resources
edited Mar 24 '16 at 15:51
David Heffernan
518k348211213
518k348211213
asked Mar 24 '16 at 15:00
FF2FF2
304
304
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
1
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@DavidHeffernan, oh, didn't noticed that due incorrect signaturelpszType
becomes a valid pointer. Truly amazing case, LOL.
– Free Consulting
Mar 25 '16 at 8:16
add a comment |
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
1
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@DavidHeffernan, oh, didn't noticed that due incorrect signaturelpszType
becomes a valid pointer. Truly amazing case, LOL.
– Free Consulting
Mar 25 '16 at 8:16
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
1
1
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@DavidHeffernan, oh, didn't noticed that due incorrect signature
lpszType
becomes a valid pointer. Truly amazing case, LOL.– Free Consulting
Mar 25 '16 at 8:16
@DavidHeffernan, oh, didn't noticed that due incorrect signature
lpszType
becomes a valid pointer. Truly amazing case, LOL.– Free Consulting
Mar 25 '16 at 8:16
add a comment |
1 Answer
1
active
oldest
votes
The first problem with your code is that the callback function has the wrong calling convention and indeed the wrong signature. It should be declared like this:
function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar;
lParam: LONG_PTR): BOOL; stdcall;
The output that your code was producing was completely accidental. It's really important that you get the signatures of these function correct. I don't know where your signature came from. It looks like you just made it up! The documentation on MSDN has the correct signature. Embarcadero make things hard by declaring the API functions that accept callbacks in a way that means type checking for the signatures is neglected. So the onus falls on your. Read the documentation very carefully.
Once you have fixed that problem, there is still more to be done. Resource types, and indeed resource names, can either be integers or strings. The convention is that values < 65536 are interpreted as integers, otherwise the value is a pointer to a null-terminated character array. Rather than hard-code that magic constant, you can instead call Is_IntResource
, the Delphi translation of the Windows macro IS_INTRESOURCE
.
In your case you will be receiving named resources, but resource types that are actually integer values. From the Windows unit:
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);
The other convention at play is that you use a #
symbol to indicate a numeric identifier. So you could adopt the following policy:
- If
Is_IntResource
returnsTrue
, then convert the numeric value to string and prefix with#
. - Otherwise treat as a pointer to null-terminated character array.
The code is quite simple:
function ResourceNameToString(lpszName: PChar): string;
begin
if Is_IntResource(lpszName) then
Result := '#' + IntToStr(NativeUInt(lpszName))
else
Result := lpszName;
end;
It's imperative that you do this, for names as well as types. Otherwise your code will fail with runtime access violation errors when it tries to de-reference a pointer that is actually representing an integer. The code in the question will fail that way if you fixed the callback signature but make no further changes.
If you want your code to be more helpful you will detect the pre-defined resource types and give them special treatment.
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;
I'll let you fill in the missing values.
Put it all together like so:
{$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.
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f36203323%2flist-resources-with-name-and-type-in-delphi%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
The first problem with your code is that the callback function has the wrong calling convention and indeed the wrong signature. It should be declared like this:
function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar;
lParam: LONG_PTR): BOOL; stdcall;
The output that your code was producing was completely accidental. It's really important that you get the signatures of these function correct. I don't know where your signature came from. It looks like you just made it up! The documentation on MSDN has the correct signature. Embarcadero make things hard by declaring the API functions that accept callbacks in a way that means type checking for the signatures is neglected. So the onus falls on your. Read the documentation very carefully.
Once you have fixed that problem, there is still more to be done. Resource types, and indeed resource names, can either be integers or strings. The convention is that values < 65536 are interpreted as integers, otherwise the value is a pointer to a null-terminated character array. Rather than hard-code that magic constant, you can instead call Is_IntResource
, the Delphi translation of the Windows macro IS_INTRESOURCE
.
In your case you will be receiving named resources, but resource types that are actually integer values. From the Windows unit:
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);
The other convention at play is that you use a #
symbol to indicate a numeric identifier. So you could adopt the following policy:
- If
Is_IntResource
returnsTrue
, then convert the numeric value to string and prefix with#
. - Otherwise treat as a pointer to null-terminated character array.
The code is quite simple:
function ResourceNameToString(lpszName: PChar): string;
begin
if Is_IntResource(lpszName) then
Result := '#' + IntToStr(NativeUInt(lpszName))
else
Result := lpszName;
end;
It's imperative that you do this, for names as well as types. Otherwise your code will fail with runtime access violation errors when it tries to de-reference a pointer that is actually representing an integer. The code in the question will fail that way if you fixed the callback signature but make no further changes.
If you want your code to be more helpful you will detect the pre-defined resource types and give them special treatment.
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;
I'll let you fill in the missing values.
Put it all together like so:
{$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.
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
add a comment |
The first problem with your code is that the callback function has the wrong calling convention and indeed the wrong signature. It should be declared like this:
function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar;
lParam: LONG_PTR): BOOL; stdcall;
The output that your code was producing was completely accidental. It's really important that you get the signatures of these function correct. I don't know where your signature came from. It looks like you just made it up! The documentation on MSDN has the correct signature. Embarcadero make things hard by declaring the API functions that accept callbacks in a way that means type checking for the signatures is neglected. So the onus falls on your. Read the documentation very carefully.
Once you have fixed that problem, there is still more to be done. Resource types, and indeed resource names, can either be integers or strings. The convention is that values < 65536 are interpreted as integers, otherwise the value is a pointer to a null-terminated character array. Rather than hard-code that magic constant, you can instead call Is_IntResource
, the Delphi translation of the Windows macro IS_INTRESOURCE
.
In your case you will be receiving named resources, but resource types that are actually integer values. From the Windows unit:
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);
The other convention at play is that you use a #
symbol to indicate a numeric identifier. So you could adopt the following policy:
- If
Is_IntResource
returnsTrue
, then convert the numeric value to string and prefix with#
. - Otherwise treat as a pointer to null-terminated character array.
The code is quite simple:
function ResourceNameToString(lpszName: PChar): string;
begin
if Is_IntResource(lpszName) then
Result := '#' + IntToStr(NativeUInt(lpszName))
else
Result := lpszName;
end;
It's imperative that you do this, for names as well as types. Otherwise your code will fail with runtime access violation errors when it tries to de-reference a pointer that is actually representing an integer. The code in the question will fail that way if you fixed the callback signature but make no further changes.
If you want your code to be more helpful you will detect the pre-defined resource types and give them special treatment.
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;
I'll let you fill in the missing values.
Put it all together like so:
{$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.
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
add a comment |
The first problem with your code is that the callback function has the wrong calling convention and indeed the wrong signature. It should be declared like this:
function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar;
lParam: LONG_PTR): BOOL; stdcall;
The output that your code was producing was completely accidental. It's really important that you get the signatures of these function correct. I don't know where your signature came from. It looks like you just made it up! The documentation on MSDN has the correct signature. Embarcadero make things hard by declaring the API functions that accept callbacks in a way that means type checking for the signatures is neglected. So the onus falls on your. Read the documentation very carefully.
Once you have fixed that problem, there is still more to be done. Resource types, and indeed resource names, can either be integers or strings. The convention is that values < 65536 are interpreted as integers, otherwise the value is a pointer to a null-terminated character array. Rather than hard-code that magic constant, you can instead call Is_IntResource
, the Delphi translation of the Windows macro IS_INTRESOURCE
.
In your case you will be receiving named resources, but resource types that are actually integer values. From the Windows unit:
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);
The other convention at play is that you use a #
symbol to indicate a numeric identifier. So you could adopt the following policy:
- If
Is_IntResource
returnsTrue
, then convert the numeric value to string and prefix with#
. - Otherwise treat as a pointer to null-terminated character array.
The code is quite simple:
function ResourceNameToString(lpszName: PChar): string;
begin
if Is_IntResource(lpszName) then
Result := '#' + IntToStr(NativeUInt(lpszName))
else
Result := lpszName;
end;
It's imperative that you do this, for names as well as types. Otherwise your code will fail with runtime access violation errors when it tries to de-reference a pointer that is actually representing an integer. The code in the question will fail that way if you fixed the callback signature but make no further changes.
If you want your code to be more helpful you will detect the pre-defined resource types and give them special treatment.
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;
I'll let you fill in the missing values.
Put it all together like so:
{$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.
The first problem with your code is that the callback function has the wrong calling convention and indeed the wrong signature. It should be declared like this:
function EnumResNameProc(hModule: HMODULE; lpszType, lpszName: PChar;
lParam: LONG_PTR): BOOL; stdcall;
The output that your code was producing was completely accidental. It's really important that you get the signatures of these function correct. I don't know where your signature came from. It looks like you just made it up! The documentation on MSDN has the correct signature. Embarcadero make things hard by declaring the API functions that accept callbacks in a way that means type checking for the signatures is neglected. So the onus falls on your. Read the documentation very carefully.
Once you have fixed that problem, there is still more to be done. Resource types, and indeed resource names, can either be integers or strings. The convention is that values < 65536 are interpreted as integers, otherwise the value is a pointer to a null-terminated character array. Rather than hard-code that magic constant, you can instead call Is_IntResource
, the Delphi translation of the Windows macro IS_INTRESOURCE
.
In your case you will be receiving named resources, but resource types that are actually integer values. From the Windows unit:
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);
The other convention at play is that you use a #
symbol to indicate a numeric identifier. So you could adopt the following policy:
- If
Is_IntResource
returnsTrue
, then convert the numeric value to string and prefix with#
. - Otherwise treat as a pointer to null-terminated character array.
The code is quite simple:
function ResourceNameToString(lpszName: PChar): string;
begin
if Is_IntResource(lpszName) then
Result := '#' + IntToStr(NativeUInt(lpszName))
else
Result := lpszName;
end;
It's imperative that you do this, for names as well as types. Otherwise your code will fail with runtime access violation errors when it tries to de-reference a pointer that is actually representing an integer. The code in the question will fail that way if you fixed the callback signature but make no further changes.
If you want your code to be more helpful you will detect the pre-defined resource types and give them special treatment.
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;
I'll let you fill in the missing values.
Put it all together like so:
{$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.
edited Mar 24 '16 at 15:51
answered Mar 24 '16 at 15:08
David HeffernanDavid Heffernan
518k348211213
518k348211213
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
add a comment |
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
Thanks David Heffernan
– FF2
Mar 24 '16 at 19:39
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f36203323%2flist-resources-with-name-and-type-in-delphi%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Shouldn't this code crash with segfault?
– Free Consulting
Mar 24 '16 at 18:42
I would not have any error, it showed the name but not the type, I tried it on Windows 7 64-bit with Delphi XE2
– FF2
Mar 24 '16 at 19:39
1
@Free The combination of wrong calling convention and wrong signature meant that, amazingly, it did not seg fault.
– David Heffernan
Mar 24 '16 at 19:50
@DavidHeffernan, oh, didn't noticed that due incorrect signature
lpszType
becomes a valid pointer. Truly amazing case, LOL.– Free Consulting
Mar 25 '16 at 8:16