digitalmars.com                        
Last update Sun Sep 8 21:42:02 2013

16 Bit Windows (Win16) Programming Guidelines

This chapter describes how to use the compiler and linker to create Windows 3.x applications and DLLs. For the compiler, it explains how to choose memory models, and select the entry and exit code (if any) you want to generate for functions. For the linker, it describes switches and definition (.def) file statements for linking Windows objects.

For information about:

What's in This Chapter

Compiling Windows Programs

This section describes how to choose memory models and use prolog and epilog code when compiling Windows programs with C++.

Choosing a memory model

You can use these memory models in Windows programs: We recommend compiling Windows applications with the Large model, as this minimizes the problems associated with mixed-model programming. Windows 3.0 and later eliminate any advantage to using the Medium memory model. It is especially important to use the Large model when compiling DLLs, since some functions in the run-time library work correctly only in DLLs that are compiled with the large model. Also, Digital Mars C++ only supports MFC in the Large model.

In general, if in doubt about what model to use, use the Large model. Specify the Large model with the -ml compiler option (see Compiling Code), or use the Memory Models subpage on the Build page of the IDDE's Project Settings dialog box. (The compiler will use the Small model unless you specify otherwise.)

Note: You cannot compile Windows 3.x programs with the Tiny, DOSX, Phar Lap, or NT memory models.

Windows applications usually consist of several source files. Always compile all the files in a Windows application with the same (preferably Large) memory model if possible, or explicitly declare a type for each pointer in a function prototype. If you are mixing near and far data references, make sure that all declarations match their corresponding definitions, or hard-to-find bugs can result.

For more information, see the section "Fine-Tuning with Mixed Model Programming" in Choosing a Memory Model.

Choosing entry and exit (prolog/epilog) code

C++ generates different types of entry code (the prolog) and exit code (the epilog) for functions in Windows applications. Different types of prolog/epilog code yield different instructions in the generated code and affect the size of the executable.

You can choose the type of entry/ exit code you need from the Windows Prolog/ Epilog subpage on the Build page of the IDDE's Project Settings dialog box, or with the -W command line option. See "-W Compile for Microsoft Windows" in Compiling Code, for details about the -W option and modifiers.

When you select the No Prolog/ Epilog option (-W-or -W0), the compiler does not generate any prolog or epilog code.

Note: For compatibility with Microsoft C and C++, Digital Mars C++ supports the extension __declspec(naked), which tells the compiler not to generate prolog/ epilog code for individual functions. For information see Digital Mars C++ Language Implementation.

When you select the Full Prolog/ Epilog for all far Functions option (-W or -W1), the compiler generates one type of prolog and epilog for all far functions.

When you select the Reduced Prolog/ Epilog for non-exported far Functions option (-W2), two types of prolog and epilog result. All exported far functions have the prolog and epilog shown for the Full Prolog/ Epilog option.

When you select the Smart Callbacks -Load DS from SS for far Functions option (-W3), the compiler compiles far functions with a smart prolog and epilog that loads the data segment from the stack segment.

For more information on Windows entry and exit code, see Chapters 7 and 19 in Programming Windows 3.1 by Charles Petzold (3rd Ed.).

Warning: Only use the "Smart Callbacks" option with applications in which the data segment is the same as the stack segment (DS== SS). Do not use it with DLLs.

When you select the Windows Protected Mode Executable option (-WA), the compiler generates a protected mode Windows application with callback functions marked with __export.

When you select the Windows Protected Mode DLL option (-WD), the compiler generates a protected mode Windows DLL with callback and exported functions marked with __export.

Recommendations for using the prolog/ epilog options

The following combinations of options are recommended: You should avoid these combinations of options: If your program defines a virtual member function that you need to call from a DLL: A virtual function is a callback function. Callback functions cannot be called directly from a program; they can only be called via a pointer returned by the Windows API function MakeProcInstance(). They also must be compiled with a Windows prolog/ epilog (-W), which is impractical for virtual functions. Therefore, do not reference static or global data in a virtual function meant to be called from a DLL, or else use near pointers.

Using the -Wb option

The -Wb option (assume DS != DGROUP) causes the compiler to issue a warning whenever a segment fixup is done to DGROUP. -Wb does not affect code generation; it only reports when a DGROUP segment fixup is generated. If your program is using an alternate data segment, a segment fixup to DGROUP could be a program bug.

In Large model code, DGROUP fixup can be triggered by constructs like this:

static int x;
static int *px = &x; /* DGROUP fixup */
static char *p = "abc"; /* DGROUP fixup */
To eliminate the fixup, make the pointers near pointers:
static int __near *px = (int __near *)&x;
static char __near *p = "abc";
Using near pointers will result in DGROUP relative fixups, not DGROUP segment fixups. Alternatively, the pointers can be initialized at run time, as the compiler generates code that uses DS to initialize segment values.

Eliminating DGROUP segment fixups is useful for:

The -Wb option can be useful in tracking down hard to find bugs in the kinds of programs listed above.

Note: -Wb will cause the compiler to generate errors if you are using __loadds (because DS is reloaded from DGROUP), or if you are using -Wd (load DS from DGROUP) for Windows prologs.

