Microsoft Windows 3.1x/WfW + Win32s
Windows 3.1x and Win32s overview
Windows 3.1x can be run from (on top of) DOS 3.xx - 6.22 or DOS 7.xx/8.xx (Windows 9x)
- in Windows 9x - only in Standard/286 Mode (win.com /s).
Win32s is a subset of Win32 API for using 32-bit programs in Windows 3.1x, see below.
> View win 3.1 screenshots :) <
> View win 3.11 screenshots :) <
> Download Windows 3.1/3.11wfw HERE [WinWorld] :) <
> The Win32s compatibility list :) <
> Download Windows 3.xx updates & stuff :) <
Windows 3.1x 256-color VESA/VBE Compatible Driver
SVGAPatch: Tool to patch svga256.drv to make it VESA compliant. This may be useful if you want to run windows 3.1 or WfW 3.11 (in DOSEMU, for instance), but there exists no driver for your video adapter for these GUIs. SVGA256.DRV is included in WfW, but the driver itself can be downloaded from the net from various places (do a search for SVGA.EXE).
Follow these steps:
Microsoft Win32s Win32 API Support
API Features supported:
- Complete windowing interfaces (User)
- All graphics functions (GDI)
- OLE support
- OLEDLG (OLE Dialogs)
- DDE/DDEML (dynamic data exchange and DDE Management Library)
- TrueType fonts
- Common dialogs
- Network support (NetBios and Windows Sockets 1.1 APIs)
- Multimedia support (sound APIs)
- Structured exception handling (SEH)
- Sparse memory (Virtual memory API)
- Memory-mapped files (backed by disk image)
- Growable heaps (Heap API)
- International Support (localized versions of Win32s and Code Page/Unicode translation APIs)
- New National Language Support (NLS) functions
- Memory-saving compressed code page files
- Combined libraries that require less memory
- Windows 9x/Windows NT Common Controls
- Windows 9x/Windows NT Common Dialogs
- WinHelp 4.0
except for features covered below:
- Asynchronous File I/O
- Bezier curves
- Comm APIs
- Console APIs
- Enhanced Metafiles
- MAPI
- OpenGL
- Paths (graphics object)
- RPC
- Security APIs
- Threads
- Unicode APIs (Win32s does support Code Page/Unicode translation APIs)
In MS VC/C++ 1.x-4.x exist a full listing of functions supported in Win32s, see fourth column in LIB\win32api.csv table.
Also there in help files, where Win32 API functions documented, it is clearly marked in what operating system such as Win95/NT or Win32s which API is supported or not.
In addition - some specfic programming considerations when compiling for Win32s noticed there, such as maximum stack size and so on.
See CT sample in My projects for Win32s API demonstration. Only for latest Win32s version!
Win32s version history
Version history (source here):
- Oct. 1992 Beta (floppy and CD) - the earliest known version, has no actual version number
- 1.0 (1.0.61 Beta - floppy and CD) - included in Win32 SDK Beta from March 1993 (build 404)
- 1.1 (1.1.88 - Developer, MSVC32s and floppy)
- 1.1a (1.1.89 - floppy)
- 1.15 (1.15.103 - Developer and floppy) - also included in Windows Chicago Beta 1 SDK, 25 April 1994
- 1.15a (1.15.111 - floppy), 7 June 1994
- 1.20 (1.20.123 - Developer, floppy, CD and OLE2), 18 October 1994
- 1.20 (1.20.127 - floppy)
- 1.25 (1.25.139) - included in Windows 95 Beta 2 SDK
- 1.25 (1.25.141 - floppy, CD and OLE2), 21 February 1995
- 1.25a (1.25.142 - floppy, CD and OLE2), 17 May 1995
- 1.30 (1.30.140 Beta - floppy) - included in Windows 95 Beta 2 SDK
- 1.30 (1.30.152 Beta - floppy)
- 1.30 (1.30.152 - floppy)
- 1.30 (1.30.159 - floppy), 11 July 1995
- 1.30a (1.30.166 - Developer, floppy, CD and OLE2), 11 September 1995
- 1.30c (1.30.172 - Developer, floppy and CD) - the last version, 31 January 1996
NOTE 1: Microsoft Win32s version 1.30c is the latest version of the software that allows you to run Win32-based applications on Windows version 3.1 or Windows for Workgroups versions 3.1 and later. The Win32s upgrade is now available in the Microsoft Software Library (MSL) as Pw1118.exe.
Version 1.30 conflicts with 32-bit OS/2 environment, some emulators (f.e. MS Virtual PC 2004/2007) - use version 1.25a. Or use this method (source article is here: Installing a hybrid WIN32S 1.25/1.30 extension in WinOS/2 on OS/2 Warp 4):
- Install win32s 1.25
- Copy these files from Win32s 1.30 to %WINDIR%\SYSTEM\WIN32S directory:
shell32.dll
comctl32.dll
oleaut32.dll
ole2thk.dll
ole32.dll
NOTE 2: In Win32s 1.25 environment some features introduced in version 1.30 are not supported, such as:
- Windows Common Controls (no COMCTL32.DLL and it's functionality).
Win32s MSKB ( Microsoft Knowledge Base ) Articles
MSKB: Win32s Version 1.x Bug/Fix Lists
BUG: Win32s 1.1 Bug List (Q113739)
The following is a list of known problem in Win32s version 1.1. Microsoft has confirmed these to be problems in Win32s version 1.1. Problems marked
with a hyphen ("-") will be corrected in Win32s version 1.15. Problems marked with an asterisk ("*") will be corrected in Win32s version 1.2.
- - Setup fails if there are 40 groups in Program Manager.
- - WinFile generates a general protection (GP) fault while viewing file properties.
- - The Universal Thunk (UT) callback returns a WORD, rather than a DWORD.
- - The LA (linear address) Table is limited to 256 entries. This limits the number of VirtualAlloc() calls that will succeed.
- - Win32s does not handle paths that contain an ampersand ("&") or a number sign ("#").
- - FP (floating point) exceptions are not trapped by SEH (structured exception handling. FP exceptions in 32-bit code which are called from 16-bit code via UT can cause a GP fault in WIN87EM.
- - Thread Local Storage (TLS) data is allocated from a limited heap size. This can cause applications that use a lot of TLS data to fail to load.
- - CB_FINDSTRING and LB_FINDSTRINGEXACT are not thunked correctly from a 16-bit application to a 32-bit application.
- - Dialog templates passed from a 32-bit applications are corrupted.
- - If a DDE client responds to INITIATE for which it is also the server, lParam is packed incorrectly.
- * fstat() always returns that rt_mode is read/write.
- * chdrive() does not retain the current working directory. chdrive() always uses the root directory.
- - ChooseFont()'s referenced CHOOSEFONT structure has blue value set to 0 with CF_EFFECTS.
- - CopyFile() uses the current time rather than the file time.
- - CreateFile() does not parse UNC names correctly.
- - CreateProcess() does not set current directory correctly.
- - CreateProcess() ignores window size and window position.
- - CreateProcess() debug version corrupts the environment if lpApplicationName != NULL.
- - CreateProcess() returns failure if the child does not call GetMessage() or yield in some way before control goes to the parent.
- - CreateProcess()'s dwFlags is ignored when starting Win16 applications, while wShowWindow is always passed.
- - CreateWindowEx()'s CW_USEDEFAULT flag is not handled, which causes problems with using WM_VISIBLE.
- - EnumMetaFile()'s handles array is corrupted.
- - EnumPropsEx() enumerates non-existing properties.
- - EqualRect() returns TRUE for rectangles that are lines.
- - FindFirstFile() error code is set to ERROR_NO_MORE_FILES instead of ERROR_FILE_NOT_FOUND if there are no matches for the search pattern.
- - FindFirstFile() may use a bad DTA, causing stack corruption.
- - GetClassInfo() WNDCLASS buffer is corrupted if passed an invalid class.
- * GetFileInformationByHandle() support added in version 1.15, but file attribute returned is always 0.
- - GetFilePointer() returns valid value when given invalid handle.
- - GetFileSize() moves the file pointer.
- - GetFileVersionSize() causes a GP fault when 16-bit applications for Windows call the function from a 32-bit DLL.
- - GetKerningPairs() results are not in Win32 format.
- - GetModuleFileName() causes the OFSTRUCT structure to be truncated in 16-bit applications calling this function on a 32-bit DLL.
- - GetModuleFileName()'s char count returned includes the terminating NULL character.
- - GetOpenFileName() call fails with OFN_ENABLETEMPLATEHANDLE.
- - GetOpenFileName() has a hook you can use to trap WM_INITDIALOG to get the address of OPENFILENAME struct, but the pointer is corrupted by the next message.
- - GetOutlineTextMetrics() returns OUTLINETEXTMETRIC structure with Windows 3.1 format rather than Win32 format.
- - GetOutlineTextMetrics()'s OUTLINETEXTMETRIC UnderscorePosition, UnderscoreSize, and otmItalicAngle are incorrect.
- - GetSystemInfo() returns an incorrect lpMinimumApplicationAddress and an incorrect lpMaximumApplicationAddress.
- - GlobalCompact() exception occurs when the value is larger than available memory.
- - HeapAlloc/malloc() are slow because debug check was left in the code.
- - IsCharAlpha() returns 0 for characters 128-255.
- - LoadLibrary() fails to report unsucessful load of 16-bit DLLs (should return ERROR_BAD_EXE_FORMAT).
- - LoadLibrary() fails after 4591 calls due to a memory leak.
- - LoadLibrary() was fixed to work from a 32-bit DLL called by a 16-bit application.
- - LoadModule() does not pass cmdshow so applications get SW_SHOWNORMAL.
- - LocalAlloc() fixed to work from a 32-bit DLL called by a 16-bit application.
- - MultiByteToWideChar() has the wrong string returned with USE_GLYPHCHARS.
- - NetAccessAdd(), NetApiBufferAllocate(), NetUseGetInfo(), and NetUserSetGroups() all are not exported by NETAPI32.DLL. NOTE: These functions are not supported.
- - OpenFile() does not parse UNC names correctly.
- - PeekMessage() causes RIP in debug windows if hwnd is NULL.
- - PlayMetaFileRecord()'s handles array is corrupted.
- - PolyPolygon() fails with more than 16 polygons.
- - PrintDlg() incorrectly frees global memory and fails with MFC sample.
- - SetClipboardData()'s 32-bit memory is not freed when clipboard is emptied.
- - SetErrorMode()'s SEM_NOOPENFILEERRORBOX does not work. The message box still appears.
- - SetFilePointer() returns a valid value if given an invalid handle.
- - SetProp()'s seventeeth call fails if lpsz is a string rather than an atom.
- - SetWindowLong()'s GWL_USERDATA always returns 1.
- - TrackMenuPopup()'s optional lprc parameter is not handled correctly.
- - waveOutGetDevCaps()'s WAVEOUTCAP buffer not filled correctly for the SoundBlaster.
- - waveOutWrite()'s WOM_DONE messages are not posted with multiple buffers and loop play.
- * WinExec() will cause 16-bit applications which are launched to GP fault.
BUG: Win32s 1.25a Bug List (Q130138)
The following is a list of the known bugs in Win32s version 1.25 at the time of its release.
- EM_GETWORDBREAKPROC return code is incorrect.
- Int 3 cannot be trapped via Structured Exception Handling (SEH) on Win32s.
- GlobalAlloc(GMEM_FIXED) from 32-bit .EXE locks memory pages. It is more efficient to use GlobalAlloc(GMEM_MOVEABLE) and call GlobalFix() if necessary.
- WinHlp32.exe will not run.
- C run-time functions getdcwd()/getcwd() do not work.
- PlayMetaFileRecord()/EnumMetaFile() contain incorrect lpHTable.
- Print setup common dialog does not work as expected (the dialog does not appear in some situations).
- Size of memory mapped files is rounded to a whole number of pages, meaning that the size is a multiple of 4096 bytes.
- Functions chdrive() and SetCurrentDirectory() fail on PCNFS network drives.
- Calling CreateWindowEx() with a 32-bit menu handle causes int 3.
- GetExitCodeProcess() does not return exit codes for Win16 applications.
- FindFirstFile()/FindNextFile() return local time, not Universal Coordinated Time (UTC) time. This behavior matches Windows 3.1, but not Windows NT.
- Memory passed to Netbios() must be allocated with GlobalAlloc().
- biSizeImage field of BITMAPINFOHEADER is zero
- CreateFile() on certain invalid long filenames closes Windows.
- Only the first CBT hook gets messages.
- GlobalUnlock() sets an error of ERROR_INVALID_PARAMETER.
- CreateFile() with share options of 0 does not lock file.
- lstrcmp()/lstrcmpi() do not use the collate table correctly.
- FreeLibrary() in DLL_PROCESS_DETACH crashes system.
- LockResource() does not return NULL if hResource is invalid.
- sndPlaySound() may cause a crash or may work poorly.
- GetVolumeInformation() fails for Universal Naming Convention (UNC) root path.
- Stubbed API GetFileAttributesW() does not return -1 on error.
- Code page CP_MACCP not supported.
- Invalid LCIDs are not recognized.
- CreateFile() fails to open an existing file in share mode.
- CreateDirectory()/RemoveDirectory() handle errors differently on Windows NT and Win32s.
- SetCurrentDirctory() returns different error codes than on Windows NT.
- FindText() leaks memory.
- FindText() may cause GP fault.
- Not all 32-bit DLLs have correct version numbers.
- WINMM16.DLL has no version information.
- RegEnumValue() and other Registry functions return ERROR_SUCCESS even though they are not implemented. Win32s implements only the registry functions supported by Windows.
- COMPOBJ.DLL calls FreeLibrary() on w32sys.dll, leaving the FP exception vector invalid. Causes crash, often out to MS-DOS.
- CreatePolyPolygonRgn() is not closing the polygons.
- SetDIBits() with DIB_PAL_INDICES is not supported (this behavior matches Windows 3.1, but not Windows NT).
- Progman gets restored when debugger app exits.
- Cannot do ReadProcessMemory (RPM) on memory that has a hardware break point set on it.
- Pointer to common dialog structures (lParam) becomes invalid.
- ResumeThread() while debugging writes to debuggee stack.
- Fault in initialization if app has more than 128K bytes of local data. This is because the application stack is limited to 128K.
- Using CVW debugger, exception will terminate the app being debugged.
- RealizePalette() error on Windows NT is -1, but is not defined under Win32s.
- Using StartDoc() does not produce document from printer.
- Can't open file using full path with different drive in common dialog.
- GetFileInformationByHandle() doesn't return correct file attribute.
- GlobalReAlloc(x,y,GMEM_MOVEABLE) returns wrong handle type.
- Thread Local Storage (TLS) data not initialized to zero in TlsAlloc().
- spawnl() does not pass parameters to an MS-DOS application.
- Incorrect context at EXIT_PROCESS_DEBUG_EVENT.
- Win32s doesn't support language files other than default (l_intl.nls).
- SetLocaleInfoW()/SetLocaleInfoA() not implemented.
- GetScrollPos() fails if scroll pos is 0.
- SetScrollPos() fails if last scroll pos is 0.
- FreeLibrary() may crash when using universal thunks.
- Win32s does not support forwarded exports.
- GetCurrentDirectory() returns wrong directory after calling GetOpenFileName().
- Module management APIs missing ANSI to OEM translation.
- LoadString() leaks memory if the string is a null string.
FIX: Win32s 1.25a Fix List (Q130139)
The following is a list of the known bugs in Win32s version 1.2 that were fixed in Win32s version 1.25.
- GlobalAlloc(GMEM_FIXED) from 32-bit .EXE locks memory pages. It is more efficient to use GlobalAlloc(GMEM_MOVEABLE) and call GlobalFix() if necessary.
- WINMM16.DLL has no version information.
- CreateFileMapping() with SEC_NOCOMMIT returns ERROR_INVALID_PARAMETER.
- PolyPolygon() does not close the polygons.
- OpenFile() only searches the current directory when only a filename is given, not the application directory, the system directory, the windows directory, or the directories listed on the path.
- GetFileInformationByHandle() doesn't return the correct file attribute.
- GlobalUnlock() sets an error of ERROR_INVALID_PARAMETER.
- lstrcmp()/lstrcmpi() do not use the collate table correctly.
- FreeLibrary() in DLL_PROCESS_DETACH crashes the system.
- FindResource(), LoadResource(), GetProcAddress(), GetModuleFileName(), EnumResourceNames(), and other APIs, fail with a NULL hInstance.
- sndPlaySound() with SND_ASYNC | SND_MEMORY may cause a crash or may work poorly.
- Thread Local Storage (TLS) data is not initialized to 0 in TlsAlloc().
- The pointer received in the lParam of WM_INITDIALOG in the common dialog hook function becomes invalid in the following messages if the pointer is "remembered" in a static variable.
- Stubbed API GetFileAttributesW() does not return -1 on error.
- Code page CP_MACCP not supported.
- Invalid LCIDs are not recognized.
- CreateFile() fails to open an existing file in share mode.
- GetLocaleInfo() for locale returns system defaults from WIN.INI.
- GetVolumeInformation() fails with ERROR_INVALID_NAME for volumes without a label.
- VirtualProtect() may miss the last page in an address range.
- GetLocaleInfo() returns incorrect information for most non-US locales.
- ANSI/OEM conversions always use code page 437.
- GetProcAddress() for printer driver APIs is case sensitive.
- The LanMan APIs are unsupported, but they return 0, which indicates that the API was successful. They should return NERR_InvalidAPI (2142).
- CreateFileW() returns 0 instead of -1 (HFILE_ERROR).
- lstrcpyn() copies n bytes from source to destination, then appends a NULL terminator, instead of copying n-1 bytes and appending the NULL terminator.
- GetDriveType() doesn't report detecting a CD-ROM or a RAM DISK.
- CRTDLL calls TlsFree() upon each process detach, not just the last.
- If a DllEntryPoint calls FreeLibrary() when using universal thunks, the system can crash.
- Not all 32-bit DLLs have correct version numbers.
- GetCurrentDirectory() returns the wrong directory after calling GetOpenFileName(). The workaround is to call SetCurrentDirectory(".") right after returning from the call to GetOpenFileName().
- RegEnumValue() and other Registry functions return ERROR_SUCCESS even though they are not implemented. Win32s implements only the registry functions supported by Windows.
- AreFileApisANSI()/SetFileApisToANSI()/SetFileApisToOEM() are not exported. AreFileApisANSI() should always return TRUE, SetFileApiToOEM() should always fail, and SetFileApiToANSI() should always succeed.
- SetLocaleInfoW()/SetLocateInfoA() are not implemented.
- GetScrollPos() sets the last error if the scroll position is 0.
- SetScrollPos() sets the last error if the last scroll position is 0.
- LoadString() leaks memory if the string is a null string.
- GetFileVersionInfoSize() fails if the resource section is small and close to the end of the file.
- MoveFile() doesn't call SetLastError() on failure or sets a different error than on Windows NT.
- SetCurrentDirectory() does not work on a CD-ROM drive.
- GetFileVersionInfoSize() fails if the 2nd parameter is NULL.
- WSOCK32.DLL is missing exported stubs for unimplemented APIs.
- Win32s fails to load 64x64 monochrome (black and white) icons.
- CreateFile() fails when called with a filename with an international character.
- GetCurrentDirectory() returns an OEM string.
- PrintDlg() causes GP fault if hDevMode!=NULL and another printer is selected that uses a larger DevMode buffer.
- Unicode resources are not properly converted to 8-bit characters.
- CreateDC() returns an incorrect DEVMODE. This can cause a variety of symptoms, like the inability to do a Landscape Print Preview from an MFC application or the displayed paper width and height not changing, even when you change the paper size.
- OpenFile() fails on filenames with OEM characters in the name.
- WNetCancelConnection() should be supported similar to NetAddConnection().
- GetDriveType() fails on a Stacker 3.1 drive.
- SetCurrentDirectory() fails on Novell client machines.
- GetProp() returns 0 in the second instance of an app in certain cases.
- fopen(fn, "w") fails on second call.
- TLS indices allocated by a module are released when that module is freed.
- CreateWindow() handles STARTUPINFO incorrectly if the application starts minimized.
- CreateFile() creates files with incorrect attributes.
- Resource sections are now read/write to emulate the behavior of Windows NT and Windows 95.
- Removed the 128K stack limitation.
- CompareStringW() sometimes uses incorrect locale, primarily Swedish and other Scandinavian locales.
- Added dummy _iob to CRTDLL for applications that reference standard handles.
- Added support for OPENCHANNEL, CLOSECHANNEL, SEXGDIXFORM, and DOWNLOADHEADER escapes.
FIX: Win32s 1.3 Fix List (Q133027)
The following is a list of the known bugs in Win32s version 1.25a that were fixed in Win32s version 1.3.
- DeviceCapabilities() with DC_BINS and DC_PAPERS are thunked incorrectly. The array should be left as is.
- SearchPath() and OpenFile() don't work properly with OEM chars in the filename.
- GetSystemInfo() doesn't set correct ProcessorType for the Pentium.
- FindResource() returns a non-NULL handle for a nonexistent resource.
- VirtualProtect() with anything other than PAGE_NOACCESS, PAGE_READ, OR PAGE_READWRITE yields unpredictable page protections.
- COMPAREITEMSTRUCT, DELETEITEMSTRUCT, DRAWITEMSTRUCT, AND MEASUREITEMSTRUCT incorrectly sign-extend fields.
- GetWindowTextLength() and GetWindowText() incorrectly sign-extend the return value.
- MoveFile() fails on Windows for Workgroups when the source is remote and the destination is local.
- PrintDlg() GP faults if the PRINTDLG structure has an illegal size (size other than 42).
- Loading resources may cause memory and selector leakage. The leakage occurs when the resource is loaded from a DLL.
- FP context is corrupted when an FP exception occurs while using the FP emulator.
- If a window class defined in one DLL uses a window function in another DLL and this DLL is unloaded before the DLL that defines the window class, a general protection (GP) fault occurs in WIN32S16.DLL when you terminate the process from a debugger.
- GetBitmapBits() and SetBitmapBits() return the wrong value. The return code is not converted from dx:ax to eax.
- FindResource() does not set the last error code to a proper value.
- NLS APIs fail when AnsiCP in the [NLS] section of WIN32S.INI is set to the code page of the machine (473 on U.S. machines).
- _tzset() in CRTDLL.DLL can cause a general protection (GP) fault.
In addition, there were several bugs fixed in the Windows NT FP emulator. These fixes were are included in Win32s.
Win32s 1.30a Bug List at the Time of Its Release (Q138234)
This article lists the known bugs in Win32s version 1.30a at the time of its release.
Software support overview for Win32s
Making programs for Win32s? It is possible since Win32s API is a subset of Win9x/NT Win32 API.
OpenWatcon C/C++ (www.openwatcom.org) FREE
- WORKS PERFECTLY!
- In compiler options set option to generate .reloc section in exe-file needed for Win32s.
MinGW C/C++, GNU C/C++
FreePascal (www.freepascal.org)
- Using Version 1.0.10 is OK! (2.0.x and later may also work) :?
- In compiler options set conditional define -WR option to generate .reloc section in exe-file needed for Win32s.
Microsoft Visual C/C++ 32bit
- MS VC/C++ 1.x (_MSC_VER=800): has official support for Win32s.
- MS VC/C++ 2.x (_MSC_VER=900): has official support for Win32s.
- MS VC/C++ 4.x (_MSC_VER=1000): Up to version 4.1b has official support for Win32s.
- MS VC/C++ 5.x, VS5.0/1997 (_MSC_VER=1100): static linking only (but if you rename msvcrt40.dll (from VC 4.0-4.1b) to msvcrt.dll dynamic link works).
- MS VC/C++ 6.x, VS6.0/1998 (_MSC_VER=1200): dynamic linking only, if you rename msvcrt40.dll to msvcrt.dll. Why? See this article.
- MS VC/C++ 7.x, VS.NET product line from:
- MS VC/C++ 7.0, Visual Studio .NET/2002 (_MSC_VER=1300).
- MS VC/C++ 7.1, Visual Studio .NET/2003 (_MSC_VER=1301) from Visual C++ Toolkit 2003 FREE, search internet for VCToolkitSetup.exe.
- MS VC/C++ 7.1, Visual Studio .NET/2003 (_MSC_VER=1301) from Windows Server 2003 SP1 DDK (February 2003) FREE, Download [236 MB ISO file] - static linking only.
- MS VC/C++ 8.0, Visual Studio 2005 (_MSC_VER=1400).
- MS VC/C++ 9.0, Visual Studio 2008 (_MSC_VER=1500).
- MS VC/C++ 10.0, Visual Studio 2010 (_MSC_VER=1600).
- Note 1: If you are dynamically link with CRTDLL.LIB (i.e. to CRTDLL.DLL) almost every version of MS compilers will produce working executable for Win32s.
- Note 2: To overcome linking problems and incompatibilities with standard linker link.exe you can use UniLink universal linker made by Yury Haron - ULNBxxxx.ZIP ftp://ftp.styx.cabel.net/pub/UniLink.
It produces compact code, and does not stamp os/subsystem version in PE-header.
Use it like this:
ulink -ZX- -B- -ZOmyprogram.exe myprogram.obj
- Note 3: In MS VC/C++ 5.0 and later you have to set linker /FIXED:NO option to generate .reloc section in exe-file needed for Win32s. (or set it in project properties Alt+F7).
- Note 4: Even if Console API is absent you do not require to set /SUBSYSTEM:WINDOWS instead of /SUBSYSTEM:CONSOLE in linker options:
both of them are working in Win32s, such functions as printf() exists in Win32s system libraries, but they are "stubbed" and doing nothing in Win32s environment.
- Note 5: In some cases when you are using C/C++ Compiler 7.x and later it is possible to cross-link with MSVCRT.LIB, LIBC{MT}.LIB from MSVC 5.0 or earlier.
You also can use these libraries from older Windows SDK, DDK packages.
- Note 5:Win32s-compatible VC/C++ Runtime and MFC redistributable files list
MS VC/C++ 1.x
MS VC/C++ 2.x
- CRTDLL.DLL - from MS VC/C++ 1.x
- CTL3D32.DLL
- MFC30.DLL
- MFCANS32.DLL
- MFCD30.DLL
- MFCN30.DLL
- MFCO30.DLL
- MFCUIA32.DLL
- MSVCRT10.DLL - from MS VC/C++ 1.x
- MSVCRT20.DLL
MS VC/C++ 4.x
- CRTDLL.DLL
- CTL3D32.DLL
- CTL3DS.DLL
- IMAGEHLP.DLL
- MFC40.DLL
- MFC40CHS.DLL
- MFC40DEU.DLL
- MFC40ENU.DLL
- MFC40ESP.DLL
- MFC40FRA.DLL
- MFC40ITA.DLL
- MFC40JPN.DLL
- MFC40KOR.DLL
- MSVCIRT.DLL
- MSVCRT.DLL
- MSVCRT10.DLL - from MS VC/C++ 1.x
- MSVCRT20.DLL - from MS VC/C++ 2.x
- MSVCRT40.DLL
- Note 6: This is sample CONSOLE code:
#include "stdio.h"
#include "string.h"
#define _CRT_SECURE_NO_DEPRECATE // For VS 2005 ++
#define _CRT_NONSTDC_NO_DEPRECATE // For VS 2005 ++
#define _CRT_NON_CONFORMING_SWPRINTFS // For VS 2005 ++
//#pragma comment(linker, "/entry:main")
//#pragma comment(linker, "/nodefaultlib")
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
//#pragma comment(lib,"crtdll.lib")
// Link with CRTDLL.DLL instead of MSVCRT.DLL or MSVCRTxx.DLL
#pragma comment(linker,"/ALIGN:4096 /FIXED:NO")
// FIXED:NO VS .NET (2002) and later doesn't allow it here, only in command line
// ALIGN:4096 strips zeroes from MS VS 6.0-made file
char outn[_MAX_PATH];
void main(void)
{
FILE * oFile;
#if defined(_MSC_FULL_VER)
sprintf((char*)&outn, "\\%u.log",_MSC_FULL_VER);
#else
sprintf((char*)&outn, "\\%u.log",_MSC_VER);
#endif
oFile = fopen(outn,"wb");
fputs("*** begin log\n",oFile);
#if defined(_MSC_FULL_VER)
fprintf(oFile,"MSVC: _VER '%u', _FULL_VER '%u'\n",_MSC_VER, _MSC_FULL_VER);
#else
fprintf(oFile,"MSVC: _VER '%u', _FULL_VER '?'\n",_MSC_VER);
#endif
fputs("*** end log\n",oFile);
if (oFile) fclose(oFile);
}
- Note 7: This is sample GUI, WINDOWS code:
#include "windows.h"
#include "stdio.h"
#define _CRT_SECURE_NO_DEPRECATE // For VS 2005 ++
#define _CRT_NONSTDC_NO_DEPRECATE // For VS 2005 ++
#define _CRT_NON_CONFORMING_SWPRINTFS // For VS 2005 ++
//#pragma comment(linker, "/entry:main")
//#pragma comment(linker, "/nodefaultlib")
#pragma comment(lib,"kernel32.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"crtdll.lib")
// Link with CRTDLL.DLL instead of MSVCRT.DLL or MSVCRTxx.DLL
#pragma comment(linker,"/ALIGN:4096 /FIXED:NO")
// FIXED:NO VS .NET (2002) and later doesn't allow it here, only in command line
// ALIGN:4096 strips zeroes from MS VS 6.0-made file
char msg[_MAX_PATH];
int WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst,LPSTR lpCmdLine,int)
{
#if defined(_MSC_FULL_VER)
wsprintf(msg,"MSVC: _VER '%u', _FULL_VER '%u'",_MSC_VER, _MSC_FULL_VER);
#else
wsprintf(msg,"MSVC: _VER '%u'",_MSC_VER);
#endif
return MessageBox(GetDesktopWindow(),"Quick brown fox jumps over the lazy dog",msg,MB_OK + MB_ICONINFORMATION);
}
- Note 8: Win32 dynamic link make script (bat/cmd file) for console application:
@echo off
cls
set _WIN32_WINNT=0x400
set WINVER=0x400
set CFLAGS=/nologo /Ox /Zp1 /D "WIN32" /D "NDEBUG"
set LFLAGS=/link /fixed:no /SUBSYSTEM:CONSOLE,3.10 /VERSION:0.0
echo +BEGIN+
echo *** making BY VS2010
cl /MD %CFLAGS% /w %1.CPP /Fe100.exe %LFLAGS%
echo *** making BY VS2008
cl /MD %CFLAGS% /w %1.CPP /Fe90.exe %LFLAGS%
echo *** making BY WDK71(VS2008)
cl /MD %CFLAGS% /w %1.CPP msvcrt_win2000.obj /Fe90w.exe %LFLAGS%
echo *** making BY WDK7(VS2005)
cl /MD %CFLAGS% /w %1.CPP /Fe80v.exe %LFLAGS%
echo *** making BY VS2005
cl /MD %CFLAGS% /w %1.CPP /Fe80.exe %LFLAGS%
echo *** making BY VS2003
cl /MD %CFLAGS% /w %1.CPP /Fe71.exe %LFLAGS%
echo *** making BY W2K3DDK(VS2003)
cl /MD %CFLAGS% /w %1.CPP bufferoverflowu.lib /Fe71t.exe %LFLAGS%
echo *** making BY VS2002(VS.NET)
cl /MD %CFLAGS% /w %1.CPP /Fe70.exe %LFLAGS%
echo *** making BY VS1998(VS6)
cl /MD %CFLAGS% /w %1.CPP /Fe60.exe %LFLAGS%
echo *** making BY VS1997
cl /MD %CFLAGS% /w %1.CPP /Fe50.exe %LFLAGS%
echo *** making BY VC40
cl /MD %CFLAGS% /w %1.CPP /Fe40.exe %LFLAGS%
echo *** making BY VC20
cl /MD %CFLAGS% /w %1.CPP /Fe20.exe %LFLAGS%
echo +END+
- Note 9: Win32 static link make script (bat/cmd file) for windowed application:
@echo off
cls
set _WIN32_WINNT=0x400
set WINVER=0x400
set CFLAGS=/nologo /Ox /Zp1 /D "WIN32" /D "NDEBUG"
set LFLAGS=/link /fixed:no /SUBSYSTEM:WINDOWS,3.10 /VERSION:0.0
echo +BEGIN+
echo *** making BY VS2010
cl /MT %CFLAGS% /w %1.CPP /Fe100_s.exe %LFLAGS%
echo *** making BY VS2008
cl /MT %CFLAGS% /w %1.CPP /Fe90_s.exe %LFLAGS%
echo *** making BY WDK71(VS2008)
cl /MT %CFLAGS% /w %1.CPP /Fe90w_s.exe %LFLAGS%
echo *** making BY WDK7(VS2005)
cl /MT %CFLAGS% /w %1.CPP /Fe80v_s.exe %LFLAGS%
echo *** making BY VS2005
cl /MT %CFLAGS% /w %1.CPP /Fe80_s.exe %LFLAGS%
echo *** making BY VS2003
cl /ML %CFLAGS% /w %1.CPP /Fe71_s.exe %LFLAGS%
echo *** making BY W2K3DDK(VS2003)
cl /ML %CFLAGS% /w %1.CPP bufferoverflowu.lib %LFLAGS%
echo *** making BY VS2002(VS.NET)
cl /ML %CFLAGS% /w %1.CPP /Fe70_s.exe %LFLAGS%
echo *** making BY VS1998(VS6)
cl /ML %CFLAGS% /w %1.CPP /Fe60_s.exe %LFLAGS%
echo *** making BY VS1997
cl /ML %CFLAGS% /w %1.CPP /Fe50_s.exe %LFLAGS%
echo *** making BY VC40
cl /ML %CFLAGS% /w %1.CPP /Fe40_s.exe %LFLAGS%
echo *** making BY VC20
cl /ML %CFLAGS% /w %1.CPP /Fe20_s.exe %LFLAGS%
echo +END+
- Note 10:
This is compatibility table for Win32s 1.25a (Build 142) using different Microsoft Compilers & libraries ( testing based on simple hello-world alike W32App project ):
all ulinked - BAD - error 21
a) /SUBSYSTEM:WINDOWS
1) dynamic crt (/MD, crtdll.lib) - 20..71 OK
2) dynamic crt (/MD, msvcrt.lib)
20 OK
40 error, unresolved HeapUnlock
50..60,71t error, unresolved _acmdln
others - BAD - error 21
3) static crt (/ML later /MT)
20..50 OK
60 BAD, does nothing
70,71t error, unresolved GetSystemTimeAsFileTime
others - BAD - error 21
b) /SUBSYSTEM:CONSOLE
1) dynamic crt (/MD, crtdll.lib) - 20..71t OK, except for 71
2) dynamic crt (/MD, msvcrt.lib)
20 OK
40..60 error, unresolved HeapUnlock
71t error, unresolved _initenv
3) static crt (/ML later /MT)
20..50 OK
60 BAD, does nothing
70,71t error, unresolved GetSystemTimeAsFileTime
others - BAD - error 21
- Note 11:
This is compatibility table for Win32s 1.30c (Build 174) using different Microsoft Compilers & libraries ( testing based on simple hello-world alike W32App project ):
a) /SUBSYSTEM:WINDOWS
1) dynamic crt (/MD, crtdll.lib) - all OK
2) msvcrt.lib (/MD)
20..40 OK
50..60,71t error, unresolved _acmdln
70..71 error, terminated
80..90w error, unresolved InterlockedCompareExchange
others - BAD - error 21
3) static (/ML later /MT)
20..50,71t OK
60..71 BAD, does nothing
others - BAD - error 21
b) /SUBSYSTEM:CONSOLE
1) dynamic crt (/MD, crtdll.lib) - 20..71t OK, except for 71
2) dynamic crt (/MD, msvcrt.lib)
20 OK
40..60 error, unresolved HeapUnlock
71t error, unresolved _initenv
3) static crt (/ML later /MT)
20..50,71t OK
60,80w,90w BAD, does nothing
others - BAD - error 21
Microsoft Visual FoxPro 3.0
- This product natively supports Win32s.
Spyglass Mosaic Browser
- This product natively supports Win32s.
Borland/Inprise products
- Borland C++ Compiler 5.5 ( free download link http://www.codegear.com/downloads/free/cppbuilder ) can be used for Win32s, it's linker ilink32.exe automaticly generate .reloc sections without additional switches:
- Win32 GUI version (bat/cmd file):
@echo off
bcc32 -c -a1 -f -O1 %1.c > %1.log
ilink32 /q /x /w /tW %1.obj c0w32.obj WILDARGS.OBJ import32.lib cw32.lib, %1.exe,,,,
del %1.obj
del %1.i??
- Win32 Console version (bat/cmd file):
@echo off
bcc32 -c -a1 -f -O1 %1.c > %1.log
ilink32 /q /x /w /tX %1.obj c0x32.obj WILDARGS.OBJ import32.lib cw32.lib, %1.exe,,,,
del %1.obj
del %1.i??
BearWindows©™