Using resource names in WinAPI

c++, embedded-resource, winapi

Solution

Solution and Results:

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:

- Surround the `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`.

- Alternatively, open the resource script file in any text editor and choose the name like that. Again the idea is to prevent a macro from being generated. So detaching the the resource script and resource header would work, or simply make sure the macro doesn't exist in the header.

Problem

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? Test Code ``` #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` and `HTML`?

Original source

Related problems