Thursday, September 27, 2007

MAKEINTRESOURCE macro

Many Win32 API functions use a LPCTSTR parameter as resource name or type.
For example, a trivial one:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);

And the documentation for the lpIconName states that:

Pointer to a null-terminated string that contains the name of the icon resource to be loaded. Alternatively, this parameter can contain the resource identifier in the low-order word and zero in the high-order word. Use the MAKEINTRESOURCE macro to create this value.

Now, how the LoadIcon code knows to diferentiate between a resource string name and a predefined constant like IDI_ASTERISK which is defined as:

#define IDI_ASTERISK MAKEINTRESOURCE(32516)

We are used to the wizard generated resource IDs in our applications but a resource can have any null terminated string as name and type too. Look to the FindResource function for example.

All resource Win32API functions use the macro IS_INTRESOURCE(id)

BOOL IS_INTRESOURCE(
WORD wInteger
);

#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)

If the macro is TRUE then the id "specifies the integer identifier of the name or type of the given resource. Otherwise, those parameters are long pointers to null-terminated strings"

Practically, the memory address of a name or type passed as input, is checked to see if its within the WORD boundary, or else said if the memory address is between 0 and unsigned short (65536), because:

typedef unsigned short WORD;

So, for the win32 API functions, if the pointer value has an 'invalid address' it's clear that it's rather an id (a integer, an unsisgned short in fact) then an actual memory address containing a null terminated string from the application.

Wednesday, September 26, 2007

Navigating to an embedded resource in .NET

This task is very common but since i did not find a clear and simple solution i decided to write it.

I have a simple C# application which has a webbrowser control and i want to use the res:// protocol to navigate to an embedded resource, a html file from the assembly, like this:

webbrowser.Navigate("res://myApp.exe/Help.htm");

since managed resources are not native ones, adding an html file to the project and select "embedded resource" wont help.
if you open the assembly with a resource editor you won;t see the html resource.
hence, the res:// protocol wont work.

so i wrote this simple console application which accepts as parameters the resource file you want to add.

Usage:
AddResourceManaged.exe ExePath ResFile ResName [ResType]

adds a new resource to an exe file
ExePath - path of the exe
ResFile - path of the file to be added as a resource
ResName - name of the resource
ResType - (optional) type of the resource; if omitted, the application will try to use one of the default resource types
based on the ResFile file extension

Example:
AddResourceManaged.exe myManagedApp.exe Help.htm help.htm 23

it is equivalent to:

AddResourceManaged.exe myManagedApp.exe Help.htm help.htm
because the value of MAKEINTRESOURCE(RT_HTML) is 23