All Windows resource handling APIs (like FindResource, LoadImage, LoadMenu,…) accept at least a resource identifier and an instance handle. This information is required to load the resource. MFC classes (like CMenu, CBitmap, …) only take the identifier as they try to find the module containing the resource on their own. This article discusses how you can load resources by ID (as integer and string) or name (string).
Say you create a menu resource called IDR_MENU_MAIN using Microfot Visual Studio. This will result in the following lines in the resource file:
// .rc file
IDR_MENU_MAIN MENU
BEGIN
POPUP "File"
BEGIN
MENUITEM "Default Entry", ID_FILE_DOIT
MENUITEM "Default Only Entry", ID_FILE_DEFAULTENTRY
END
END
Visual Studio also adds a resource ID definition to the resource.h file:
//resource.h
#define IDR_MENU_MAIN 132
Given the appropriate instance handle, the new menu resource can now be easily loaded by its resource ID:
// .cpp file
HMENU hMenu = NULL;
HMODULE hModule = GetModuleHandle(NULL);
hMenu = ::LoadMenu( hModule, MAKEINTRESOURCE( IDR_MENU_MAIN ) );
Another way to load the resource would be to create a string that contains the resource ID preceded by a number sign (#):
HMENU hMenu = NULL;
HMODULE hModule = GetModuleHandle(NULL);
hMenu = ::LoadMenu( hModule, _T("#132") );
But how do you load the resource by its name? All of the resource APIs accept a resource name. But if you try the following you will get a ERROR_RESOURCE_NAME_NOT_FOUND (1814) error:
hMenu = ::LoadMenu( hModule, _T("IDR_MENU_MAIN") );
This happens as the RC file also includes the resource.h file and therefore the resource compiler replaces IDR_MENU_MAIN in the resource definition with 132. That means, that your menu resource is no longer named „IDR_MENU_MAIN“. Its now called „132“. You can use my utility program „DumpRes.exe“ to see how the resource compiler names your resources.
So… how would you use it?
Say you have an application that has to display a image resource depending on some external circumstance that is given as a string („OK“, „WARNING“, „FAIL“).
You embed three bitmaps in your resource file: „IDB_IMAGE_OK„, „IDB_IMAGE_WARNING„, „IDB_IMAGE_FAIL„. Please don’t forget to put the names in quotes.
In your code you build the string identifier of the image to display by concatenating the base name „IDB_IMAGE_“ with the status („OK“, „WARNING“, „FAIL“) and display it.
CString sImage = _T("IDB_IMAGE_") + m_sState ;
HBITMAP hBmp = (HBITMAP)LoadImage( GetModuleHandle(NULL), sImage, IMAGE_BITMAP, 32,32, LR_SHARED|LR_VGACOLOR );
Doing the same with resource IDs would require a ’switch‘ selection (if possible) or a mapping of states to resource ID.
By the way: the resource identifier string is case insensitive. 🙂
Thanks for the add, I look forward to learning a lot here.
Is there any way we can get resource name like IDR_MENU_MAIN from control ID we get from GetDlgCtrlID ?
Currently I don’t know any.
What can be done depends on what you try to achieve. 😉