EXTENDING WINDOWS TO 32 BITS

Programming benefits and pitfalls when moving to 32-bit Windows programming

Steven Baker

Steven works for the Oregon Department of Energy coaxing energy conservation out of new state buildings. He was editor of Programmer's Journal and coauthor of Extending DOS. Steven can be reached at msbaker@astute.com via Internet or msbaker@tanelorn.UUCP via UUCP.


For years, I've been using 386 DOS extenders to take advantage of the native power of the chips under the hood. While DOS extenders should have disappeared long ago, their persistence is a tribute to just how painfully slowly system software has developed. Now that Windows appears well established and offers a modestly stable environment for users, it's time to move to Windows those applications that can benefit from a GUI. Since OS/2 2.0 can also run Windows programs, this seems a safe approach. But for some applications, the move makes sense only if the potential performance of 32-bit CPUs can be exploited. I'll share with you what I've learned about 32-bit Windows development and some programming issues to consider.

Prospecting for the Golden App

The first challenge is choosing which problems are well served by moving to 32-bit Windows. To some extent, this depends on whether or not you plan on targeting Windows 3.1, Windows NT, or OS/2 Presentation Manager. Omitting OS/2, target platforms that can run 32-bit applications include 16-bit Windows 3.x hosts requiring a 32-bit Windows extender and 32-bit Windows NT in native mode. For the time being, the most likely prospect is running a 32-bit Windows application hosted atop the 16-bit Windows 3 runtime.

Full 32-bit programming works well with several types of computation problems: CPU-intensive programs, memory-intensive programs, and programs ported from 32-bit environments (UNIX, VAX, and the like).

If your application chews up a gazillion CPU cycles, then running under 32 bits offers faster performance than 16-bit Windows or DOS code. Registers are a full 32 bits wide and the 386 flat model reduces the necessity for segment-register loads with their inherent performance penalty. Programs with large memory needs also benefit dramatically from the wide open spaces that 32-bit programming provides. If you're porting to the PC from UNIX or VAX, then you're starting with a 32-bit program. Targeting an environment like 32-bit Windows will be dramatically easier than attempting to shoehorn a large UNIX application into the multiple-64K-segment world of 16-bit Windows and DOS.

On the other hand, if your program is rife with user-interface code without much computation or memory requirements, 32-bit Windows may not be appropriate. In fact, running a 32-bit app that is mostly user interface can actually be slower than the equivalent 16-bit Windows code. When running a 32-bit Windows program hosted on Windows 3.1, the Windows API calls are slower than with a native Windows 3.1 app. The average penalty is estimated at 10 percent, but, like fuel efficiency, this number can vary depending on the mix of API calls used. The degradation results from the thunk layer that must convert 32-bit parameters, addresses, and results to segmented 16:16 pointers and 16-bit integers to communicate with the underlying Windows 3.x API; see Figure 1. (Aside from address translation, a thunk layer may also handle realigning structures and the stack.)

If your target is true Windows NT, then the promise of 32-bit graphics device drivers may provide a performance boost. Keep in mind that higher-performance 32-bit video drivers may soon be in the cards for Windows 3.1.

Options for the Big Picture Show

As Table 1 shows, several choices are available for creating 32-bit GUI programs. For over a year now, both MetaWare and Watcom have bundled with their 386 compilers a 32-bit Windows development kit and Windows extender as free enhancements. Rational Systems offers BigWin, a 32-bit Windows extender, to developers for use with MetaWare, Watcom, or Zortech 386 compilers. Like Rational's DOS16/M product (used by Lotus), BigWin is priced more toward OEM sales.

Table 1: 32-bit Windows options. MetaWare and Watcom have announced future support for the Win32S Subset and the Win32 NT API. Since Windows NT is supposed to run Windows 3.1 applications, programs built with one of the Windows extenders may also run under Windows NT.

  Vendor         Product        Platform      API supported
  ---------------------------------------------------------

                    --Windows 3.1 Extenders--
  MetaWare       High C/386     Windows 3.x    Windows 3.0
                                             (extended)
  Rational       BigWin         Windows 3.x    Windows 3.1
                                             (extended)
  Watcom         C/386          Windows 3.x    Windows 3.1
                                             (extended)
  Microsoft      Win32S DLLs    Windows 3.x    Win32 Subset
                 --Native 32-bit Windows--
  Microsoft      Windows NT     Windows NT     Win32 and
                                              Win32S Subset

