Download Source Code and Example
Environment: VC6 95/98/Me/NT/2000/XP
Overview
I personally find the Win32 Resource API to be overly complex for performing
simple operations such as enumerating and copying resources. Some operations
like deleting resources is even missing from the standard Win32 API set. The
classes presented in this article provides a simple interface for enumerating,
adding and removing resources from Win32 image files (.dll/.exe).
Understanding Win32 Resources
This section gives you a conceptual overview of the Win32 resource layout. We
will not go into details about the format of the .rsrc section here.
The diagram above shows an example of a conceptual view of the Win32 resource
tree. Each resource instance (leaf-level) contains the following attributes:
Type | cursors, dialogs, bitmaps, etc |
Name | a Unicode string or a 2-byte numeric identifier |
Language | a 2-byte numeric value indicating the language of the resource instance. E.g., English (U.S.) = 1033, Chinese (Traditional) = 1028 |
Data | the actual data of the resource (e.g. a bitmap image) |
These resource instances live in a Win32 image file as a tree structure. Top
level of the tree hosts the resource types. For each resource type, there can
be multiple resources with the same name, but different language IDs. Those
are organized at the 2nd and 3rd levels of the resource tree. At the leaf-level
is the actual resource data itself.
The Win32 Resource API
Windows NT (Yes, and I mean only NT/2000/XP. Windows 95/98/Me do not support
these APIs. To get cross-platform functionality, check out the Geeworks
Win32 Resource Library) provides some useful APIs for modifying resources
in Win32 image files. For instance, to copy resources from one image file to
another involves the following step:
1. | Set up a recursive loop (using EnumResourceTypes, EnumResourceNames, EnumResourceLanguages) to navigate the resource tree of the source image file and collect the resource attributes. |
2. | Use BeginUpdateResource to open the destination iamge file (not supported on Win9x). |
3. | Load resource data into memory using FindResource and LoadResource (partially supported on Win9x). |
4. | Copy the resource data using UpdateResource (again, not supported on Win9x). |
5. | Close the destination image file to write the changes to the destination image file. |
Not only are they overly complicated, they are not even supported on Win9x
platforms. Details see Microsoft KB article Q271442 and documentation for BeginUpdateResource(),
UpdateResource(), or EditUpdateResource().
The Win32 Resource API C++ Wrapper
Two C++ classes are presented here for manipulating Win32 resources. CWin32ResourceSrc
encapsulates a read-only source for resource copying. It provides a simple,
non-recursive interface for resource enumeration. CWin32ResourceDest provides
functions for adding and removing resources from a Win32 image file.
|
||||||||||||||||
|
Example
See how simple it can be to copy Win32 resources…
void CopyResources(LPCTSTR
Source, LPCTSTR Dest)
{
CWin32ResourceSrc src;
CWin32ResourceDest dest;
if
(!src.Open(Source)) // open the source file for resource enumeration
{
HandleError("unable
to open source file for copying\n");
return;
}
if
(!dest.Open(Dest)) // open the target file for
resource copying
{
HandleError("unable
to open destination file for copying\n");
return;
}
RSRC_TYPE_ARRAY types;
src.EnumTypes(types); // get a list of all the
types
// go through each
type in the source image file
for
(RSRC_TYPE_ITOR iType = types.begin(); iType != types.end(); iType++)
{
RSRC_NAME_ARRAY names;
//
get a list of names for the particular type
src.EnumNames(*iType, names);
//
go through each name within this type
for
(RSRC_NAME_ITOR iName = names.begin(); iName != names.end(); iName++)
{
RSRC_LANG_ARRAY langs;
// get a list of all the language IDs
src.EnumLangs(*iType, *iName, langs);
// go through each lang ID
for (RSRC_LANG_ITOR iLang = langs.begin(); iLang !=
langs.end(); iLang++)
{
LPCTSTR type = *iType;
LPCTSTR name = *iName;
WORD lang = *iLang;
// Add each resource instance with a
particular lang ID
dest.Add(src, type, name, lang);
}
}
//
clean up the names array
EmptyIdArray(names);
}
// clean up the types
array
EmptyIdArray(types);
dest.Close(FALSE);
}