We have been treating handles as abstract numbers. But sometimes handles are actually pointers. If you use LMEM_FIXED in LocalAlloc, the handle returned from the call is a near pointer that you can use directly. You do not need to call LocalLock. (If you do, it simply returns the same value you pass as a parameter—the handle that is actually a valid near pointer.) In fact, WINDOWS.H defines a special flag for calling LocalAlloc with an LMEM_FIXED parameter. The flag is LPTR (”local pointer“) and is defined as:
LMEM_FIXED | LMEM_ZEROINIT
When you use this flag, you need only cast the return value from LocalAlloc into a near pointer of the type you want:
npString = (char NEAR *) LocalAlloc (LPTR, wSize) ;
You free it up by casting the near pointer back to a handle and calling LocalFree:
LocalFree ((LOCALHANDLE) npString) ;
This technique is handy for allocating small chunks of local memory. For instance, here's the example shown above for allocating memory for the window class structure. It now uses a fixed block of local memory:
NPWNDCLASS npwndclass ;
[other program lines]
if (!hPrevInstance)
{
npwndclass = (NPWNDCLASS) LocalAlloc (LPTR, sizeof (WNDCLASS)) ;
npwndclass->style = CS_HREDRAW | CS_VREDRAW ;
npwndclass->lpfnWndProc = WndProc ;
npwndclass->cbClsExtra = 0 ;
npwndclass->cbWndExtra = 0 ;
npwndclass->hInstance = hInstance ;
npwndclass->hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
npwndclass->hCursor = LoadCursor (NULL, IDC_ARROW) ;
npwndclass->hbrBackground = GetStockObject (WHITE_BRUSH) ;
npwndclass->lpszMenuName = NULL ;
npwndclass->lpszClassName = szAppName ;
RegisterClass (npwndclass) ;
LocalFree ((LOCALHANDLE) npwndclass) ;
}
We've eliminated two lines of code (LocalLock and LocalUnlock) and one variable (the local memory handle). Note the casting in the LocalAlloc and LocalFree calls.
The same technique is even applicable for GlobalAlloc when the GMEM_FIXED (or GPTR) flag is used. The ”handle“ returned from GlobalAlloc is the segment address of the segment. It's a little more clumsy to convert that into a far pointer, but here's how to do it:
lpString = (LPSTR) MAKELONG (0, GlobalAlloc (GPTR, dwSize)) ;
The MAKELONG macro combines the segment address returned from GlobalAlloc and an offset address of 0 to make a long integer, which is then cast into a long pointer to type char. To free this block, you have to extract the segment address from the pointer and pass it to GlobalFree:
GlobalFree ((GLOBALHANDLE) LOWORD ((LONG) lpString))) ;
I don't like the memory allocation shortcuts, and I don't think they should be used. I've included them only because many sample Windows programs use them, particularly when allocating local memory.