Reputation: 4410
In WinAPI, you can access resources via FindResource
and LoadResource
.
According to the documentation for FindResource
, you can specify the name of the resource:
lpName [in]
Type: LPCTSTR
The name of the resource. Alternately, rather than a pointer, this parameter can be MAKEINTRESOURCE(ID), where ID is the integer identifier of the resource. For more information, see the Remarks section below.
I have two questions:
First, this doesn't even seem to be accurate because neither specifying the ID or file name worked. What is the proper value to input for the lpName
argument?
This other question seemed to have this issue as well
Second, I want to know if it is possible to retrieve the file name for the resource at run-time. Is this possible? Or is the file name discarded once the file is packaged as a resource?
#include <Windows.h>
#include <tchar.h>
#include "resource.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
//This is the only test that succeeds.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_DRAWING1), _T("BINARY")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_DRAWING1); BINARY"), _T(""), MB_ICONERROR);
}
//This one fails.
if (!FindResource(hInstance, _T("IDR_DRAWING1"), _T("BINARY")))
{
MessageBox(NULL, _T("\"IDR_DRAWING1\"; BINARY"), _T(""), MB_ICONERROR);
}
//ICON - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), _T("ICON")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), _T("ICON")))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDI_ICON1), RT_ICON))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDI_ICON1); RT_ICON"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDI_ICON1"), RT_ICON))
{
MessageBox(NULL, _T("\"IDI_ICON1\"; RT_ICON"), _T(""), MB_ICONERROR);
}
//HTML - Each fails.
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), _T("HTML")))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), _T("HTML")))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, MAKEINTRESOURCE(IDR_HTML1), RT_HTML))
{
MessageBox(NULL, _T("MAKEINTRESOURCE(IDR_HTML1); RT_HTML"), _T(""), MB_ICONERROR);
}
if (!FindResource(hInstance, _T("IDR_HTML1"), RT_HTML))
{
MessageBox(NULL, _T("\"IDR_HTML1\"; RT_HTML"), _T(""), MB_ICONERROR);
}
return 0;
}
Resource.rc
This isn't the entire file because it contains a lot of boiler-plate code. Here are the relevant resource declarations.
IDR_DRAWING1 BINARY "Drawing1.dwg"
IDI_ICON1 ICON "icon1.ico"
IDR_HTML1 HTML "html1.htm"
The .ico and the .htm were created automatically using Visual Studio; by adding new resources of the corresponding type. So their format shouldn't be messing up the FindResource
statement.
resource.h
#define IDR_DRAWING1 101
#define IDI_ICON1 102
#define IDR_HTML1 103
EDIT:
Per Ben Voigt's comment, I've gone ahead and changed the Resource.rc file so non-numeric names are used:
DWG1 BINARY "Drawing1.dwg" ICON1 ICON "icon1.ico" HTML1 HTML "html1.htm"
Now, the resource.h file isn't used at all. Following are the new relevant tests:
FindResource(hInstance, _T("DWG1"), _T("BINARY")); //Succeeds now. FindResource(hInstance, _T("ICON1"), _T("ICON")); //Still fails. FindResource(hInstance, _T("ICON1"), RT_ICON); //Still fails. FindResource(hInstance, _T("HTML1"), _T("HTML")); //Still fails. FindResource(hInstance, _T("HTML1"), RT_HTML); //Still fails.
So, my expectations are met for my binary resource, but what is happening with the
ICON
andHTML
?
Upvotes: 4
Views: 5490
Reputation: 4410
Okay, so I've finally got a predictable results.
The way you find the resource is partially dependent on the resource type. In this case, DWG1
is a BINARY
resource which is a custom type. There does not exist a predefined RT_*
among the resource types, so you will need to specify the type as an LPCTSTR
:
FindResource(hInstance, _T("DWG1"), _T("BINARY"));
For a predefined resource type, you cannot specify the type name as a LPCTSTR
. Instead you must use the corresponding RT_*
value. This is probably because each RT_*
value corresponds to a MAKEINTRESOURCE(WORD)
, and if my understanding is correct, that macro result points to an invalid address within the portable executable file, not to a textual representation of the resource type.
This questions addresses MAKEINTRESOURCE
The issue with the ICON1
resource was that the type should have been RT_GROUP_ICON
instead of RT_ICON
. The difference of these two types is that the former is hardware-independent and the latter is hardware-dependent. Though, I do not know why RT_ICON
didn't work.
Last, the issue with HTML1
was a fault on my part because I hadn't made sure that the referenced file actually had data. During the build, it was probably omitted since it was essentially a null resource. The correct type to use for this resource is RT_HTML
.
Now, in regards to the names. As mentioned by Ben Voigt in a comment to his answer, non-numeric names are required in order to specify the name as a LPCTSTR
. If numeric names are used, then one must use MAKEINTRESOURCE
instead.
Visual Studio's resource editor makes it a bit cumbersome to name resources with strings instead of numbers, since by default it creates macros for each resource. These macros then replace the resource name with a number during the preprocessing phase.
In order to change the name into a string, you have 2 options:
ID
of the resource (found in the properties) with double quotes. This prevents the resource editor from creating a macro for the name. However, a macro might already exist if quotations were placed around a previously set ID
.
Upvotes: 5
Reputation: 283803
is the file name discarded once the file is packaged as a resource?
Yes, exactly.
For example, in the ICON statement the first column is the resource name, and the third column is the filename..
nameID ICON filename
And some resources don't come from external files at all, for example the MENU statement gets its data from nested MENU
and MENUITEM
statements directly in the resource script. DIALOG
, STRINGTABLE
, VERSION
, and VERSIONINFO
are just a few of the other common resources that don't exist as separate files.
Upvotes: 2