List Resources with name and type in Delphi












1















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 ?










share|improve this question

























  • 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


















1















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 ?










share|improve this question

























  • 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
















1












1








1








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 ?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 signature lpszType 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











  • 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



















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














1 Answer
1






active

oldest

votes


















3














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 returns True, 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.





share|improve this answer


























  • Thanks David Heffernan

    – FF2
    Mar 24 '16 at 19:39











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
});


}
});














draft saved

draft discarded


















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









3














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 returns True, 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.





share|improve this answer


























  • Thanks David Heffernan

    – FF2
    Mar 24 '16 at 19:39
















3














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 returns True, 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.





share|improve this answer


























  • Thanks David Heffernan

    – FF2
    Mar 24 '16 at 19:39














3












3








3







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 returns True, 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.





share|improve this answer















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 returns True, 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.






share|improve this answer














share|improve this answer



share|improve this answer








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



















  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Full-time equivalent

Bicuculline

さくらももこ