At first, it seems impossible for Windows to support moveable memory blocks in real mode. When a program allocates some local or global memory, Windows has to give the program a pointer so that the program can access the memory. If Windows later moves the memory block, then that pointer will be invalid. It will no longer point to the right place.
How does Windows do it? The catch here is that the memory allocation functions do not directly return pointers that the program may use. Instead, these functions return—as you can probably guess by now—handles. WINDOWS.H defines two data types called LOCALHANDLE and GLOBALHANDLE. These are defined as type HANDLE (which is a WORD, or unsigned 16-bit short integer). Before your program can use the allocated memory block, it must pass that handle back to Windows in another function that locks the memory block and returns a pointer. When a memory block is locked, Windows will not move it. The pointer will continue to be valid until you call another function to unlock the block. After that, Windows is free to move the memory again.
More precisely, the functions that lock a block of memory increment a ”lock count“ for the memory block. The unlocking functions decrement the lock count. When you first allocate moveable memory, the lock count is 0, meaning that Windows can move it if necessary. When the lock count is positive, Windows cannot move the block. (A lock count is preferable to a simple flag that denotes whether a block is locked, because different parts of your program can independently lock a block, use it, and unlock it. If Windows used a flag instead of a lock count, the memory block could become unlocked when another section of the program still needed it.)
When you use moveable memory in your Windows program, you should keep it locked only when your program has control. You should unlock it before you leave your window procedure. When you are entirely done with the memory block, you can then free the block.