The information in this article applies to:
- Microsoft Win32s, version 1.25a, 1.3, 1.3a, 1.3c
SUMMARY
This article describes some of the known limitations in the implementation
of certain features under Win32s. The information in this article does not
include the list of unsupported Win32 APIs under Win32s. For information on
the list of supported Win32 APIs under Win32s, please refer to the "Win32
Programmer's Reference" documentation or the Win32api.csv file in your
Win32 Software Development Kit (SDK) product. For information on
documentation errors related to Win32s, please refer to the following
article in the Microsoft Knowledge Base:
ARTICLE ID: Q155861
TITLE: DOC: Errors in Win32s Compatibility
Note that the information in this article applies to all versions of
Win32s.
MORE INFORMATION
- Thread creation is not supported.
- Win32s uses the Windows version 3.1 nonpreemptive scheduling mechanism.
- 32-bit processes should be started from a 16-bit application through
WinExec() or Int 21 4B. LoadModule() does not start a 32-bit process.
- Win32-based applications cannot use the EM_SETHANDLE or EM_GETHANDLE
messages to access the text in a multiline edit control. These messages
allow the sharing of local memory handles between an application and
USER.EXE. In Win32s, an application's local heap is 32-bit, so User.exe
cannot interpret a local handle. To read and write multi-line edit
control text, an application should use WM_GETTEXT and WM_SETTEXT.
Text for multi-line edit controls is stored in the 16-bit local heap in
DGROUP, which is allocated by Windows version 3.1 for the Win32s.exe
stub loaded before each Win32-based application is loaded. This means
that the size of edit control text is limited to somewhat less than 64K.
- The CBT hook thunks do not copy back the contents of structures, so any
changes are lost.
- Win32-based applications should not call through the return from
SetWindowsHook(). SetWindowsHook() returns a pointer to the next hook in
the chain. To call this function, the application should call
DefHookProc(), and pass a pointer to a variable where this address is
stored. Because Win32s simulates the old hook API in terms of the new,
SetWindowsHook() actually passes back a hook handle, not a function
pointer.
- Resource integer IDs must be 16-bit values.
- PostMessage() and PeekMessage() do not thunk structures. These functions
do not allocate space for repacking structures, because there is no way
to know when to free up the space.
- Private application messages should not use the high word of wParam.
Win32s uses Windows to deliver window messages. For unknown messages,
wParam is truncated to make it fit into 16-bits. Therefore, Win32-based
applications should not put 32-bit quantities into the wParam of
privately-defined messages, which are unknown to the thunk layer.
- After calling FindText(), an application cannot directly access the
FINDREPLACE structure. When an application calls the common dialog
function FindText(), it passes a FINDREPLACE structure. The FindText()
dialog communicates with the owner window through a registered message,
in which the lParam points to the structure. The thunks repack this
structure in place, so that unless the application is processing the
registered message, it should not access the structure.
- Subclassing a window that owns a FindText() common dialog does not work.
The FindText() thunk repacks the FINDREPLACE structure in place. This
means that 32-bit window procedures cannot subclass 16-bit owners of
FindText() dialogs without likely trashing four bytes beyond the end of
the structure, because the 32-bit FINDREPLACE is four bytes bigger than
the 16-bit version.
For 32-bit owners of the dialog box, there are also problems. Whenever
the structure might be referenced by 16-bit code, it needs to be in the
16-bit format. However, when the FindText() dialog box terminates, the
structure needs to be in 32-bit format so that the application can read
the final values. The dialog box indicates to its owner that it is about
to be destroyed by sending the commdlg_FindReplace message with the
FR_DIALOGTERM bit set in the Flags field of the FINDREPLACE structure.
After sending this message, the FindText() dialog box does not reference
the structure anymore, so the commdlg_FindReplace thunk leaves it in
32-bit format.
The problem occurs when the owner has been subclassed. Once the message
has moved to the 32-bit side, the structure will not be reconverted to
16-bits. Suppose the dialog box owner was subclassed by a 16-bit window
procedure, which was in turn subclassed by a 32-bit window procedure.
When a message is sent to the owner, it will first go to 32-bits, then
to 16-bits, then back to 32-bits to the original window procedure:
1. 16->32 message sent to 32-bit subclasser (struct repacked to 32-bits)
2. 32->16 message sent to 16-bit subclasser (struct not repacked)
3. 16->32 message sent to 32-bit original WndProc (struct not repacked)
The 16-bit subclasser cannot interpret the message parameters because
they are in 32-bit format. Between steps 2 and 3, the structure is not
repacked because it's already in 32-bit format.
Therefore, when a Win32-based application calls FindText(), allocate the
following:
1. A structure that contains the htask of Win32s.exe.
2. The original 32-bit FINDREPLACE pointer.
3. A count of the number of times the structure has been thunked without
returning.
4. A 16-bit format copy of FINDREPLACE.
The structure is repacked into the 16-bit version and this copy is
passed to Windows. The count is initially 0. When the
commdlg_FindReplace message is sent in either direction (16->32 or
32->16), repack the structure on the stack. If it was originally 32-bit,
increment the count. When returning in either direction, unpack the
structure and, if originally 32-bit, decrement the count.
If the Flags field of the structure has the FR_DIALOGTERM bit set, the
structure is originally 32-bit, and the count goes to 0 on a return,
then repack the structure back to the original 32-bit space.
- DDE messages are always posted, not sent, except for two:
WM_DDE_INITIATE and WM_DDE_ACK (responding to the former). The sent form
of WM_DDE_ACK is different from the posted form. When sent, no thunking
of lParam is necessary when going between 16- and 32-bit format.
However, when posting, the lParam parameter is repacked as two DWORDS
into private memory, allocated by COMBO.DLL (or by USER.DLL in Windows
NT). The thunk layer makes this distinction through the InSendMessage()
function. Therefore, a Win32-based application should not do anything in
the processing of a WM_DDE_INITIATE message that would cause the return
code from InSendMessage() to be FALSE.
- The following DDE messages are handled differently by applications under
Windows and Win32:
WM_DDE_ACK
WM_DDE_ADVISE
WM_DDE_DATA
WM_DDE_EXECUTE
WM_DDE_POKE
Because of the widening of handles, there is not enough space in the
Win32 message parameters for all the Windows data. Win32-based
applications are required to call helper functions that package the data
into memory (DDEPACK structure) referenced by a special handle. Win32s
implements the helper functions and allocates the DDEPACK structure on
behalf of 16-bit code when necessary.
As with other memory handles shared through DDE, there are rules
concerning who frees the memory allocated by these helper routines:
lParam = PackDDElParam(...)
if (PostMessage(...,lParam))
receiving window has obligation of freeing memory
lParam now invalid for this process
else
FreeDDElParam(...,lParam)
A Win32s hook procedure that has called CallNextHookProc() should not
use the lParam handle as the later's return code indicates that the
message has been processed. The hooks that could possibly process a DDE
message are:
WH_DEBUG
WH_HARDWARE
WH_KEYBOARD
WH_MOUSE
WH_MSGFILTER
WH_SYSMSGFILTER
In each case, if the hook proc (and therefore CallNextHookEx()) returns
a non-zero value, the message was either discarded or processed.
Windows-based procedures should not use the lParam of a DDE message
after handing it off to any other message API because they cannot know
if the message has been processed, so they must assume that it has been.
- WDEB386 does not support FreeSegment() for 32-bit segments. Win32s
Kernel Debugger support depends on it.
- The maximum size of shared memory is limited by Windows memory.
CreateFileMapping(hFile,
lpsa,
fdwProtect,
dwMaximumSizeHigh,
dwMaximumSizeHigh,
lpszMapName)
lpsa - Ignored.
dwMaximumSizeHigh - Must be zero.
MapViewOfFile(hMapObject,
fdwAccess,
dwOffsetHigh,
dwOffsetLow,
cbMap)
dwOffsetHigh - Must be zero.
- SetClipbrdData() must be used only with a global handle. Otherwise, the
data can't be accessed by other applications.
- Win32s supports printing exactly as Windows version 3.1 does. Win32s
does not add beziers, paths, or transforms to GDI; to allow applications
to use these features on PostScript printers, you must call the Escape
function with the appropriate escape codes.
Applications link to Windows version 3.1 printer drivers through
LoadLibrary() and GetProcAddress(), which have special support for this
purpose. There is no general mechanism allowing a Win32-based
application to link to a 16-bit DLL.
- Win32s does not support these escape codes:
BANDINFO ;24
GETSETPAPERBINS ;29
ENUMPAPERMETRICS ;34
EXTTEXTOUT ;512
SETALLJUSTVALUES ;771
- Integer atoms must be in the range 0-0x3FFF. This restriction is
necessary for the current implementation of the window properties API
thunks: SetProp(), GetProp(), RemoveProp(), EnumProps(), and
EnumPropsEx(). Integer atoms above 0x4000 are rejected by the thunk
layer.
- Arrays must fit in 64K after converting to 16-bit format. An array
passed to a function such as SetCharABCWidths() or Polyline() must fit
within 64K after its elements have been converted to their 16-bit form.
Its 32-bit form may be bigger than 64K.
- All Windows version 3.1 APIs that return void, return 1 to the
Win32-based application.
You can simulate a boolean return value by validating the API parameters
and returning FALSE if one is bad. However, you can't always do complete
validation, and if the API is called, you must assume it succeeded
unless there is a method to verify whether or not it succeeded.
- Win32 child window IDs must be sign-extended 16-bit values. This
excludes the use of 32-bit pointer values as child IDs.
- When calling PeekMessage(), a Win32-based application should not filter
any messages for Windows internal window classes (button, edit,
scrollbar, and so on). The messages for these controls are mapped to
different values in Win32, and checking for the necessity of mapping is
time-consuming.
- The dwThreadId parameter in SetWindowsHookEx() is ignored. The
dwThreadId is translated to hTask in Windows 3.1. There's a bug in
Windows version 3.1 where if hTask!=NULL, the call may fail.
- CreateWindowEx() has a DWORD dwExStyle parameter. In Windows 3.1 the
hiword of dwExStyle is cleared as a protection against garbage in the
hiword before it's used. Win32s passes CreateWindowEx() to the 16 bit
CreateWindowEx() and the hi 16 bits in the dwExStyle are lost.
- Floating point (FP) emulation by exception cannot be performed in 16-bit
applications. When tasks are switched between applications, the CR0-EM
bit state is not preserved in order to support 32-bit application FP
emulation by exception without breaking the existing 16-bit applications
that use FP instructions. The CR0-EM bit is assumed to be cleared during
execution of 16-bit application FP instructions. Upon executing a 16-bit
application FP instruction, the bit is cleared and reset when switching
back to a 32-bit application. The CR0-EM bit management is done in the
Win32s VxD, thus disabling the possibility of getting an int 7 exception
just by setting the CR0-EM bit in a 16-bit application.
- EndDialog() nResult parameter is sign-extended. Applications specify the
return value for the DialogBox() function by way of the nResult
parameter to the EndDialog() API. This parameter is of type int, which
is 32-bit in Win32s. However, this value is thunked through to the
Windows version 3.1 EndDialog() API, which truncates it to a 16-bit
value. Win32s sign-extends the return code from DialogBox().
- GetClipBox() returns SIMPLEREGION(2) and COMPLEXREGION(3). Because
Windows NT is a preemptive multitasking system, GetClipBox() on Windows
NT never returns SIMPLEREGION(2). The reason for this is that between
the time the API was called and the time the application gets the
result, the region may change. Win32s can return both SIMPLEREGION(2)
and COMPLEXREGION(3).
- PeekMessage() filtering for posted messages (hWnd==-1) is not supported.
The hWnd is replaced with NULL.
- Message queue length is limited to Windows default: 8 or whatever
length was set by DefaultQueueSize=n in the WIN.INI file. This limit may
be increased in the future to a larger size, but there will always be a
limit.
- GetFileTime() and SetFileTime() process only the lpLastWriteTime
parameter and return an error if this parameter is not supplied.
In the DEBUG version, supplying the other parameters causes a warning
message to be displayed.
- The precision of the time of a file is two seconds (MS-DOS limitation).
- CreateProcess has the following limitations:
- fdwCreate - Only DEBUG_PROCESS and DEBUG_ONLY_THIS_PROCESS are
supported.
- Process priority is always NORMAL.
- lpsaProcess, lpsaThread - Security information ignored.
- Always use device-independent bitmaps for color bitmaps. Win32s supports
the four Win32 device-dependent bitmap APIs. These are device-dependent
in the sense that the bitmap bits are supplied without a color table to
explain their meaning.
CreateBitmap
CreateBitmapIndirect
GetBitmapBits
SetBitmapBits
These are well defined and fully supported for monochrome bitmaps. For
color bitmaps, these APIs are not well defined and Win32s relies on the
Windows display driver for their support. This means that an application
cannot know the format of the bits returned by GetBitmapBits() and
should not attempt to directly manipulate them. The values returned by
GetDeviceCaps() for PLANES and BITSPIXEL and the values returned by
GetObject() for a bitmap do not necessarily indicate the format of the
bits returned by GetBitmapBits(). It is possible for the GDI DIB APIs to
be unsupported on some displays. However, it is now rare for display
drivers to not support DIBs. The one case where you may encounter a lack
of DIB support is with printer drivers, which may not support the
GetDIBits() API, though most do support the SetDIBits() API.
Win32s does not transform the bits in any way when passing them on to a
Windows version 3.1 API. When running an application that creates a
device-dependent bitmap via CreateBitmap() or CreateBitmapIndirect(), be
aware that the bits it is passing in may not be in the right format for
the device. Windows NT takes care of this by treating the bits as a DIB
whose format is consistent with the PLANES and BITSPIXEL values; but
Win32s simply passes them through.
- GetPrivateProfileString() and GetProfileString() return an error when
the lpszSection parameter is NULL. Under Windows NT, they give all the
sections in the .INI file.
- String resources are limited to a length of 255, as they were in Windows
version 3.1.
- TLS locations are the same in all processes for a specific DLL. This is
because Win32s does not support per-instance data for DLLs. The TLS
locations are unique per DLL. Each DLL should call TlsAlloc() only once
if it is runing on Win32s. The index returned will be valid for all
Win32 processes.
- GlobalCompact() is thunked through to Windows version 3.1
GlobalCompact(). This API has no effect on memory allocated through
VirtualAlloc(), which does not come from the Windows global heap.
- GetVolumeInformation() does not support the Volume ID.
- GetFileInformationByHandle() create time and access time are always 0
(MS-DOS limitations). The volume id, file index low/high are also 0
(Win32s limitations). This affects the CRT fstat() as well.
- CreatePolyPolygonRgn() requires a closed polygon, as it does under
Windows version 3.1. If the polygons are not closed, the Windows NT call
closes the polygons for you. In Windows version 3.1 or Win32s, if the
polygons are not closed, the call does not create the region correctly,
or it returns an error for an invalid parameter.
- Win32s does not support the DIB_PAL_INDICES option for SetDIBits(). It
will be supported in a future release. DIB_PAL_PHYSINDICES and
DIB_PAL_LOGINDICES are not supported either.
- The WH_FOREGROUNDIDLE hook type is not supported. Windows version 3.1
does not provide the necessary support.
- The brush styles BS_DIBPATTERNPT and BS_PATTERN8X8 are not supported and
cause an error to be returned.
- The hFile in DLL and PROCESS DEBUG events is not supported in Win32s
because there is no support for duplicating file handles between
processes (basically an MS-DOS limitation).
There are two way to access the image bytes: ReadProcessMemory() or open
the file in compatibility mode using the name provided in lplpImageName.
- Under Windows NT, NetBIOS keeps a different name table for each process.
On Win32s, there is only one NetBIOS name table for the system. Each
name (group or unique) added by a process is kept in a doubly-linked
list. Through NCBRESET or by destroying the process, you delete all the
names that were added by the process. Win32s does not implement the full
NetBIOS 3.0 specification, which has a separate name table per process.
- When calling 32-bit code from 16-bit code with UT (for example, from an
interrupt routine), the stack must be at least 10K. The interrupt
routine must assure that the stack will be big enough.
- GetThreadContext() and SetThreadContext() can be called only from within
an exception handler or an exception debug event. At all other times,
these functions return FALSE and the error code is set to
ERROR_CAN_NOT_COMPLETE.
- CreateProcess() PROCESS_INFORMATION is not supported for 16-bit
applications. A valid structure must be passed to CreateProcess(), but
the function fills all the fields with NULLs and zeroes.
- Win32s does not support the Windows NT event mechanism, therefore the
ncb_event field in NCB structure is not supported.
- CreateFileMapping() does not support SEC_NOCACHE or SEC_NOCOMMIT. The
call fails with ERROR_INVALID_PARAMETER.
- WaitForDebugEvent() does not fully support the dwTimeout parameter. If
the parameter is zero, WaitForDebugEvent() behaves the same as under
Windows NT. Otherwise, the parameter is treated as if it were INFINITE.
However, the function returns if any messages arrive. If a message
arrives, the return value is FALSE. The calling process should call
SetLastError(0) before calling WaitForDebugEvent() and examine
GetLastError() if WaitForDebugEvent() returns FALSE. If the error is
zero, it means that a message arrived and the process should process
the message. Otherwise, the process should handle the error.
- If a section contains duplicated keys, GetPrivateProfileSection()
returns the duplicated keys, but all values are the same as the value
of the first key.
Suppose a section contains these keys:
key1=x1
key2=x2
key2=x3
key2=x4
key3=x5
key2=x6
The values returned are:
key1=x1
key2=x2
key2=x2
key2=x2
key3=x5
key2=x2
- String IDs of resources should not be longer than 255 characters.
- String IDs must be in the English language. The resources themselves
can be mulitilingual.
- GetDlgItemInt() only translates up to 16-bit int/unsigned values. This
is because it gets its value from Windows, which translates only 16-bit
values. As a workaround, call GetDlgItem() and translate the value
using atoi() or sscanf().
|