These three products follow the trail blazed by the 386 DOS extenders, but use Windows 3.x and its underlying DOS protected-mode interface (DPMI) to extend Windows to 32 bits. These tools allow programmers to write 32-bit Windows applications that run under Windows 3.0 and Windows 3.1 in Enhanced mode.

To programmers, these Windows extenders look like the Windows 3.x API with various parameters and functions widened to 32 bits or slightly modified for performance. Each vendor supplies replacement Windows header files for proto-typing that handle the 32-bit version of the Windows 3.x API.

New Technology for Old

Microsoft began its real push in Windows NT with its July '92 Developers' Conference and prerelease Win32 CD-ROM SDK. Soon afterwards, new manuals documenting the evolving Win32 API were made available to developers.

Part of Microsoft's strategy for enticing developers to Windows NT is providing the option of running 32-bit Windows apps on Windows 3.x. A collection of DLLs supporting a subset of the full-blown Windows NT API called Win32S will be available with the Windows NT SDK for use with Windows 3.1. An initial version the Win32S DLLs made its way onto the October '92 Win32 SDK CD-ROM. Win32S offers the promise of creating a single executable that will run under both Windows 3.1 and Windows NT.

The Win32S DLLs for Windows 3.1 provide a 32-bit Windows extender similar to the MetaWare, Watcom, and Rational Windows extenders. The Win32S DLLs work only with Windows 3.1. It's unlikely that Microsoft will add support for Windows 3.0 -- the earlier version had too many bugs to patch and work around for Microsoft's taste. In fact, some of the design decisions of the other Windows extenders resulted from manipulating around serious Windows 3.0 bugs for 32-bit programs.

A Map for All Seasons

Each Windows extender provides a slightly different twist to the memory model that an application sees. All provide a thunking layer or Windows supervisor that translates between 32-bit Windows calls and the native segment:offset (16:16) format required by the 16-bit Windows 3 kernel; see Figure 2.

Both MetaWare and Watcom use a similar zero-based flat memory model with a fixed 64K stack at the bottom, followed by code, static data, and heap; see Figure 3. MetaWare and Watcom use DPMI to allocate memory from the Windows kernel, manage this 32-bit segment, and trap various INT functions for special handling. The stack size and its placement were designed to handle serious bugs in Windows 3.0.

Under some circumstances, the Windows 3.0 kernel trashes the upper half of the stack-pointer register (ESP). Limiting the stack of the bottom 64K of the segment preempts damage from occurring. This stack is also shared by the 16-bit side of the supervisor so parameters can be easily passed.

A design fault in the DPMI specification can preclude simultaneously running more than one 32-bit application that requires floating-point emulation. Watcom provides a virtual device driver (VxD) that provides floating-point emulation and allows any number of 32-bit apps to run. The Watcom VxD uses the first 256 bytes of the stack to store the environment, including the floating-point registers when context is switched to another program using floating-point emulation. This enhancement is lacking in the MetaWare and Rational extenders. Under Windows NT and IBM OS/2 2.0, the operating system provides floating-point emulation--the preferred strategy.

One outcome of using a zero-based model is that pointers returned by Windows from, say, a DDE message must be turned into a 48-bit (segment:offset) data pointer by the thunking layer for access. When an application gets this data, segment registers must be reloaded. Callbacks in the 32-bit application must also be passed as 48-bit pointers to the thunking layer.

Windows 3.0 can also trash the upper half of the instruction pointer (EIP) when executing certain DOS and BIOS interrupt instructions. Keeping the 32-bit library code that executes these INT instructions below 64K (intdos and intdosx, for example) prevents these problems.

Rational's BigWin also presents a flat memory model to a 32-bit program, but it is not zero based. Instead of asking the Windows kernel for memory using DPMI, the BigWin VxD goes to the bottom of the chain and talks directly to the low-level memory-manager device driver below Windows. A BigWin segment uses various page-allocate requests and page mapping to create a more flexible flat-model memory map. This allows BigWin to map its thunking layer and Windows itself into this same segment. A DDE message pointer passed by Windows from some other application also maps into this flat segment. Segment registers in a BigWin application never need to be loaded.

The stack under Rational's BigWin is not limited to 64K. Rather than relying on the Windows kernel for DOS and BIOS interrupt support with its resulting quirks and bugs, Rational was able to just incorporate the INT handler technology from their other DOS extenders. BigWin even demand-loads the 32-bit application rather than reading the whole executable into memory at startup.

