INFO: MapSL, MapLS, UnMapLS Function Documentation

ID: Q195310

The information in this article applies to:

SUMMARY

The MapSL, MapLS, UnMapLS pointer translation routines are used in Windows 95 and Windows 98 Device Driver Kit sample code. However, these are not documented functions. This article provides the documentation for these routines that Windows 9x display driver developers need.

MORE INFORMATION

Windows 95 and Windows 98 provide functions for translating pointers 16-bit to 32-bit and vice versa. To help distinguish between the two types, the names include either SL or LS. The "L" stands for "linear" (the type of address used by 32-bit processes), and the "S" stands for "selector" (the selector:offset pointers used by 16-bit applications and DLLs). Functions with SL in their names translate pointers from 16-bit to 32-bit, while those with LS translate from 32-bit to 16-bit.

All the Windows 95 and Windows 98 thunking functions are implemented only in the Windows 95 and Windows 98 32-bit kernel (Kernel32.dll). To use them, you must first determine that you are running on Windows 95 or later, and then call GetProcAddress to get their addresses because they are not exported by the Kernel32.dll and are not in Kernel32.lib.

For example, you can get a pointer to MapLS() as follows:

   hModKernel = GetModuleHandle ("kernel32.dll");
   lpMAPLS = GetProcAddress (hModKernel, "MAPLS");

The following type definition, used in the following documentation to distinguish between 16-bit far pointers and 32-bit pointers, is not provided in any header file so you should add it to your project:

   typedef DWORD  LPFAR16;

Values declared as LPFAR16 are 16-bit far pointers. All other pointer types are 32-bit pointers.

LPVOID APIENTRY MapSL(LPFAR16 lp16Bit)

Translates a 16-bit far pointer into a 32-bit pointer.

Parameters:

   LPFAR16 lp16Bit

A 16-bit far pointer that is translated into a pointer that can be used by a 32-bit process.

Return Value:

If successful, it returns a 32-bit pointer that aliases (points to) the same location as lp16Bit. If unsuccessful, it returns NULL.

If lp16Bit points to a block of memory with a linear address below 64K, the return value is equal to lp16Bit because the region below 64K is not accessible from 32-bit processes. This allows convenient translation of values that can be either pointers or words (such as atoms).

Remarks:

This API is used by a 32-bit process to translate a 16-bit far pointer (passed to it from a 16-bit application) into a 32-bit pointer. It should be used when the 16-bit application has allocated memory and needs to give a 32-bit process access to that memory.

If the 16-bit application allocated the memory through GlobalAlloc(), it must fix the block by calling GlobalFix() or GlobalWire() before the 32-bit process translates the pointer with MapSL(). Allocating memory with the GMEM_FIXED flag and then locking it with GlobalLock() from a 16-bit application does not allocate fixed memory. From a 16-bit DLL, GlobalAlloc with the GMEM_FIXED flag allocates fixed and pagelocked memory. Because the block does not need to be pagelocked, it is recommended that DLLs allocate movable memory and then use GlobalFix() or GlobalWire().

Failure to fix the block before translating a pointer to it allows the 16- bit global memory manager to move the block, which invalidates the 32-bit pointer that aliases it. If the block remains fixed for a long time, you should use GlobalWire() instead of GlobalFix() because it moves the block lower in the heap before fixing it, which helps the 16-bit global memory manager reduce fragmentation in the 16-bit global heap.

Preferably, instead of calling GlobalFix() on the block, the 16-bit application should pass the pointer to the 32-bit application, and then the 32-bit application should use MapSLFix() instead of MapSL().

LPFAR16 APIENTRY MapLS(LPVOID lp32Bit)

Translates a 32-bit pointer into a 16-bit far pointer.

Parameters:

Return Value:

Returns a newly created far pointer that is composed of a single newly- allocated read-write data selector and an offset that is guaranteed to be zero. The selector's base address is the linear address specified by lp32Bit, and its limit is 64K.

The 32-bit application that called MapLS() passes the return value to the 16-bit application or DLL. The 16-bit application or DLL might increase or decrease the selector's limit with SetSelectorLimit().

If lp32Bit is less than 64K, it is treated as a DWORD, the return value is the same as lp32Bit, and no selector is allocated. This allows convenient translation of values that can be either pointers or words (such as atoms).

If this function fails, the return value is NULL.

Remarks:

The returned pointer is global to all 16-bit processes, and its selector is not automatically freed on process termination. Selectors are a limited resource, so you must use UnMapLS() to free every pointer allocated with MapLS().

The 16-bit applications and DLLs can only use the pointer when the 32-bit process that translated it is in context. This is because each 32-bit process has its own private address space, which is mapped between 0 and 2 gigabytes (GB) only when one of its threads is running. An example of when a 16-bit application can use the translated pointer is inside a 32 to 16 thunk.

LPVOID APIENTRY MapSLFix(LPFAR16 lp16Bit)

Translates a 16-bit far pointer into a 32-bit pointer.

Parameters:

Return Value:

If successful, it returns a 32-bit pointer that points to the same location as lp16Bit. If unsuccessful, it returns NULL.

If lp16Bit points to a block of memory with a linear address below 64K, the return value is equal to lp16Bit because the region below 64K is not accessible from 32-bit processes. This allows convenient translation of values that can be either pointers or words (such as atoms).

Remarks:

If the block pointed to by lp16Bit was allocated by the 16-bit global memory manager, this function fixes the block before doing the translation, so the 16-bit side does not need to call GlobalFix() on it. Otherwise, MapSLFix() acts just like MapSL().

Once you finish using the linear address, you should call UnMapSLFixArray() to unfix the block.

VOID APIENTRY UnMapSLFixArray(DWORD cNum, LPFAR16 *lp16Bit)

Unfixes blocks previously fixed by MapSLFix(). Traverses an array of 16-bit far pointers and unfixes each block.

Parameters:

Return Value:

None.

Remarks:

This routine traverses the array of 16-bit far pointers and unfixes each memory block in succession. If a particular block was not allocated by the 16-bit global memory manager, it is safely ignored by this function.

Once this function has been called, any 32-bit pointers that alias (point to) these blocks should be considered invalid because the 16-bit global memory manager can move the blocks again.

This routine preserves the EAX and EDX registers, as well as the registers all STDCALL functions preserve. This allows it to be used at the end of a thunking routine without destroying the return value from the thunk target.

VOID APIENTRY UnMapLS(LPFAR16 lp16Bit)

Releases the selector associated with the 16-bit far pointer allocated by MapLS().

Parameters:

Return Value:

None.

Remarks:

If lp16Bit is less than 64K, UnMapLS() does nothing. Otherwise, the high word of lp16Bit is assumed to be a selector allocated by MapLS(), and the low word (the offset) is ignored. This selector is freed.

Only selectors allocated by MapLS() should be passed to this function. If a 16-bit application or DLL changed the limit of the selector with SetSelectorLimit(), you do not need to change it back before calling UnMapLS().

Additional query words:

Keywords          : kbDDK kbWinOS95 kbWinOS98 
Issue type        : kbinfo

Last Reviewed: November 5, 1998