Compatibility with Microsoft

The table below list Microsoft C Version 7 and Visual C++ options for generating prolog/ epilog code, and their Digital Mars C++ equivalents:

Table 17-1 VC++ options and DMC++ equivalents
Microsoft Digital Mars Result
-Gw -W Full Windows prolog/ epilog for far functions.
-Au -mwu Assume DS!= SS and load DS on entry to each function.
-Aw -mw Assume DS!= SS.
-GA -WA Optimized protected mode Windows application.
-GD -WD Optimized protected mode Windows DLL.
-GEa -Wa Load DS from AX.
-GEd -Wd Load DS from DGROUP.
-GEe -We Emit EXPDEF records for all exported functions.
-GEf -W-r Create prolog/ epilog code for all far functions.
-GEm -Wm Add inc BP/ dec BP to prolog/ epilog for far functions.
-GEr -W2V Real mode, reduced prolog for non-exported functions.
-GEs -Ws Load DS from SS.
-Gq -Wtxme Reduced prolog/ epilog. Equivalent to -GW for MSC V6. (Digital Mars C/C++ generates a full prolog/ epilog for __far __export functions; MSC V6 does not.)
-GW -Wtxmev -D_WINDOWS Reduced prolog/ epilog for real mode Windows functions.

Recompiling MFC 2.5 Code for Digital Mars C++

When recompiling MFC 2.5 code for Digital Mars C++, use the compiler options listed below for the libraries linked with:

Table 17-2 Compiler options for MFC 2.5 compilations
Use these options... With these libraries...
-WA -ml lafxcw
-WA -ml -D_DEBUG lafxcwd
-WD-r -ml -D_USRDLL lafxdw
-WD-r -ml -D_DEBUG -D_USRDLL lafxdwd
-WA-r -ml -D_DEBUG -D_AFXDLL smfc25d (for Windows application)
-WD-r -ml -D_DEBUG -D_AFXDLL smfc25d (for Windows DLL)
-WA-r -ml -D_AFXDLL smfc25 (for Windows application)
-WD-r -ml -D_AFXDLL smfc25 (for Windows DLL)
-WA-r -ml -D_DEBUG -D_AFXDLL smfco25d, mfco250d (for Windows application)
-WD-r -ml -D_DEBUG -D_AFXDLL smfco25d, mfco250d (for Windows DLL)
-WA-r -ml -D_AFXDLL smfco25 (for Windows application)
-WD-r -ml -D_AFXDLL smfco25 (for Windows DLL)
-WA-r -ml -D_AFXDLL smfcd25 (for Windows application)
-WD-r -ml -D_ AFXDLL smfcd25 (for Windows DLL)
-WA-r -ml -D_ DEBUG -D_ AFXDLL smfcd25d (for Windows application)
-WD-r -ml -D_ DEBUG -D_ AFXDLL smfcd25d (for Windows DLL)

You might also need the following options:

Note: The following libraries are only necessary if your application or DLL is using the DLL version of MFC and uses the OLE 2.0 and ODBC MFC classes: smfcd25[d].lib smfco25[d].lib mfco250[d].lib mfcd250[d].lib

For more information on the using the MFC 2.5 libraries, see the "read me" file SRC\MFC16\mfcsrc.txt in the distribution.

Win16 Definition File Directives

These are the directives used in definition files for Win16 programs. For descriptions of these directives see Definition File Directives.

NAME name[ WINDOWAPI| WINDOWCOMPAT| NOTWINDOWCOMPAT ] [ NEWFILES ]

LIBRARY name [ INITGLOBAL | INITINSTANCE ]

DESCRIPTION 'descriptive line'

EXETYPE [WINDOWS 3.00 | WINDOWS 3.10 | DOS4 | DOS | UNKNOWN]

HEAPSIZE [number | MAXVAL]

NEWFILES

PROTMODE

REALMODE

STACKSIZE number

STUB 'filespec'

CODE [PRELOAD | LOADONCALL] [EXECUTEONLY | EXECUTEREAD]
        [MOVEABLE | FIXED ] [IOPL | NOIOPL]
        [CONFORMING | NONCONFORMING] [DISCARDABLE | NONDISCARDABLE]
        [SHARED | NONSHARED]

DATA [NONE | SINGLE | MULTIPLE] [PRELOAD | LOADONCALL]
        [MOVEABLE | FIXED ] [READONLY | READWRITE]
        [IOPL | NOIOPL] [SHARED | NONSHARED]

SEGMENTS
{   name [CLASS 'class']
        [PRELOAD | LOADONCALL] [EXECUTEONLY | EXECUTEREAD]
        [MOVEABLE | FIXED ] [READONLY | READWRITE]
        [DISCARDABLE | NONDISCARDABLE] [IOPL | NOIOPL]
        [NONCONFORMING | CONFORMING] [SHARED | NONSHARED] }

IMPORTS { [internal=] externalfile.func }

EXPORTS { extname [= intname] [@ number [RESIDENTNAME | NONAME]]
        [parms] [NODATA] }
Home | Runtime Library | IDDE Reference | STL | Search | Download | Forums