[<<Previous Entry] [^^Up^^] [Next Entry>>] [Menu] [About The Guide]
 Dual mode
------------------------------------------------------------------------------


 Overview

 The ability to create dual mode programs simply by adding a single command
 to the link script file is a major breakthrough. Dual mode programs detect
 at startup whether there are enough system resources to run in protected
 mode. If there are insufficient resources then the same program will run as
 a normal dynamically overlaid program.

 The .EXE still only consists of one program capable of operating in either
 mode, it is not two separate copies joined together in some way. There is
 negligible increase in .EXE size over a single mode program, and a similarly
 negligible overhead in execution speed, since the whole program is loaded
 into memory when running in protected mode.

 For this dual mode to work and be effective, all code must be written to
 execute in both real and protected mode. High level languages, such as CA-
 Clipper, require no code changes whatsoever to run in protected mode, and
 changes for C, PASCAL and FORTRAN are the exception rather than the rule.
 This requirement should only effect high level C and ASM programmers. In the
 worst case the code should be able to test for the processor mode each time
 it is executed and then jump to the appropriate code.

 We suggest that C and ASM programmers DO NOT create a protected mode library
 separate from the real mode library, since both types of code will have to
 be linked in at link time to create a dual mode program. The benefits of
 writing dual mode code and creating a dual mode library include :

    .  Only one copy of the source code and one library to maintain.
    .  Less disk space requirement for distribution.
    .  Less technical support with people linking the wrong library.

 Coding for dual mode

 This section details the suggested way to adapt code to run in both real and
 protected mode, rather than coding specifically for one or the other.

 When linking DOS extended or dual mode programs it is always necessary to
 include an additional Blinker library for the appropriate compiler. This
 library contains replacement .OBJs for any compiler library .OBJs which are
 not protected mode compatible.

 The Blinker libraries all have names of the form BLXcccnn, where ccc
 indicates the vendor and compiler, and nn indicates the compiler version
 number. They are all compiled as large model and so should only be used with
 large model programs.

 The appropriate compiler library must always be SEARCHed just before the
 standard compiler library or the script file containing the compiler
 library.

 For example, with Microsoft Visual C++:

    SEARCH BLXMVC15      # Blinker library
    LIB LLIBCE           # MSVC library

 or with CA-Clipper 5.2:

    SEARCH BLXCLP52      # Blinker library 
    LIB CLIPPER       # CA-Clipper library

 or:

    SEARCH BLXCLP52      # Blinker library 
    @CL520MID            # Script containing CA-Clipper library

 If the compiler library is not explicitly mentioned then place the SEARCH of
 the Blinker library as the last library in the link file.

 When using third-party libraries please ensure that they are protected mode
 or dual mode compatible before attempting to use them in a DOS extended
 program. Blinkinc cannot guarantee that any particular library is either
 overlayable or protected mode compatible or both. Please refer to the file
 3RDPARTY.DOC for up-to-date details on compatibility issues which we are
 aware of. The third party libraries should typically be placed before the
 SEARCH of the Blinker library unless otherwise documented in the third party
 product.

 As stated before, most code will actually run in both modes without
 modification. Most of the remaining code will run in either mode after being
 modified to use a variable set up with the appropriate value at start up.
 For example, in the case of directly accessing the video buffer, in C we
 would write:

    #include <blx286.h>
    BYTE ProcMode;
    static SEL Selector;
    static unsigned char far *VideoBuffer;
    ...
    if (DosGetMachineMode(&ProcMode) == 0)
       switch (ProcMode)
          {
          case 0:
             printf ("\nReal mode - absolute pointers ok\n");
             VideoBuffer = MK_FP(0xb800,0);
             break;
          case 1:
             printf ("\n286 Protected mode - plenty memory\n");
             if (DosMapRealSeg (0xb800, 4000l, &Selector))
                {
                printf ("\nTrouble\n");
                exit (1);
                }
             VideoBuffer = MK_FP(Selector,0);
             break;
          default:
             printf ("\nOther mode - interesting\n");
             exit(1);
       }

 Then:

    *VideoBuffer[0] = `*';     /* Display a `*' in top left */
                                  /* corner of screen */

 As can be seen, there is no extra overhead in code or execution speed once
 the initialisation has been done.

 In the exceptional case where the code is totally different for the two
 modes, one of two approaches can be used. The first is to use a simple `if'
 or `switch' statement on a global variable, as is used in the example above
 for the initialisation code. If the choice has to be made throughout your
 code the second method of using a function pointer is more appropriate.

    #include <blx286.h>
    
    int (*DoCode) (int);       /* Variable for function pointer*/
    int ProtCode (int);        /* Protected mode code function */
    int RealCode (int);        /* Real mode code function */
    ...
    if (ProcMode)              /* If protected mode */
       DoCode = ProtCode;
    else                       /* Real mode */
       DoCode = RealCode;
    
    int ProtCode (int abc)
       {
       printf ("ProtCode %d\n",abc);
       return (abc * 2);
       }

 Then:

    DoCode(1234);              /* Execute the appropriate code */

 It should be noted that in the unusual cases where an overhead is necessary,
 it is absolutely minimal, less than a millionth of a second in C even on a
 286. In the case of a higher level language such as CA-Clipper, which
 executes hundreds of these tests for each `if' clause in the CA-Clipper
 source, the relative overhead is so small as to be totally irrelevant.

 There is a common misconception that this type of construct will slow down a
 program written in a high level language program such as CA-Clipper. As
 anyone who has traced these things under an assembly language debugger will
 know, even passing a simple logical or integer variable from CA-Clipper to C
 or ASM requires hundreds of CPU instructions, including a large number of
 test and jump instructions like the one above.

 The only time that the overhead is even vaguely an issue is when the code is
 executed hundreds of thousands of times without interacting with, i.e.
 calling or returning to, the high level language.

 Low level programming

 As an alternative to using the API functions described in Chapter 10, a
 subset of the DPMI API is also provided by the Blinker DOS extender if a
 DPMI host is not available. This means that programs can be written to
 directly access the DPMI functions to allocate and manage segments. The
 benefit is that the code is then not specific to a particular extender.

 The down side is that the functions are typically at a lower level than
 those provided by the extender API functions, so more work may be required
 on the part of the programmer.

This page created by ng2html v1.05, the Norton guide to HTML conversion utility. Written by Dave Pearson