The Mircrosoft Win32S DLLs for Windows 3.1 are tightly integrated with the Windows kernel code, a luxury that only Microsoft could have. This allows Win32S to support a more flexible flat memory model similar to Rational's BigWin. By ignoring Windows 3.0, Microsoft was able to eliminate a number of difficult problems other vendors had to work around. Rather than using INT 7 (the Coprocessor Not Present exception) for floating-point emulation, Microsoft compilers use other INT functions that point into the compiler library for this emulation. With this strategy, Microsoft isn't limited to a single 32-bit application that uses the emulator.

Heady Changes Ahead

With the exception of Microsoft's Win32S extender, the tools in Table 1 all support a 32-bit version of the Windows 3.1 API, although the Windows header files must be changed to reflect where parameters have been widened. Revised header files also prototype functions that may require FAR (48-bit) pointers from a 32-bit program. The thunking layer supplied by each vendor can hide much of the requirement for 48-bit pointers. Still, the three Windows extenders take different approaches to this issue.

At one end of the spectrum is the thunking layer in Rational's BigWin, which eliminates the necessity of any far pointers for the programmer. Watcom is closer to the middle since the programmer must explicitly convert function callbacks and some returned data pointers (DDE messages from other apps, for example) to far pointers with some supplied macros. MetaWare is at the other extreme: It defines all Windows calls and data pointers to Windows parameters as FAR (48-bit), rather than hiding much of this in the thunking layer.

Changes to the calling conventions necessitated by the thunking layer and any widened parameters must also be reflected in revised header files. The file requiring the most change in WINDOWS.H, supplied with the Microsoft Windows 3.1 SDK. Microsoft defined many of the Windows 3.1 structures in a nonportable way by using int in place of short. Somehow Microsoft managed to clean up most of the other headers supplied with the 3.1 SDK before its release. Windows NT header files use the UINT macro in structures to hide this difference.

Watcom handles these header changes by actually #includeing the 3.1 header file intact within their own WINDOWS.H wrapper file, which temporarily #defines int to short and dummies out FAR when _WINDOWS_16 is not defined. Rational provides a revised WINDOWS.H file with the offending structure members explicitly changed to short and the FAR modifier removed. MetaWare provides a complete rewrite of the header files with even more changes since parameters to Windows functions become extended to FAR (48-bit) data pointers. Windows messages remain unchanged from the Windows 3.1 API.

One of Microsoft's design goals for Win32 API was to minimize the impact on existing code, so that 16-bit applications can be easily adapted. However, some significant changes were made along the way for the larger address space; see Table 2. The most problematic change for programmers is that some messages are modified and repacked, most notably WM_COMMAND. Microsoft's Win32S reflects a subset of the full Win32 API. The Win32S API functions and the 32-bit versions of the Win 3.1 API from these other vendors are reasonably close, with a few exceptions. I've extracted excerpts from Windows.H for comparison between the 3.1 SDK and these Windows extenders. These files are available electronically, see "Availability" on page 5.

Table 2: Changes from the Windows 3.1 API. Remember that the Win32 API is a moving target. This information is based on the October '92 NT SDK.

                  Total   Comparison with Windows 3.1 API:
                  count   Widened Changed Dropped New
  --------------------------------------------------------

                     --Functions--
  Windows 3.1      973
  Win32S           838    711    6    256   121
  Win32           1449    829    6    138   614
                      --Messages--
  Windows 3.1      271
  Win32S           287    250   21      0    16
  Win32            291    250   21      0    20

Win 3.1 and the Win32S API differ primarily in repacking messages. The other three Windows extenders don't require such changes. The MetaWare and Watcom extender do require the programmer to explicitly convert some function and data pointers to FAR using supplied macros. To illustrate how your source might change, I've excerpted code from a converted version of the GENERIC sample program comparing Win 3.1 and the Windows extenders. Listing One (page 88) is the code from the Windows 3.1 SDK, Listing Two (page 88) is the same code converted to Rational Systems' BigWin, Listing Three (page 88) is code for Watcom's C/386, Listing Four (page 88) is code for MetaWare's High C/386, and Listing Five (page 88) is code for the Windows NT October '92 SDK beta.

