views:

48

answers:

4

Looking at the Windows SDK, I found this #define directive for MAKEINTRESOURCEW:

#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))

Can someone explain to me what the heck that means? For example, what would be the value of MAKEINTRESOURCEW(0)? (1)? (-1)?

+1  A: 

That's a macro that casts an argument i to a word, then casts that result to a pointer to an unsigned long, then again to a long pointer to a wide-character string.

Khnle
+2  A: 

The result of this macro will be pointer to long string with value equal to given parameter. You can see it by reading precompiler output (see /P C++ compiler options). All casting is required to compile this macro result, when LP[w]WSTR pointer is required, both in Win32 and x64 configurations.

Some Windows API, like LoadIcon, expect string pointer as their parameter. Possibly, these functions test the pointer value, and if it is less than some maximum, they interpret it as resource index, and not as string (problems of ugly C-style interface). So, this macro allows to pass WORD as string, without changing its value, with appropriate casting.

Alex Farber
Don't blame C for an ugly interface. There are a number of ways to solve this problem in C other than the one Win32 takes in this instance. :-)
asveikau
I don't blame C, just explain :) I am working in C, but this is still ugly hack. Since C doesn't allow overloading, they coud write two different finctions, like LoadIconByName and LoadIconByIndex.
Alex Farber
You said it was "C style". As someone who works frequently in C I wanted to make it clear that it's "bad style", and not the language's fault. :-)
asveikau
+2  A: 

For the most part, it leaves the value unchanged, but converts it from an int to a pointer so it's acceptable to functions that expect to see a pointer. The intermediate casts widen the input int to the same size as a pointer, while ensuring against it's being sign extended. In case you care, ULONG_PTR is not a "ULONG POINTER" like you might guess -- rather, it's an unsigned long the same size as a pointer. Back before 64-bit programming became a concern, the definition was something like:

#define MAKEINTRESOURCE(i)  (LPTSTR) ((DWORD) ((WORD) (i)))

Nowadays, they use ULONG_PTR, which is a 32-bit unsigned long for a 32-bit target, and a 64-bit unsigned long for a 64-bit target.

Jerry Coffin
Are you sure about 64-bit ULONG for Win64? I thought that 'long' and 'unsigned long' were still 32-bit - which may be different from LONG and ULONG but not according to some simple Google research. See, for example [KB250906](http://support.microsoft.com/kb/250906).
Jonathan Leffler
@Jonathan: When I say "64-bit unsigned long", the "unsigned long" is meant only as a description, not a literal type. At least with the version of the SDK I have handy, the actual type is `unsigned __int64`.
Jerry Coffin
+1  A: 

Like other users said - it just casts an integer into a "pointer to a string".

The reason for this is the following: At the ancient times of Windows 3.0 people tried to be minimalistic as much as possible. It was assumed that resources in the executable can have either string identifier or integer. Hence when you try to access such a resource - you specify one of the above, and the function distinguish what you meant automatically (by checking if the provided "pointer" looks like a valid pointer).

Since the function could not receive a "variable argument type" - they decided to make it receive LPCTSTR (or similar), whereas the actual parameter passed may be integer.

Another example from Windows API: A pointer to the window procedure. Every window has a window procedure (accessed via GetWindowLong with GWL_WNDPROC flag. However sometimes it's just an integer which specifies what "kind" of a window is that. Then there's a CallWindowProc which knows to distinguish those cases.

valdo