INFO: General limitations under Win32s

This article has been archived. It is offered "as is" and will no longer be updated.
This article describes some of the known limitations in the implementationof certain features under Win32s. The information in this article does notinclude the list of unsupported Win32 APIs under Win32s. For information onthe list of supported Win32 APIs under Win32s, please refer to the "Win32Programmer's Reference" documentation or the Win32api.csv file in yourWin32 Software Development Kit (SDK) product.
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:
    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:
    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.
    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:
    The values returned are:
  • 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().
limits docerr docerror win32s unsupported tshoot

Article ID: 131896 - Last Review: 01/11/2015 01:00:30 - Revision: 6.0

  • kbnosurvey kbarchive kbinfo kbprogramming kbtshoot KB131896