The MetaWare, Rational, and Watcom Windows extenders offer one significant advantage over Win32S when converting from existing 16-bit Windows programs. All these other products support calling 16-bit DLLs while Win32S does not. For Microsoft to support mixing 16-bit and 32-bit code would break the notion of a single Win32S-compatible executable running on both Windows 3.1 and NT. By supporting 16-bit DLLs, the transition to 32 bits can be made gradually, module by module. Third-party libraries or existing assembly language modules can be used until 32-bit code is available. With Win32S it's currently an all-or-nothing proposition.

Testing the 32-bit Waters

When running Windows 3 executables on either Windows NT or OS/2, similar thunking layers must be used, but in reverse. Consequently, I ran the 16-bit version of PC Labs' Winbench program (a benchmark for video cards) under Windows NT and OS/2 2.0; this should give a rough indication of the worst-case thunk overhead for common GDI operations. This assumes that both OS/2 and NT have comparable VGA drivers to Windows 3.1. As Table 3 shows, the OS/2 thunking layer surprisingly had less overhead than the October '92 version of NT.

Table 3: Thunking overhead using Winbench 2.5. Benchmarks run on a 386/40 in 640x480 mode with a standard VGA device driver and an older Tseng 3000 card. Larger numbers are better.

  Platform                 Performance

  Windows 3.1            1,285,900 pixels/sec
  OS/2 2.0               1,029,760 pixels/sec
  Win NT (Oct '92 SDK)     787,218 pixels/sec

I selected several program types for evaluating the benefits offered with 32-bit Windows, including simulation (intense number crunching), database operations, large text-manipulation tools, and graphics (image) processing. For each type, I tried to create a modest Windows program or test application to determine the possible performance benefits. For comparison purposes, I had to create equivalent 16-bit and 32-bit Windows programs -- a very time-consuming process. (Source code for some of the conversion programs is provided electronically; see "Availability," page 5.)

To represent the sheer number crunching of simulation, I modified a version of the Linpack benchmark (translated to C) to run under Windows and display its results. The execution timing differences are dominated by the computation times since the text and graphics output-function overhead is modest.

For database operations, I used library routines from CodeBase 4.5 from Sequiter Software (Edmonton, Alberta) for manipulating large database and index files (FoxBase format). For text manipulation, I tried several different programs. I pulled out and modified part of the PortTool sample code from the Windows NT SDK to run under 16-bit Windows. This program scans a source-code file for Windows functions that may require changes when porting to the Win32 API. PortTool reads a datafile of keywords into memory, creates a linked list of keywords, and loops through this list, comparing every token in the source file. The second text tool was the GNU diff program that reads two files into memory, scans for comparisons, and reports the differences. The algorithm used by diff hashes the lines and goes about its comparisons. The problem under DOS and Windows comes about when the files are large and huge pointers must be used.

For graphics processing, I had originally planned to port a large UNIX ray-tracing program. But after some false starts, I extracted parts of another sample from the Windows NT SDK--the Julia (Mandel) program which calculates and draws the Mandelbrot and corresponding Julia set. Julia can do its calculations with either fixed-point or floating-point math and uses the Windows GDI and USER functions to draw fractals.

Most of my test programs improved by at least a factor of two, going from 16- to 32-bit Windows. Table 4 shows the most dramatic results of these tests for Linpack. If huge pointers must be used to access data structures (like arrays) greater than 64K, then the overhead under 16-bit Windows is truly enormous. These 32-bit Windows extenders offer much better performance than their 16-bit counterparts on these selected program types. I found porting code to 32-bit Windows can be somewhat frustrating, but the performance benefits for your application can be most rewarding.

Table 4: Using Linpack to compare DOS, 16-bit, and 32-bit Windows. Higher numbers are better--floating-point operations per second (FLOPS) for single-precision results on an AMI 486/33.

API               Execution Rate    Compiler       Extender

MS-DOS            23,000 FLOPS      Watcom C       none
16-bit Windows    18,000 FLOPS      Watcom C       Windows 3.1
32-bit Windows     1,360,000 FLOPS  Watcom C/386   BigWin & Windows 3.1
Extended DOS       1,440,000 FLOPS  Watcom C/386   Watcom (Rational)

Products Mentioned

MetaWare Extended                 Watcom C9.0/386
DOS                               Watcom
High C/C++ w/ADK                  415 Philips Street
MetaWare                          Waterloo, Ontario
2161 Delaware Avenue              Canada N2L 3X2
Santa Cruz, CA 95060              800-265-4555
408-429-6382



                                  Windows NT SDK
BigWin SDK                        Microsoft
Rational Systems                  1 Microsoft Way
220 North Main Street             Redmond, WA 98052
Natick, MA 01760                  206-882-8080
508-653-6006


_EXTENDING WINDOWS TO 32 BITS-
by Steven Baker


[LISTING ONE]

/* Excerpts from GENERIC sample program supplied with Windows 3.0 & 3.1 SDK  */

BOOL InitApplication(hInstance)
HANDLE hInstance;                       /* current instance           */
{
    WNDCLASS  wc;

    /* Fill in window class structure with parameters that describe the  */
    /* main window.                                                      */

    wc.style = NULL;                    /* Class style(s).               */
    wc.lpfnWndProc = MainWndProc;       /* Function to retrieve messages */
                                        /* for windows of this class.    */
    wc.cbClsExtra = 0;                  /* No per-class extra data.      */
    wc.cbWndExtra = 0;                  /* No per-window extra data.     */
    wc.hInstance = hInstance;           /* Application that owns class.  */
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "GenericMenu";   /* Name of menu resource in RC file. */
    wc.lpszClassName = "GenericWClass"; /* Name in call to CreateWindow. */

    /* Register the window class and return success/failure code. */

    return (RegisterClass(&wc));
}
long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;                                /* window handle                   */
unsigned message;                         /* type of message                 */
WORD wParam;                              /* additional information          */
LONG lParam;                              /* additional information          */
{
    FARPROC lpProcAbout;                  /* pointer to the "About" function */
    switch (message) {
        case WM_COMMAND:           /* message: command from application menu */
            if (wParam == IDM_ABOUT) {
                lpProcAbout = MakeProcInstance(About, hInst);
                DialogBox(hInst,                 /* current instance         */
                    "AboutBox",                  /* resource to use          */
                    hWnd,                        /* parent handle            */
                    lpProcAbout);                /* About() instance address */
                FreeProcInstance(lpProcAbout);
                break;
            }
            else                            /* Lets Windows process it       */
                return (DefWindowProc(hWnd, message, wParam, lParam));
        case WM_DESTROY:                  /* message: window being destroyed */
            PostQuitMessage(0);
            break;
        default:                          /* Passes it on if unproccessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (NULL);
}





[LISTING TWO]


/* Excerpts from GENERIC.C modified for use with Rational Systems BigWin
 * 32-bit Windows extender. Class names must be unique for each "instance" to
 * run multiple instances of the same 32-bit Windows program. The WNDPROC macro
 * is used to handle the differences between the MetaWare, Watcom, and Zortech
 * compilers and their strictness when parsing multiple attributes. These are
 * the only changes required to recompile this program.  */

static char szClassName[8] ; /* GENxxxx, where xxxx is instance hdl */

BOOL InitApplication(hInstance)
HANDLE hInstance;                              /* current instance           */
{
    WNDCLASS  wc;

    wc.style = NULL;                    /* Class style(s).               */
    wc.lpfnWndProc = (WNDPROC) MainWndProc;
                                        /* windows of this class.        */
    wc.cbClsExtra = 0;                  /* No per-class extra data.      */
    wc.cbWndExtra = 0;                  /* No per-window extra data.     */
    wc.hInstance = hInstance;           /* Application that owns the class.  */
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "GenericMenu";   /* Name of menu resource in RC file. */
    wsprintf(szClassName, "GEN%4.4X", hInstance) ;
    wc.lpszClassName = szClassName ;

    return (RegisterClass(&wc));
}







[LISTING THREE]


/* Excerpts from GENERIC.C modified for use with Watcom C/386 Compiler and
 * 32-bit Windows extender. Class names must be unique for each "instance" to
 * run multiple instances of the same 32-bit Windows program. The LPVOID macro
 * for callback functions casts this function pointer as a far (16:32) pointer
 * These are the only changes required to recompile this program.  */

char _class[64];

BOOL InitApplication(hInstance)
HANDLE hInstance;                              /* current instance           */
{
    WNDCLASS  wc;
    wc.style = NULL;                    /* Class style(s).                */
    wc.lpfnWndProc = (LPVOID) MainWndProc;
                                        /* windows of this class.         */
    wc.cbClsExtra = 0;                  /* No per-class extra data.       */
    wc.cbWndExtra = 0;                  /* No per-window extra data.      */
    wc.hInstance = hInstance;           /* Application that owns the class.  */
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "GenericMenu";   /* Name of menu resource in RC file. */
    sprintf( _class,"GenericWClass%d",hInstance );
    wc.lpszClassName = _class; /* Name used in call to CreateWindow. */
    return (RegisterClass(&wc));
}






[LISTING FOUR]


/* Excerpts from GENERIC.C modified for use with MetaWare High C/C++ 386
 * Compiler and 32-bit ADK Windows extender. The "unsigned" message parameter
 * is changed to a WORD message. This is the only change required to recompile
 * this program. The function declararations in the revised WINDOWS.H handle
 * any other changes. */

long FAR PASCAL MainWndProc(hWnd, message, wParam, lParam)
HWND hWnd;                                /* window handle                   */
WORD message;                             /* type of message                 */
WORD wParam;                              /* additional information          */
LONG lParam;                              /* additional information          */






[LISTING FIVE]


/* Excerpts from GENERIC.C modified for use with Windows NT October SDK beta.
 * The use of the WNDPROC cast of MainWndProc and the use of the APIENTRY macro
 * for callback functions since WINDOWS NT currently uses the _stdcall calling
 * convention for windows functions (a cross between C parameter passing order
 * and Pascal's callee clears stack efficiency. The largest change is that
 * many messages are packed differently in the Windows API and must be unpacked
 * differently from the the Windows 3.1 API (see the WM_COMMAND message below
 * and the LOWORD macro). The DialogBox callback for the about box also has
 * messages that that must be unpacked differently (not shown)  */

BOOL InitApplication(HANDLE hInstance)       /* current instance             */
{
    WNDCLASS  wc;

    wc.style = NULL;                    /* Class style(s).                  */
    wc.lpfnWndProc = (WNDPROC)MainWndProc; /* Function to retrieve messages */
                                        /* for windows of this class.       */
    wc.cbClsExtra = 0;                  /* No per-class extra data.         */
    wc.cbWndExtra = 0;                  /* No per-window extra data.        */
    wc.hInstance = hInstance;          /* Application that owns the class.  */
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName =  "GenericMenu";   /* Name of menu resource in RC file. */
    wc.lpszClassName = "GenericWClass"; /* Name in call to CreateWindow. */

    return (RegisterClass(&wc));
}
LONG APIENTRY MainWndProc(
        HWND hWnd,                /* window handle                   */
        UINT message,             /* type of message                 */
        UINT wParam,              /* additional information          */
        LONG lParam)              /* additional information          */
{
    FARPROC lpProcAbout;          /* pointer to the "About" function */
    switch (message) {
        case WM_COMMAND:           /* message: command from application menu */
            if (LOWORD(wParam) == IDM_ABOUT) {
                    lpProcAbout = MakeProcInstance((FARPROC)About, hInst);
                DialogBox(hInst,                 /* current instance         */
                    "AboutBox",                  /* resource to use          */
                        hWnd,                    /* parent handle            */
                        lpProcAbout);            /* About() instance address */
                FreeProcInstance(lpProcAbout);
                break;
            }
            else                            /* Lets Windows process it       */
                    return (DefWindowProc(hWnd, message, wParam, lParam));
        case WM_DESTROY:                  /* message: window being destroyed */
            PostQuitMessage(0);
            break;
        default:                          /* Passes it on if unproccessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return (NULL);
}



=====================================================

UNPUBLISHED SOURCE CODE FROM HERE ON:

/* Selected excerpts from WINDOWS.H supplied with Windows 3.1 SDK
 *
 * Note the use of nonportable "int" parameters in functions and structures
 *      that will map to 16-bit values for a 16-bit compiler
 *      or 32-bit bits for a 386 compiler
 */

#define FAR                 _far
#define PASCAL          _pascal
#define WINAPI              _far _pascal

typedef unsigned int       UINT;

typedef UINT                    HANDLE;
#define DECLARE_HANDLE(name)    typedef UINT name

DECLARE_HANDLE(HWND);   // after first expansion becomes "typedef UINT HWND"

HWND    WINAPI CreateWindowEx(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);
HWND    WINAPI CreateWindow(LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);

/* WM_CREATE/WM_NCCREATE lParam struct */
typedef struct tagCREATESTRUCT
{
    void FAR* lpCreateParams;
    HINSTANCE hInstance;
    HMENU     hMenu;
    HWND      hwndParent;
    int       cy;
    int       cx;
    int       y;
    int       x;
    LONG      style;
    LPCSTR    lpszName;
    LPCSTR    lpszClass;
    DWORD     dwExStyle;
} CREATESTRUCT;
typedef CREATESTRUCT FAR* LPCREATESTRUCT;

======================================================


/* Excerpts from WINDOWS.H supplied with Rational Systems BigWin
 *
 * note that "int" parameters in functions are left unchanged,
 *      but are now widened to 32-bits when passed
 * and "int" declarations in structures have been changed to SHORT
 *      to ensure they match with Windows 3.1 definitions
 */

#define _far

#define PASCAL              _pascal
#define WINAPI              _far _pascal

typedef unsigned short      UINT;

typedef UINT                    HANDLE;
#define DECLARE_HANDLE(name)    typedef UINT name

DECLARE_HANDLE(HWND);

HWND    WINAPI CreateWindowEx(DWORD, LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);
HWND    WINAPI CreateWindow(LPCSTR, LPCSTR, DWORD, int, int, int, int, HWND, HMENU, HINSTANCE, void FAR*);

/* WM_CREATE/WM_NCCREATE lParam struct */
typedef struct tagCREATESTRUCT
{
    void FAR* lpCreateParams;
    HINSTANCE hInstance;
    HMENU     hMenu;
    HWND      hwndParent;
  SHORT       cy;
  SHORT       cx;
  SHORT       y;
  SHORT       x;
    LONG      style;
    LPCSTR    lpszName;
    LPCSTR    lpszClass;
    DWORD     dwExStyle;
} CREATESTRUCT;
typedef CREATESTRUCT FAR* LPCREATESTRUCT;


[LISTING THREE: UNPUBLISHED SOURCE]


/* Excerpts from WINDOWS.H supplied with Watcom C/386 Compiler
 *
 * note that "int" parameters in functions and structures are left unchanged,
 *      but "int" is #defined as "short"
 * after inclusion of the original WINDOWS.H file int, far, etc are #undef
 */

#ifdef _WINDOWS_16_
#include <win16.h>   // the original Windows 3.1 file left intact
#else
#include <_win386.h>   // Watcom's 32-bit header file wrapper
#endif

// Excerpts from _win386.h
#define int short
#define __far
#define __huge
#define __export

#include <win16.h>   // the original Windows 3.1 file left intact

#undef int
#undef __far
#undef __huge
#undef FAR
#define FAR far


[LISTING FOUR: UNPUBLISHED SOURCE]


/* Excerpts from WINDOWS.H supplied with MetaWare High C/386 Compiler
 *
 * note that "int" parameters in functions and structures are left unchanged,
 *      but "int" is #defined as "short", and "far" disappears
 * after inclusion of the original WINDOWS.H file int, far, etc are #undef
 */

#ifdef __HIGHC__
#define int short
#define far

#   define lpFAR   _Dfar
#endif

#define FAR                 far
#define PASCAL              pascal

typedef char lpFAR            *LPSTR;
typedef char _Dfar *LP48STR;

HWND  FAR PASCAL CreateWindow(LP48STR, LP48STR, DWORD, int, int, int, int, HWND, HMENU, HANDLE, LP48STR);
HWND  FAR PASCAL CreateWindowEx(DWORD, LP48STR, LP48STR, DWORD, int, int, int, int, HWND, HMENU, HANDLE, LP48STR);

typedef struct tagCREATESTRUCT
  {
    LP48STR       lpCreateParams;   // a true 48-bit (16:32) far pointer
    HANDLE      hInstance;
    HANDLE      hMenu;
    HWND        hwndParent;
    int         cy;      // members become defined as 16-bit short
    int         cx;
    int         y;
    int         x;
    LONG        style;
    LP48STR       lpszName;
    LP48STR       lpszClass;
    DWORD       dwExStyle;
  } CREATESTRUCT;
typedef CREATESTRUCT FAR    *LPCREATESTRUCT; typedef CREATESTRUCT _Dfar *LP48CREATESTRUCT;

===========================================================

/* Selected excerpts from WINDOWS.H, WINBASE.h, and WINUSER.H supplied with
 *      Windows NT October SDK beta
 *
 * Note the use of nonportable "int" parameters in structure definitions
 *      that will map to 16-bit values for a 16-bit compiler
 *      or 32-bit bits for a 386 compiler
 * Note that "int" parameters have now been widened to 32-bits
 * Two versions of this function exist in the Win32 API depending on
 *      whether UNICODE (16-bit characters) is used
 */

#define far
#define near
#define pascal

#define WINAPI
#define APIENTRY    WINAPI
#define PASCAL              pascal
#define FAR                 far

typedef unsigned int        UINT;

HWND WINAPI CreateWindowExA(
    DWORD dwExStyle,
    LPCSTR lpClassName,
    LPCSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);

HWND WINAPI CreateWindowExW(
    DWORD dwExStyle,
    LPCWSTR lpClassName,
    LPCWSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif // !UNICODE

typedef struct tagCREATESTRUCTA {
    LPVOID      lpCreateParams;
    HINSTANCE   hInstance;
    HMENU       hMenu;
    HWND        hwndParent;
    int         cy;
    int         cx;
    int         y;
    int         x;
    LONG        style;
    LPCSTR   lpszName;
    LPCSTR     lpszClass;
    DWORD       dwExStyle;
} CREATESTRUCTA, *LPCREATESTRUCTA;
typedef struct tagCREATESTRUCTW {
    LPVOID      lpCreateParams;
    HINSTANCE   hInstance;
    HMENU       hMenu;
    HWND        hwndParent;
    int         cy;
    int         cx;
    int         y;
    int         x;
    LONG        style;
    LPCWSTR  lpszName;
    LPCWSTR    lpszClass;
    DWORD       dwExStyle;
} CREATESTRUCTW, *LPCREATESTRUCTW;
#ifdef UNICODE
#define CREATESTRUCT CREATESTRUCTW
#define LPCREATESTRUCT LPCREATESTRUCTW
#else
#define CREATESTRUCT CREATESTRUCTA
#define LPCREATESTRUCT LPCREATESTRUCTA
#endif // UNICODE


================================================================

/* Selected excerpts from WINDOWS.H, WINBASE.H, and WINUSER.H supplied with
 * Windows NT October '92 SDK beta. Note use of nonportable int parameters in
 * structure definitions that will map to 16-bit values for a 16-bit compiler
 * or 32-bit bits for a 386 compiler. Note int parameters have now been widened
 * to 32-bits. Two versions of this function exist in the Win32 API depending
 * on whether UNICODE (16-bit characters) is used */


#define far
#define near
#define pascal

#define WINAPI
#define APIENTRY    WINAPI
#define PASCAL              pascal
#define FAR                 far

typedef unsigned int        UINT;

HWND WINAPI CreateWindowExA(
    DWORD dwExStyle,
    LPCSTR lpClassName,
    LPCSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);

HWND WINAPI CreateWindowExW(
    DWORD dwExStyle,
    LPCWSTR lpClassName,
    LPCWSTR lpWindowName,
    DWORD dwStyle,
    int X,
    int Y,
    int nWidth,
    int nHeight,
    HWND hWndParent ,
    HMENU hMenu,
    HINSTANCE hInstance,
    LPVOID lpParam);
#ifdef UNICODE
#define CreateWindowEx CreateWindowExW
#else
#define CreateWindowEx CreateWindowExA
#endif // !UNICODE

typedef struct tagCREATESTRUCTA {
    LPVOID      lpCreateParams;
    HINSTANCE   hInstance;
    HMENU       hMenu;
    HWND        hwndParent;
    int         cy;
    int         cx;
    int         y;
    int         x;
    LONG        style;

    LPCSTR   lpszName;
    LPCSTR     lpszClass;
    DWORD       dwExStyle;
} CREATESTRUCTA, *LPCREATESTRUCTA;
typedef struct tagCREATESTRUCTW {
    LPVOID      lpCreateParams;
    HINSTANCE   hInstance;
    HMENU       hMenu;
    HWND        hwndParent;
    int         cy;
    int         cx;
    int         y;
    int         x;
    LONG        style;
    LPCWSTR  lpszName;
    LPCWSTR    lpszClass;
    DWORD       dwExStyle;
} CREATESTRUCTW, *LPCREATESTRUCTW;
#ifdef UNICODE
#define CREATESTRUCT CREATESTRUCTW
#define LPCREATESTRUCT LPCREATESTRUCTW
#else
#define CREATESTRUCT CREATESTRUCTA
#define LPCREATESTRUCT LPCREATESTRUCTA
#endif // UNICODE






Copyright © 1993, Dr. Dobb's Journal