 Microsoft OS/2 Software Development Kit
 =============================================================================


 1. Executing OS/2 Applications under MS-DOS

 Problem:

 I am unable to execute an OS/2 application under MS-DOS. The program
 executes correctly under OS/2.

 Response:

 To prepare an application to execute under OS/2 and MS-DOS, do the
 following:

 1. Check the code against compatibility rules (see "Programming Hints"
    4.2.3).

 2. Use a subset of API calls (see "Programming Hints" 4.3).

 3. Link with -Lp option, when using C, as in the following example:

    cl -G0 -Lp <filename.ext>.

 4. Use cpbind to create compatible application, as in the following
    example:

    cpbind <filename.ext>  \lib5\api.lib  \lib5\doscalls.lib.


 2. Opening Files under Both OS/2 and MS-DOS

 Problem:

 My application runs correctly under OS/2, but is unable to open a file
 under MS-DOS.

 Response:

 The following is an example function that will open a file under
 OS/2 and MS-DOS. Note the settings of modeflag(struct flags).

 /***  openfile - opens file to be read
  *
  *    openfile uses DOSOPEN to open or create a file and
  *      return a handle to it.
  *
  *    openfile (fname, fhandle)
  *
  *    ENTRY    fname   - name of the file
  *
  *    EXIT     fhandle - file handle
  *
  *    openfile will exit the program if there is an error
  *      opening the file or if the file was created by
  *      DOSOPEN.
  *
  *    EFFECTS  fhandle - by returning a handle to the file
  *             memory  - by opening a file
  */

 void openfile(fname, fhandle)
 char           *fname;
 unsigned short *fhandle;
 {
     unsigned short actiontaken = 0;    /* value return by DOS */
     unsigned long  fsize = 0l;         /* set to not change file size (0) */
     unsigned short fattrib  = 0;       /* set to not change file attrib (0) *
     unsigned short openflag = 0x0011;  /* set to open or create file */
     struct flags {
       unsigned access     :3 ;   /* set to read & write access (2) */
       unsigned reserved1  :1 ;   /* must be zero */
       unsigned sharing    :3 ;   /* set to deny read & write access (1) */
       unsigned inheritance:1 ;   /* set to private (1) */
       unsigned reserved5  :5 ;   /* must be zero */
       unsigned failerrors :1 ;   /* needs to be zero for API */
       unsigned write      :1 ;   /* needs to be zero for API */
       unsigned dasdopen   :1 ;   /* needs to be zero for API */
     };
     static union {
       struct flags   modeflags;
       unsigned short mode;
     } openmode = { { 2,0,1,1,0,0,0,0 } };
     short          rc;         /* return code from DOS call */

 /*  Open the file */
     rc = DOSOPEN( (char far *)fname, (unsigned far *)fhandle,
                   (unsigned far *)&actiontaken,
                    fsize, fattrib, openflag,
                    openmode.mode, 0l);
     if ((rc != 0) || (actiontaken != 1)) {
       printf("error opening file %d \n", rc);
       exit(3);
     }
 }


 3. Swapping under OS/2 and Booting from a Floppy Disk

 Problem:

 My OS/2 application will not swap. The system is booted from a floppy
 in Drive A, and the application is executed from the hard drive. Since
 the application will not swap, it is limited by the amount of memory
 in the machine.

 Response:

 In this case, the problem is the result of not using the OS/2
 CONFIG.SYS command SWAPPATH. Since the swap path is not set, it
 defaults to the boot drive--the floppy drive. The floppy in Drive A
 has very little free space left, so no swap file can be created. To
 correct the problem, set SWAPPATH in CONFIG.SYS to the hard drive.


 4. Exiting a Thread with DOSEXIT

 Question:

 I have a program that prints a message using the C run-time printf()
 routine, then exits using DOSEXIT. None of my output appears on the
 screen. What is wrong?

 Response:

 OS/2 provides a standard method of exiting a thread, DOSEXIT. This
 call is defined in the include file DOSCALLS.H as follows:

    extern void far pascal DOSEXIT (
      unsigned,
      unsigned );

 The two parameters are as follows:

    ActionCode  -   0 -> only the current thread is terminated
                    1 -> all threads in the process are terminated

    ResultCode  -   Program's completion code (specifiable), to be
                    passed to any thread that issues a DOSCWAIT
                    for this process.

 When programming in C, it is possible that data written with printf()
 will be lost if you use DOSEXIT. This is due to the C run time's
 printf() routine buffering its output. DOSEXIT will kill the thread or
 process without flushing these buffers.

 While exit() is not as flexible as DOSEXIT, in that you cannot control
 the termination of other threads--exit() will always kill all threads
 in a process--it should always be used to terminate the main thread of
 a program. DOSEXIT can be used to terminate child threads, specifying
 0 in the first parameter.


 5. Data Available from KBDCHARIN

 Problem:

 I would like to see a program illustrating the data available from
 KBDCHARIN, the standard system call for getting keyboard input under
 OS/2.

 Response:

 The KBDCHARIN call fills the fields in a data structure whose address
 has been passed to it by the program. KBDCHARIN is defined in
 SUBCALLS.H as follows:

            extern unsigned far pascal KBDCHARIN (
                    struct KeyData far *,
                    unsigned,
                    unsigned );

 Fields are defined as the following:

 CharData    -  far address of structure to receive data

 IOWait      -  indicates if should wait when no character is
                   available -  0 = yes, 1 = no

 KbdHandle   -  reserved word of zeros

 The data structure for KeyData is also defined in SUBCALLS.H:

            struct KeyData {
                    unsigned char char_code;
                    unsigned char scan_code;
                    unsigned char status;
                    unsigned char nls_shift;
                    unsigned shift_state;
                    unsigned long time;
                    };

 These fields have the following meanings:

 char_code   -  ASCII character code derived from translation of the
                scan code received

 scan_code   -  code received from the keyboard identifying the key
                pressed. This may have been modified during the
                translation process.

 status      -  indicates the state of the character through bit
                fields--see manual for exact definitions

 nls_shift   -  reserved = 0

 shift_state -  defines state of the various shift keys including
                CTRL-, ALT-, NUM LOCK, etc.--see manual for exact
                definitions

 time        -  time stamp of the keystroke in milliseconds since
                IPL (system initialization). This field is not valid
                in real mode.

 This demonstration program makes calls to KBDCHARIN and displays the
 data passed to KeyData on the screen. Pressing the space bar
 terminates the demonstration. Compile with the -Lp option.

 Before we can use KBDCHARIN, we set the keyboard. This is done by
 making a call to KBDGETSTATUS, masking the status bits to the right
 state, and calling KBDSETSTATUS to set the mode. These calls, and the
 data structures used, are also in SUBCALLS.H.

            extern unsigned far pascal KBDGETSTATUS (
                    struct KbdStatus far *,
                    unsigned );

            extern unsigned far pascal KBDSETSTATUS (
                    struct KbdStatus far *,
                    unsigned );

 In each call, the first parameter is the far address of a keyboard
 status data structure, and the second is the keyboard handle, a
 reserved word of zeros. The data structure used is defined as the
 following:

            struct KbdStatus {
                    unsigned length;
                    unsigned bit_mask;
                    unsigned turn_around_char;
                    unsigned interim_char_flags;
                    unsigned shift_state;
                    };

 Field definitions are as follows:

 length             -  length in bytes of the data structure,
                       including this word

 bit_mask           -  full word bit mask representing functions to
                       be altered. For full definitions see manual;
                       we are interested in bit 3 to set ASCII mode.

 turn_around_char   -  defines the turnaround (carriage return)
                       character

 interim_char_flags -  see manual

 shift_state        -  similar to shift_state in KBDCHARIN

 #include <doscalls.h>
 #include <subcalls.h>

 main ()
     {
         struct  KeyData keydata;
         struct  KbdStatus kbdstatus;

         kbdstatus.length = sizeof( kbdstatus );
         KBDGETSTATUS( &kbdstatus, 0 );
         kbdstatus.bit_mask |= 4;       /* turn on bit 3 for binary mode */
         KBDSETSTATUS( &kbdstatus, 0 );

         do {
                 KBDCHARIN( &keydata, 0, 0 );

                 printf( "char: %02X  scan: %02X  status: %02X  ",
                         keydata.char_code,
                         keydata.scan_code,
                         keydata.status);

                 printf( "nls_shift: %02X  shift: %04X  ",
                         keydata.nls_shift,
                         keydata.shift_state);

                 printf( "time: %02d:%02d:%02d.%02d\r\n",
                         (int) (0xFF & keydata.time),
                         (int) (0xFF & (keydata.time >> 8)),
                         (int) (0xFF & (keydata.time >> 16)),
                         (int) (0xFF & (keydata.time >> 24)));

         } while( keydata.char_code != ' ' );

         exit(0);

     }


 6. OS/2 SDK: Family API Library

 Question:

 As I understand it, there is a Family API Library that allows you to
 write a MS-DOS application that runs under MS-DOS Versions 3.x and in
 protected mode under OS/2. Also, current Windows applications are not
 binary compatible with the OS/2 Presentation Manager (PM). Is it
 possible to write a Windows application that is binary compatible with
 Windows Version 2.00 and the OS/2 Presentation Manager, or will the
 ISV have to sell and maintain two sets of source code and binaries?

 Response:

 Windows Version 2.00 and the OS/2 Presentation Manager look identical;
 however, the API (application programming interface) for each is
 different. An ISV will have to sell and maintain two sets of binaries.

 The family API is much slower than the OS/2 API calling interface. We
 expect competitive pressure to lessen the importance of the family
 API.

 It is an IBM marketing decision whether to migrate the OS/2 API back
 to MS-DOS Versions 3.x. If that does happen, one would hope there will
 be source code compatibility and possible binary compatibility.


 7. OS/2 SDK Version 1.10 Final Release

 Microsoft will deliver final releases of OS/2 Version 1.00 and OS/2
 Version 1.10 along with the associated development tools. Software
 Development Kit (SDK) purchasers will receive the final release of the
 following products:

    Microsoft OS/2 Version 1.00
    Microsoft OS/2 Version 1.10

    Microsoft OS/2 Version 1.00 Programmer's Tool Kit
    Microsoft OS/2 Version 1.10 Programmer's Tool Kit

    Microsoft OS/2 Version 1.00 LAN Manager

    Microsoft C Compiler Version 5.10
    Microsoft Macro Assembler Version 5.10

    Microsoft Windows Version 2.00
    Microsoft Windows SDK Version 2.00

 After final releases of the products listed above have been delivered,
 you will not receive any further upgrades for these products. As of
 10/01/88, OS/2 SDK purchasers have received the final releases of the
 following products:

    Microsoft OS/2 Version 1.00
    Microsoft OS/2 Version 1.00 Programmer's Tool Kit

    Microsoft C Compiler Version 5.10
    Microsoft Macro Assembler Version 5.10

    Microsoft Windows Version 2.00
    Microsoft Windows SDK Version 2.00


 8. How to Tell if You Are in the Background

 Question:
    Is it necessary for an application running under OS/2 to determine
 whether it is running in the background?

 Response:
    Yes; it may be necessary. For instance, any KBD or VIO calls will
 not work from the background. If a program that waits for keyboard
 input is run in the background by using DETACH, it will continue to
 consume resources in the background while being inaccessible and
 invisible to the user.
    Also, a program may wish to know whether its input is coming from
 the console or from an input file. The following sample program
 illustrates a method for determining this information using the
 DOSQHANDTYPE call. This call reports whether a handle refers to a file
 or device, and if it is a device, if it returns the device's driver
 attribute word. Bit 0 of this word is set if the device is standard
 input and bit 1 is set for standard output. If we make this call
 within handle 0 and get back return values indicating a device, and
 these two bits in the attribute word are both set, then we can safely
 assume that we are running in the foreground and that the keyboard and
 screen are our standard input and output devices.
    DOSQHANDTYPE is defined in DOSCALLS.H as follows:

    extern unsigned far pascal DOSQHANDTYPE (
            unsigned,
            unsigned far *,
            unsigned far * );

    These fields are defined as follows:

    FileHandle  -  the file handle we are requesting information for
    HandType    -  far address where the handle type will be returned
                    0 -> file handle,  1 -> device handle
    FlagWord    -  far address where the device's attribute word will
                   be returned if HandType = 1

    Compile this program with the -Lp option and try running it under
 OS/2 with these variations:

    C> backgrnd
    C> detach backgrnd > backgrnd.out

    Note that in the second case we must direct our output to a file,
 since we cannot write to the screen when DETACHed.
    Only in the first case are we running in the foreground; the
 program allows us to detect this. This technique could be used at the
 entry point of a program to terminate execution if not in the
 foreground, disallowing the possibility of the program being DETACHed.

    #include <doscalls.h>

    main()
        {

        unsigned short     handtype;
        unsigned short     flagword;

        DOSQHANDTYPE( 0, (unsigned far *)&handtype,
                     (unsigned far*)&flagword );

        if( handtype == 0 )
            printf( "File system handle\n\n" );
        else if( handtype == 1 ) {
                printf( "Device handle\n\n" );
                if( flagword & 1 )
                    printf( "    Screen is standard output\n\n" );
                if( flagword & 2 )
                    printf( "    Keyboard is standard input\n\n" );
                }

        exit(0);

        }


 9. Clearing the Screen under OS/2

 Question:

 What is the recommended method for clearing the screen under OS/2?

 Response:

 The following program demonstrates the recommended method for clearing
 the screen. A "cell" (a 2-byte field containing a character and an
 attribute) is copied over the entire screen using VIOSCROLLUP with a
 special set of parameters. SUBCALLS.H must be included to use the
 VIOSCROLLUP call; it contains the following definition:

 extern unsigned far pascal VIOSCROLLUP (
                    unsigned,
                    unsigned,
                    unsigned,
                    unsigned,
                    unsigned,
                    char far *,
                    unsigned );

 The fields in VIOSCROLLUP are defined as follows:

 Field           Definition

 TopRow          Rop row of the area to scroll.

 LeftCol         Left-most column of the area to scroll.

 BotRow          Bottom row of the area to scroll.

 RightCol        Right-most column of the area to scroll.

 Lines           Number of blank lines to be inserted at the bottom
                 of the screen area being scrolled. If zero is
                 specified, no lines are scrolled.

 @Cell           Far address of the cell to be used as the fill
                 character in the new blank lines.

 VioHandle       A reserved word of zeros.

 Row and column numbers are zero based.

 If TopRow and LeftCol are specified as 0, and BotRow, RightCol, and
 Lines are all specified as -1, the entire screen will be filled with
 the character defined by Cell.

 This sample program also uses the call VIOSETCURPOS to set the cursor
 to the upper left-hand corner of the screen. This call is defined in
 SUBCALLS.H as the following:

 extern unsigned far pascal VIOSETCURPOS (
                    unsigned,
                    unsigned,
                    unsigned );

 Fields are defined as follows:

 Field           Definition

 Row             New cursor row position where 0 is top row.

 Col             New cursor column position where 0 is the left-most
                 column.

 VioHandle       A reserved word of zeros.

 #include <doscalls.h>
 #include <subcalls.h>

 main()
     {

         char buffer[2];            /* Local buffer for cell value.          *

         buffer[0] = 0x20;          /* Cell to replicate is a blank (space)  *
         buffer[1] = 0x07;          /* with normal attributes.               *

         VIOSCROLLUP( 0, 0, -1, -1, -1, (char far *)buffer, 0 );

                                    /* When the first 5 parameters are set   *
                                    /* as above, the entire screen is        *
                                    /* filled with the cell in buffer[].     *

         VIOSETCURPOS( 0, 0, 0 );
                                    /* Call to set the cursor to the upper   *
                                    /* left-hand corner of the screen, so    *
                                    /* we duplicate all the functionality    *
                                    /* of the DOS 3.xx "CLS" command.        *

         exit(0);

     }


 10. Equivalent DOS 3.x and Microsoft OS/2 Function Calls

 Question:

 Which DOS Version 3.x file I/O calls map to which Microsoft OS/2 file
 I/O calls?

 Response:

 Below is a list of DOS Version 3.x file-related function calls and
 their Microsoft OS/2 equivalent function calls. The following list
 does not represent a one to one correspondence, but rather a best
 approximation:

 DOS 3.x Calls (Under Int 21H)           Microsoft OS/2 Calls

     Disk Control
         0E (14)                         DOSSELECTDISK
         19 (25)                         DOSQCURDISK
         1C (28)                         DOSQFSINFO
         2E (46)                         DOSSETVERIFY
         36 (54)                         DOSQFSINFO
         54 (84)                         DOSQVERIFY

     File Operations
         23 (35)                         DOSQFILEINFO
         3C (60)                         DOSOPEN
         3D (61)                         DOSOPEN
         3E (62)                         DOSCLOSE
         41 (65)                         DOSDELETE
         43 (67)                         DOSQFILEMODE, DOSSETFILEMODE
         45 (69)                         DOSDUPHANDLE
         4E (78)                         DOSFINDFIRST
         4F (79)                         DOSFINDNEXT
         56 (86)                         DOSMOVE
         57 (87)                         DOSQFILEINFO, DOSSETFILEINFO
         5B (91)                         DOSOPEN

     Record Operations
         3F (63)                         DOSREAD
         40 (64)                         DOSWRITE
         42 (66)                         DOSCHGFILEPTR
         5C (92)                         DOSFILELOCKS

     Directory Operations
         39 (57)                         DOSMKDIR
         3A (58)                         DOSRMDIR
         3B (59)                         DOSCHDIR
         47 (47)                         DOSQCURDISK


 11. OS/2 SDK: Queue System

 Question:

 I'm interested in the multiple-in and multiple-out queue structure;
 can the current queue structure do multiple out? Also, what about
 priority queues? Is the queue system resident and used by OS/2, or is
 the queue system only brought in when an application needs it?

 Response:

 The queue package is used by the shell but is a swappable/discardable
 module; it doesn't have to be resident when it is not being executed.
 Queues support multiple writers but only one reader. An application
 developer can either structure the application using multiple queues
 or construct his or her own queues using shared memory and semaphores.


 12. OS/2 SDK: Dynamic Link Library Initialization Routine

 Question:

 I have a question regarding the dynamic link library (DLL)
 initialization routine mentioned in Gordon Letwin's book "Inside
 OS/2." Is this routine part of OS/2, or is it a user-defined or
 application-defined routine that will be automatically called by OS/2
 when the DLL is first loaded? The dynlink example that comes with the
 OS/2 Software Development Kit (SDK) has a DYNINIT.ASM module whose
 entry point is "initroutine," yet the main executable that calls the
 DLL never calls "initroutine." Would you please elaborate on what an
 "initroutine" is, or what it means in the context of DLLs and how you
 can implement such a routine if this facility exists?

 Response:

 The init routine in a DLL is an optional routine that is executed when
 the DLL is first accessed. Based on whether the init routine is
 specified to be INITGLOBAL or INITINSTANCE, the init routine will
 either be executed the first time that the DLL is accessed by any
 process, or the first time that the DLL is accessed by each process.
 The type can be specified in the DLL's .DEF file when it is linked.

 Adding an init routine can be done by declaring a far procedure in an
 assembler module, using the END MASM directive to specify that it is
 the entry point, and then linking it with your DLL. This is the same
 way that an assembly program specifies the entry point for a regular
 .EXE file. Note that a DLL typically does not have an entry point
 defined (and does not need one). It can be thought of as simply a body
 of code, brought into memory by the OS/2 loader, and with different
 entry points within it called from OS/2 processes.

 If you are used to programming in C and not MASM, you might not be
 used to the use of the END directive, but it is actually being done
 for you by the C start-up code. Although it is necessary to define an
 init routine for a DLL in assembler because the entry point must be
 defined, what is typically done is that the assembler init routine
 simply calls the real init routine, which can then be written in C, or
 another high-level language. An example of this is shown in the
 OS/2 Version 1.00 Programmer's Toolkit sample program "DYNLINK." At
 the end of the module DYNINIT.ASM, you will see the following:

    END    START

 This defines the entry point to be the START procedure defined just
 above it in the .ASM file.


 13. Monitors

 Question:
    I was wondering if monitors are intended to solve some
 of the problems of putting existing memory resident
 functions into OS/2. It seems similar to the progression of
 DOS in general, in that the enhancements are very useful
 in fixing many previous problems but perhaps not as good at
 solving current or upcoming ones. The terminate-and-stay
 resident function seems to be one such case. You could fool
 DOS into doing this and even installing device
 drivers after boot time, but this is not really allowed. I
 think that the monitor approach, using specialized and
 restricted modes, could cause you the same set of problems
 in the future. It will still be possible to crash the
 system or really mess things up if you aren't careful.

 Response:
    Monitors are intended to provide a general means of
 peeking and modifying the data stream in a character device
 driver, primarily the keyboard. They are not intended to
 provide "terminate and stay resident"--the ExecPgm system
 call is what you use to do that. I think monitors nicely
 solve the problem of multiple packages trying to manage the
 device and hardware interrupts at too low a level in the
 current DOS. They do not solve the problem of two
 programs both needing to be the first to see the F1 key.
 That is a problem I don't think the DOS can solve.
 Application writers need to make their programs
 configurable so end users can avoid conflicts for function
 keys.
    You are right that monitors are a means to mess up the
 system somewhat. You could write a monitor application that
 takes all keys in all screen groups, and does nothing with
 them. I don't know of any way to solve this problem
 without reducing the functionality. This problem is not
 specific to our design of monitors.


 14. Exit List Functions

 Problem:
    The abort function list is set up for a list of
 functions to be called with no arguments. I would like to
 see each function associated with at least a far pointer,
 if not an additional short and long integer. I assume that
 removal of open files is done another way, but it could be
 done with a common function and an entry in the list with a
 file handle as a parameter. It is also a way that a process
 list could be terminated as necessary. This function is
 actually more generic and may be brought out like the file
 name parsing was for the old FCBs.

 Response:
    We agree your suggestion is more general--it is also
 something that the application can simulate by storing the
 required arguments in some data segment for use in the exit
 lists. In general, a given package will only need one
 exit list. The multiple exit list facility is intended for
 the case where an application attaches to black box dynlink
 libraries that need their own exit routines. But within a
 given program or dynlink library, the recommended structure
 is to have one exit handler that does several things,
 rather than register a separate exit handler for every
 piece of cleanup needed.


 15. Least Recently Used (LRU) Algorithm

 Question:
    How is the LRU (least recently used) algorithm used in
 swapping segments?

 Response:
    The kernel examines the LDT/GDT during each time slice,
 at which time the access bit in each segment is examined.
 The access bit indicates whether that segment has been
 accessed during that particular time slice. If it has
 been accessed, the segment is moved to the top of a queue
 in the memory manager; then, the access bit is cleared.
 Segments are discarded and swapped from the bottom of the
 queue, and the result is an LRU scheme.


 16. Systems Services and Dynamic Linking

 OS/2
 ISVONLY |

 Question:
    This question is really addressing how things can be
 made into resources that can be made available to
 applications other than the dynamic linking facility. This
 would be more along the lines of the Windows DDE protocol.
 For example, dynamic linking does not necessarily address
 access to a resident process that may want its services to
 be used by a number of applications where the resident
 process needs to know who it is talking to. It may also
 adjust its services based upon the requests being made upon
 it. This implies a method of finding the resource and
 communicating with it. The dynamic link feature may supply
 all this in a fashion.

 Response:
    There are really two issues here. One is how an
 application can find out about available system services
 from other processes. We don't have any specific function
 for that in OS/2, although you could easily come up with
 some convention based around shared memory. I think this is
 more an issue for an environment manager such as Windows.
    The second issue is how a dynamic link library knows who
 it is talking to and tracks clients. Again, I think this is
 more a convention for the library to specify than the OS/2.
 It was not a goal of OS/2 to provide loads of high
 level abstractions and conflict with Windows. OS/2 was
 designed as a base for Windows-like packages. It does not
 pretend to have all the high level services that Windows
 has.


 17. Running Windows in 3.x Box

 OS/2
 ISVONLY |

 Problem:
    I can't get Windows 1.x to run in real mode. It tries very hard to run, bu
 it just can't make it.

 Response:
    It won't work. Windows has a very close relationship with the internals
 of the DOS 2/3 kernel, and relies on things that just aren't there in the OS/
 real mode box. This applies only to the currently released version of Windows


 18. Is the System Crash Proof?

 OS/2
 ISVONLY |

 Question:
    Is this a crash-proof operating system?

 Response:
    No, it is not crash-proof until we get to the 386. On the 286, we have the
 real mode box unprotected, and we have protected mode applications with I/O
 privilege. The 386 lets us put the real mode box in virtual mode, and restric
 the ports I/O priv applications can touch. Also, the FAT file system lacks
 protection.
    The system is a lot less likely to crash from a bad application, or two
 applications colliding over something, but it is not 100 percent crash-proof.


 19. Error in MORE Utility

 Problem:

 The MORE utility has a minor error when executed from an OS/2 ".CMD"
 file: it displays a zero before the "<". (It still works correctly.)

 The following is an example (from a .BAT or .CMD file with echoing
 on):

    MORE <AUTOEXEC.BAT   - is displayed when in DOS

    MORE  0<AUTOEXEC.BAT - is displayed when in OS/2

 Response:

 This behavior is a feature of CMD.EXE. CMD.EXE echoes the complete
 redirection specifications when it parses the command string from a
 batch file.


 20. Redirecting INT 0 Using DosSetVec

 Question:
    I have been trying to write an exception handler for OS/2
 protect mode. The exception is trap 0, the "divide by 0"
 condition. I use DosSetVec to point OS/2 to my handler. If I then
 execute an actual divide by 0 operation, my handler gets called
 correctly. But if I try to code an INT 0 to simulate the same
 condition, I get a GP fault. What is wrong?

 Response:
    By design, an INT 0 can only be issued from ring 0 code. An attempt
 to issue it from user code will result in a GP fault. In general, OS/2
 will not allow software interrupts in protect mode applications.


 21. Interim Character Flag in KbdCharIn Call

 Question:
    Function KbdCharIn mentions an interim flag without explaining its
 meaning or purpose. I also have looked at the device driver manual,
 Page 187. It also only mentions the term. Could you please explain the
 purpose and meaning of the keyboard interim flag?

 Response:
    The interim character flag is used mainly to support double byte
 character sets where the current key's meaning depends on what key
 follows it. The interim character flag is then set so that you will
 know that the character has not been determined yet and you should
 wait for the following key before determining what to do.


 22. Memory Allocation Limits under OS/2

 Problem:

 While experimenting with virtual-memory management, we encountered
 the following problem:

 A program using DOSALLOCSEG to allocate 1K segments only allocated
 about 2000 nonsharable segments and then returned error# 8 (not
 enough memory). We have 5 megabytes of memory in the machine and 20
 megabytes free on the swap Drive C. The following is our CONFIG.SYS:

    protshell=shell cmd.exe
    shell=a:\command.com
    rmsize=640
    buffers=32
    memman=swap,move
    swappath=c:\tmp

 Response:

 The problem is not with the amount of memory in the machine or free
 space left on the swap drive. The limitation you have encountered is
 the number of descriptors available in the local descriptor table for
 nonsharable segments. Therefore, the way to allocate more nonsharable
 memory for the task is to increase the segment size. The size of the
 segment should be chosen to minimize the amount of swapping that may
 occur.

 If the application deals with several small data objects, but only a
 few at any given time, then small segments would reduce the amount of
 memory and the amount of disk I/O when swapping occurs. In the case of
 large data objects, segments at least the size of the data object will
 probably work best. Also, note that segments are swapped in their
 entirety; no partial swapping of segments is performed, and each
 segment allocated is a small amount of additional overhead for the
 system to manage.


 23. Restoring Video Attributes

 Question:
    Returning to a real mode program using EGA graphics
 gives me a white screen. If the display can't be restored,
 can you prohibit switching out?

 Response:
    The reason we can't restore it is due to the write-only
 registers. We can't prohibit switching out; there are
 things such as pop-up screens for hard errors, and the
 shell, which we cannot reasonably delay. There will be a
 documented interface for real mode applications to notify
 the operating system of mode changes. This does not,
 however, help existing applications, except Chart and Word,
 which already use this interface under DOS 2/3.


 24. Dynamic Loading of Device Drivers

 Question:
    Why isn't there dynamic loading and unloading of device
 drivers, or at least the loading of them?

 Response:
    One reason you can't dynamically load device drivers is
 that the interrupt part of a device driver has to reside in
 low memory so we can get at it if the interrupt happens to
 occur while the CPU is in real mode (mode switching per
 interrupt is too slow). Low memory is not dynamically
 allocatable--there is not much of it, and it is probably
 all assigned to the real mode box.


 25. Mode Switching on an EGA under OS/2

 Question:

 Would you demonstrate how to switch EGA between 25- and 43-line modes?

 Response:

 SETEGA accepts one parameter, which must be either "25" or "43." Too
 few or too many parameters, or a parameter other than the two
 specified above, will result in an error message and termination with
 no action taken.

 This program will work only on machines equipped with a standard EGA.
 SETEGA functions as follows:

 1. Checks parameters

 2. Clears the screen using the VIOSCROLLUP function

 3. Gets current mode information using VIOGETMODE, as follows:

    extern unsigned far pascal VIOGETMODE (
    struct ModeData far *,
    unsigned );

 This call fills a data structure of the following type, whose address
 we pass in the first parameter (the second parameter is the VIO
 handle, a reserved word of zeros):

    struct ModeData {
    unsigned length;
    unsigned char type;
    unsigned char color;
    unsigned col;
    unsigned row;
    unsigned hres;
    unsigned vres;
    };

 We leave all these fields as they are except "row," the number of
 alphanumeric rows for this mode. This is changed to the value
 specified in our parameter.

 VIOSETMODE is now used to set the mode, as follows:

    extern unsigned far pascal VIOSETMODE (
    struct ModeData far *,
    unsigned );

 This call has the same parameters as VIOGETMODE. We are now set to the
 desired mode. We then set the cursor to an appropriate size and shape.
 This is done by filling in a structure of the following type:

    struct CursorData {
    unsigned cur_start;
    unsigned cur_end;
    unsigned cur_width;
    unsigned cur_attribute;
    };

 Then VIOSETCURTYPE is called, where the second parameter is again the
 VIO handle:

    extern unsigned far pascal VIOSETCURTYPE (
    struct CursorData far *,
    unsigned );

 Last, we set the cursor to the upper left-hand corner of the screen
 using VIOSETCURPOS. Compile using the -Lp option; the following
 program may be bound for use under real mode:

 #include <subcalls.h>
 #include <doscalls.h>
 #include <stdio.h>

 void usage();

 void main( argc, argv )
 int  argc;
 char *argv[];
 {

     struct  ModeData    modedata;

     struct  CursorData  cursordata;

     static char  buffer[2] = { 0x20, 0x07 };   /* scrolling fill character */
                                                /* for clearing the screen  */
     if( argc != 2 )
         usage(argv[0]);

     switch(atoi(argv[1])) {
         case 43:
             VIOSCROLLUP( 0, 0, -1, -1, -1, (char far *)buffer, 0 );
             modedata.length = sizeof( modedata );
             VIOGETMODE( &modedata, 0 );
             modedata.row = 43;
             VIOSETMODE( &modedata, 0 );
             cursordata.cur_start = 7;
             cursordata.cur_end = 7;
             cursordata.cur_width = 1;
             cursordata.cur_attribute = 0;
             VIOSETCURTYPE( &cursordata, 0 );
             VIOSETCURPOS( 0, 0, 0 );
         break;

         case 25:
             VIOSCROLLUP( 0, 0, -1, -1, -1, (char far *)buffer, 0 );
             modedata.length = sizeof( modedata );
             VIOGETMODE( &modedata, 0 );
             modedata.row = 25;
             VIOSETMODE( &modedata, 0 );
             cursordata.cur_start = 12;
             cursordata.cur_end = 13;
             cursordata.cur_width = 1;
             cursordata.cur_attribute = 0;
             VIOSETCURTYPE( &cursordata, 0 );
             VIOSETCURPOS( 0, 0, 0 );
         break;

         default:
             usage(argv[0]);
         }
         exit(0);
 }

 void
 usage(p)
 char *p;
 {
     printf( "usage: %s 25|43\n", p);
     exit(1);
 }


 26. Thread Creation and Scheduling Demonstration

 Question:

 Would you give an OS/2 thread creation and scheduling demonstration?

 Response:

 THREADS.C creates 23 child threads and counts loops within each thread
 until you stop the program or until one of the threads has counted
 10,000 loops.

 The program below provides an example of creating threads under OS/2
 as well as demonstrating the "fairness" of the OS/2 scheduler.

 Each thread contains a DOSSLEEP() call in its counting loop. This will
 cause the thread to give up its time slice, so that at most one loop
 will be counted each time the thread is scheduled. Tests indicate that
 without DOSSLEEP(), the counting loop would be executed about 200 to
 300 times for each time the thread was scheduled. Thus it is safe to
 assume that each time a thread is scheduled, it is adding exactly one
 to its count. A sleep period of 0 is used, allowing each thread to be
 rescheduled immediately; increasing the value of SLEEPTIME tends to
 even out scheduling.

 Each child thread is passed an ID number when it is created. In this
 example, an arbitrary sequential index is used for convenience. We
 discard the threadID returned by OS/2 when the thread is created, as
 it is not needed in this program. The threadID could be saved and used
 for purposes such as changing the thread's priority or temporarily
 suspending its execution; because threadID numbers are issued
 sequentially, they could be used as an index into an array containing
 information about the threads.

 A global flag ("Ready") is used to block entry to the counting loops
 of the child threads until all threads have been created. This
 prevents the threads created first from getting a "head start."

 Note that VIO calls are used for all output except when aborting with
 an error condition. This avoids reentrancy problems, since the VIO
 calls are internally semaphored. The C run-time itoa() function is
 reentrant under Microsoft C Version 5.00.

 Compile THREADS.C with cl -G2 -Lp -Gs threads.c. -G2 enables the 80286
 instruction set. -Lp tells the linker to use protected-mode libraries.
 -Gs disables C stack checking; this switch must be used when compiling
 programs that create threads. The program is as follows:

  #include <malloc.h>
  #include <stdio.h>
  #include <dos.h>
  #include <doscalls.h>
  #include <subcalls.h>

  #define  STACKSIZE   128

  #define  THREADS     23

  #define  SLEEPTIME   0L

  #define  MAXCOUNT    10000

  unsigned short   ID;           /* global for passing ID number to threads */

  unsigned short   Ready = 0; /* global to signal threads to start counting */

  main()
  {

     void far   thread();                          /* child thread function */

     char far   *threadstack;           /* pointer to stack area for thread */

     unsigned short   threadID;    /* thread ID returned by DOSCREATETHREAD */

     unsigned short   rc;               /* return code from DOSCREATETHREAD */

     unsigned short   count = 0;            /* count of times loop executed */

     unsigned char    buffer[6];        /* general purpose character buffer */

     unsigned short   i;               /* general purpose indexing variable */

 Clear the screen and position cursor out of the way, as follows:

    buffer[0] = 0x20;                                     /* 0x20 = blank  */
    buffer[1] = 0x07;                                     /* 0x07 = normal */
    VIOSCROLLUP( 0, 0, -1, -1, -1, buffer, 0 );
    VIOSETCURPOS( 17, 0, 0 );

 Print banner and count header for main thread, as follows:

    VIOWRTCHARSTR( (char far *)"THREADS DEMO", 12, 1, 8, 0 );
    VIOWRTCHARSTR( (char far *)"Press Ctrl-C to stop", 20, 4, 8, 0 );
    VIOWRTCHARSTR( (char far *)"main()     ", 11, 0, 51, 0 );

 Start each of our threads. For each thread we do the following:

 1. Allocate space for a stack.

 2. Check to see if this allocation worked. If yes, continue. If no,
    print message and exit.

 3. Move the stack pointer to the top of the stack, since stacks grow
    down.

 4. Start the thread. The threadID that is returned is not used in this
    example.

 5. Check to see if thread create succeeded. If yes, continue. If no,
    print message and exit.

 6. Pass the new thread a sequential (arbitrary) ID number in global
    storage and block until the thread has picked it up, as signaled
    by the ID number being set back to 0.

     for( i = 1; i <= THREADS; i++ ) {

         threadstack = malloc(STACKSIZE);

         if( threadstack == 0 ) {
             printf( "Thread %d stack malloc error\n", i );
             DOSEXIT(1,1);
         }

         threadstack += STACKSIZE;

         rc = DOSCREATETHREAD( thread,
                               (unsigned far *)&threadID, threadstack );

         if( rc != 0 ) {
             printf( "create of thread %d failed, error: %d\n", i, rc );
             DOSEXIT(1,1);
         }

         ID = i;
         while( ID ) DOSSLEEP( 0L );    /* give up time slice while waiting */

     }

 When all of our threads have been started, signal them all to begin
 counting at the same time by setting the Ready flag as follows:

    Ready = 1;

 Enter counting loop; identical to the counting loop in each thread.
 Each time we are scheduled, we do the following:

 1. Increment our count.

 2. Check to see if count has reached 10,000. If yes, terminate all
    threads. If no, continue.

 3. Zero out our buffer.

 4. Use C run-time itoa() function to convert our count to an ASCII
    value.

 5. Print the count with VIOWRTCHARSTR().

 6. Give up our time slice.

     while( 1 ) {

         count++;

         if( count > MAXCOUNT )
             DOSEXIT( 1, 0 );

          for( i = 0; i < 6; buffer[i] = 0, i++ );
          itoa( count, buffer, 10 );
          VIOWRTCHARSTR( buffer, 5, 0, 63, 0 );

         DOSSLEEP( SLEEPTIME );
     }

  }

  /*** Child thread function ************************************************/

  void far thread()
  {

     unsigned short  threadnumber;          /* ID number passed from main() */

     unsigned short  count = 0;             /* count of times loop executed */

     unsigned char   buffer[6];         /* general purpose character buffer */

     unsigned short  i;                /* general purpose indexing variable */

 The child thread's first task upon waking up is to get its
 threadnumber. The ID is then set back to 0, signaling main() to start
 the next thread, as follows:

    threadnumber = ID;
    ID = 0;

 Next, print a count header for this thread, as follows:

    VIOWRTCHARSTR( (char far *)"thread  ", 8, threadnumber, 51, 0 );
    for( i = 0; i < 6; buffer[i] = 0, i++ );
    itoa( threadnumber, buffer, 10 );
    VIOWRTCHARSTR( buffer, 5, threadnumber, 59, 0 );

 Now we wait, giving up our time slice, until the Ready flag is set,
 as follows:

    while( !Ready ) DOSSLEEP( 0L );

 Enter counting loop; identical to counting loop in main(), as follows:

     while( 1 ) {

         count++;

         if( count > MAXCOUNT )
             DOSEXIT( 1, 0 );

         for( i = 0; i < 5; buffer[i] = 0, i++ );
         itoa( count, buffer, 10 );
         VIOWRTCHARSTR( buffer, 5, threadnumber, 63, 0 );

         DOSSLEEP( SLEEPTIME );
     }

  }


 27. Passing Pipes

 Question:
    Can pipes be passed to anyone besides local threads or child processes?

 Response:
    No. You need to be able to attach to the file handle. This limits it to th
 local process or any child process that can inherit a handle from the parent.


 28. Performance with Swapping Is Slow under OS/2

 Problem:

 I left BUFFERS=50 in CONFIG.SYS (as it was on the disks). The only
 problem I have had with OS/2's performance is when I halloced a
 3-megabyte huge pointer and read a 3-megabyte file into it. (I only
 have 1 megabyte of extended memory.) This didn't work at all until I
 put a SWAPPATH in CONFIG.SYS to point to a a second hard disk that had
 enough room for this data. My first hard disk did not have enough free
 space, and the program seemed to hang or run very slow.

 Response:

 Swapping isn't fast. It is important to set SWAPPATH to a drive that
 has enough free space to run your application. For example, booting
 from a floppy disk and not setting the SWAPPATH will default it to the
 floppy disk (the boot drive) which will be very slow and may quickly
 run out of disk space.


 29. Nine Open File Handles

 Question:
    I find nine open file handles on program entry. I know
 about the first five. What are the others?

 Response:
    There is no AUX in protected mode, so you actually
 probably only know about four. The others are used by
 various dynlink libraries you are attached to, probably by
 virtue of having stdin/stdout open. VIO, for example, uses
 at least one handle.


 30. Getting Device Driver's Buffer Size

 Question:

 How do I get a device driver's internal buffer size using DOSMONREG?

 Response:

 DOSMONREG requires that an input and output buffer be registered for
 each instance of a device monitor. These buffers are to be sized 20
 bytes larger than the device driver's internal buffer size.

 By making a call to DOSMONREG that fails, the second word of the input
 and output buffers will contain the device driver's buffer size, in
 bytes. The following program calls DOSMONREG with input and output
 buffer sizes specified to be zero. This call to DOSMONREG fails, and
 returns the device driver's buffer size in the second word of the
 input and output buffers. The example program then makes a second
 successful call to DOSMONREG, thus registering the input and output
 buffers.

 MONREG.C is an example of using DOSMONREG to get a device driver's
 buffer size.

 Compile using the following command:

    cl -c monreg.c

 Link using the following command:

    link4 monreg,monreg,,doscalls+slibc286;

 #include <doscalls.h>
 #include <stdio.h>
 #include <malloc.h>

 #define  FRONT       1      /* front of the monitor chain */
 #define  CUR_SG     -1      /* current screen group */

 #define  OVER       20      /* monitor overhead */

 typedef struct monitor_buffer {
     unsigned mon_buff_len;          /* monitor buffer length */
     unsigned dd_buff_len;           /* device driver length */
 } MonitorBuffer;

 void main()
 {
     /*
      *  allocate buffer space to make the first DOSMONREG call
      */
     MonitorBuffer  *in = (MonitorBuffer *)malloc(sizeof(MonitorBuffer));
     MonitorBuffer  *out = (MonitorBuffer *)malloc(sizeof(MonitorBuffer));

     unsigned int handle;         /* monitor handle */
     int result;                  /* return values from system calls */
     int size;                    /* device driver buffer size */

     /*
      *  open a keyboard monitor
      */
     result = DOSMONOPEN("KBD$",(unsigned far *)&handle);

    /*
     *  Set the monitor buffer size to zero so the DOSMONREG call will fail.
     */
     in->mon_buff_len = 0 ;
     out->mon_buff_len = 0 ;

     result = DOSMONREG(handle,                /* monitor handle */
                       (char far *) in,        /* address of input buffer */
                       (char far *) out,       /* address of output buffer */
                       (unsigned int) FRONT,   /* front of monitor list */
                       (unsigned int) CUR_SG); /* calling screen group */

     /*
      *  The device driver buffer size is returned in the second word
      *  of the input and output buffers.
      */
     size = in->dd_buff_len;  /* save the device driver buffer size */

     printf("DOSMONREG returns:\t\t%d\t(8 == not enough memory)\n", result);
     printf("Device driver buffer size:\t%d\t(bytes)\n", size);

     /*
      *  Allocate the minimum correct amount of buffer space for
      *  the input and output buffers.
      */
     in = (MonitorBuffer *)realloc(in, size + OVER);
     out = (MonitorBuffer *)realloc(out, size + OVER);

     in->mon_buff_len = size + OVER;
     out->mon_buff_len = size + OVER;

     result = DOSMONREG(handle,            /* monitor handle */
                       (char far *) in,    /* address of input buffer */
                       (char far *) out,   /* address of output buffer */
                       (unsigned int) 1,   /* front of monitor list */
                       (unsigned int) -1); /* calling screen group */

     printf("\nDOSMONREG returns:\t\t%d\t(0 == O.K.)\n", result);
 }


 31. Good FORMATS.TBL File on the Program Disk

 Question:

 Why is there a FORMATS.TBL file on both the Supplemental disk and the
 Program disk?

 Response:

 The FORMATS.TBL file on the Supplemental disk is bad and shouldn't be
 used. FORMATS.TBL on the Program disk is the correct one.


 32. KbdGetStatus() NUMLOCK Problem in VIO Window

 Microsoft has confirmed that KbdGetStatus() does not correctly report
 the shift status when run in a VIO window in the Version 1.06 OS/2 SDK
 (Software Development Kit). Examples of this problem are the status of
 the NUM LOCK, SCROLL LOCK, and CAPS LOCK lights.

 Microsoft is researching this problem and will post new information as
 it becomes available.



 33. Calculating the OS/2 Huge Shift Count

 This article describes how to calculate the OS/2 huge shift count.

 The OS/2 API DosGetHugeShift() will return the value that must be
 added to the first selector that is returned from DosAllocHuge(). By
 adding this value to the second and subsequent "huge" selectors
 returned by DosAllocHuge(), you can obtain addressability to them.

 For example, if DosGetHugeShift() returns a value of 8, and if the
 selector value returned by DosAllocHuge() is 120, then the second
 selector will be 128 (first_selector + huge_shift = 120 + 8 = 128).
 The third selector will be 136, the fourth will be 144, etc. The
 shift count is operating-system specific, and may change from one
 release of OS/2 to another. In addition, the shift count will be
 different when used in a bound application, which uses huge segments
 when it is run under MS-DOS.

 On Page 606 of Volume 1 of the "Microsoft Operating System/2
 Programmer's Reference" for Version 1.10, the following reference is
 made to two constants named DOSHUGEINC and DOSHUGESHIFT:

    If you write MS OS/2 programs in assembly language, the global
    symbols DOSHUGESHIFT and DOSHUGEINC are available for computing
    huge memory addresses. DOSHUGESHIFT is equal to the shift count
    retrieved by DosGetHugeShift, and DOSHUGEINCR is equal to the
    selector offset.

 These two values are contained in OS2.LIB and DOSCALLS.LIB. The
 problem is that by either explicitly linking or dynamically linking
 via DosGetProcAddr(), once you obtain the far pointers to these two
 values, the application doesn't have a valid selector to those values.
 This causes general protection faults when you attempt to obtain the
 values of these symbols.

 In addition to the DosGetHugeShift() API, there is another way to
 obtain this information. The DosGetInfoSeg() API can be used to obtain
 this current huge shift count, since it is stored in the cHugeShift
 field of the GINFOSEG (global information segment) structure. However,
 please note that DosGetHugeShift() is a family API function, whereas
 DosGetInfoSeg() is a protected-mode only API, so that if you are
 writing a family API that requires the huge shift count, you should
 use DosGetHugeShift() rather than DosGetInfoSeg().

 Most applications don't need to obtain this low-level information and
 can instead leave this work to the high-level-language compiler that
 the application is being developed with.

 When using the Microsoft C Compiler Version 5.10 or later, if you use
 the "huge" keyword (or default to the huge memory model with /AH), the
 huge segment calculations are added to your code in a way that is
 transparent to the application programmer. If the "huge" keyword is
 not used, you need to explicitly get the huge shift value and
 calculate all the other selector values for all but the first
 selector, which is done for you by DosAllocHuge(). Please refer to the
 Microsoft C Compiler documentation for more details.

 Related to this article is the sample application HUGE.C. This example
 will use the C huge keyword if you #define the macro
 C_HUGE_KEYWORD_ENABLED. If the macro is not #defined, it will manually
 calculate the huge jumps. The files included are as follows:

    Binary version - HUGE.EXE
    C source file  - HUGE.C
    Make file      - MAKEFILE

 The file HUGE can be found in the Software/Data Library by searching
 for the keyword HUGE, the Q number of this article, or S12405. HUGE
 was archived using the PKware file-compression utility.


 34. OS/2 SDK: Device Driver for IBM Mouse on the PS/2

 Question:

 Where can I obtain a functional mouse driver for the IBM PS/2 Model
 80?

 Response:

 Support for a mouse in the mouse port of the IBM PS/2 was added in the
 OS/2 Software Development Kit (SDK) Version 1.06. In all previous
 versions of the OS/2 SDK, the only mouse you could use on an IBM PS/2
 with OS/2 was a Microsoft (or compatible) Mouse in the serial port.


 35. Garbage Is Printed when Initializing Non-IBM Printer

 Problem:
    When I initialize the printer using DosDevIOCTL category 5,
 function 0x46, and have the spooler installed, garbage is printed on
 my non-IBM printer.
    I discovered that my problem occurs because after I open a parallel
 port, I call DosDevIOCTL to initialize the printer (category 5,
 function 0x46). It appears that when a port is not spooled, this call
 has no effect; when the port is spooled, 40 bytes of initialization
 data are put into the spool file (and then sent to the
 printer)--presumably by spool. The data are escape sequences
 appropriate to the IBM Graphics printer, and do things such as set the
 form length, character pitch, etc.

 Response:
    It is not necessary for you to call that IOCTL (5,0x46) to
 initialize the printer. You can initialize the printer on your own in
 any way that you wish and it should not cause problems.
    Microsoft is researching this problem and will post new information
 when available.


 36. Machines OS/2 Runs On

 Currently, Microsoft's Operating System/2 Software Development Kit
 (SDK) kernel will run on the following personal computers:

    IBM PC-AT
    Compaq Deskpro 286
    Compaq Deskpro 386
    Compaq Portable III
    Compaq Portable 286
    Zenith Z-241 (ROM Version 1.9 or later)
    Zenith Z-248 (ROM Version 1.9 or later)
    Zenith Z-386

 Note: Many of the OS/2 SDK Development Tools will also run under
 MS-DOS Versions 3.x.


 37. KbdCharIn(NoWait) Blocks Even if Not the Foreground Process

 Question:

 If a program is sitting in a while(1) loop polling keyboard and mouse
 with the following

    KBDCHARIN(NO_WAIT)
    MOUREADEVENTQUE(NO_WAIT);

 and is switched out of the foreground session, is it still getting
 time-slices, or is it blocked until it gets back the keyboard-mouse
 focus?

 Response:

 The process still gets CPU time when it is doing KbdCharin or
 MouReadEventQueue calls, even though it is not the foreground process.


 38. DIAL Will Not Run in the Compatibility Box

 Problem:
    DIAL works correctly on my system in PC-DOS Version 3.10, but hangs
 on entry when I run it in the compatibility box.
    The problem occurs before the first screen comes up, so it probably
 has nothing to do with the modem.

 Response:
    If you have installed the COM01.SYS driver, run SETCOM40 with an
 argument of COMx=ON, where x represents which com port to set.
    If you have not installed the driver, this process will not be
 necessary.


 39. Interrupt 24H Issued in Compatibility Mode

 Question:

 Will Interrupt 24H (Critical Error Handler Address) ever be issued by
 OS/2 in compatibility mode?  Also, can protected mode applications
 trap hard errors?

 Response:

 Yes, OS/2 will issue Interrupt 24Hs when appropriate in the
 compatibility mode. In answer to your second question, there is only
 one hard error daemon, which handles errors for all processes in the
 system and is not replaceable. There is no way to substitute your own
 error handler, as was possible under MS-DOS Versions 3.x.

 You can use the DosError() call to allow your process to receive
 hard-error notification without generating a hard error signal. In
 this case, all hard errors generated by OS/2 system calls under your
 process will be FAILed and the appropriate error code returned. Note
 that DosError() works on a per-process basis; suspending system
 handling of hard errors for your process will not affect error
 handling for other processes.

 However, even if you use DosError() to turn hard errors into error
 codes, there is still a class of error that you will not see: fatal
 errors not associated with a system call, such as memory faults. This
 class of error will still cause a hard error pop-up and the only
 "option" is to terminate the program. There is no way to return an
 error code to the application because there is no system call
 associated with a typical memory fault.


 40. DevHelp_MonWrite Call Returns Before Monitor Chain Completes

 Question:

 Why does the DevHelp_MonWrite call return before the monitor chain
 completes, even when the wait flag is set?

 Response:

 The DevHelp_MonWrite call returns as soon as the data is placed in the
 first buffer of the monitor chain. To be able to access the data after
 it goes through the monitor chain, the device driver thread must block
 itself until it is restarted in the notify routine.

 If the device driver chain happens to be empty when DevHelp_MonWrite
 is called, then when the call returns the notify routine will already
 have been called, and if you block waiting for it to return you will
 not get restarted. To avoid this problem you need to check the status
 of the request packet before DevHelp_Block is called.

 To block the process after calling DevHelp_MonWrite, use the
 DevHelp_Block call. When this call returns, you need to check whether
 the device driver was restarted by a spurious DevHelp_Run or an
 interrupt. This can be done by setting the status of the request
 packet to a constant in the notify routine and by checking the status
 after the device driver is restarted. If the status is not correct,
 the driver should stay blocked until it is restarted with the proper
 status.

 To restart the device driver at the end of the notify routine, you
 need to set the status word to some constant and then call
 DevHelp_Run.


 41. OS/2 SDK: New EXE File Header ne_flags Information

 Question:

 What are the characteristics of an EXE module? In theory, I can look
 at the structure "new_exe" (the new EXE header) and examine the field
 "ne_flags". The following bits should be defined:

 #define NENOTWINCOMPAT 0x0100 /* Not compatible with PM windowing */
 #define NEWINCOMPAT    0x0200 /* Compatible with PM windowing     */
 #define NEWINAPI       0x0300 /* Uses PM windowing API            */

 This information seems to be inconsistent. In the programs that I
 generate, the field is never set. Why is this happening?

 Response:

 By default, this field is not set. The current version of OS/2 will
 start these types of executables up in a full screen group, treating
 them like full-screen-only applications. There are a couple of
 different methods you can use to set this field. You can either use
 the MARKEXE utility to set this field after the program has been
 linked, or you can specify to the linker explicitly what type of
 program it is. This is done by using a .DEF file. The first line in
 the .DEF file should be the following:

    NAME   myapp   WINDOWCOMPAT

 "NAME" is a .DEF file keyword for naming the module; "myapp" is the
 module name, usually the base part of the executable's filename; and
 "WINDOWCOMPAT" means that the program can be compatibly run in a VIO
 window. Other values for this field are "WINDOWAPI" and
 "NOTWINDOWCOMPAT".


 42. OS/2 Will Not Boot with a Paradise VGA Card Installed

 Problem:

 I am trying to bring up Version 1.05 of the OS/2 SDK on my computer,
 which has a Paradise VGA graphics card installed in it. While the
 system is booting, I receive the following error message:

 Trap 0D

 AX=AA55 BX=0000 CX=0000 DX=0003 BP=0C42
 SI=6800 DI=0040 DS=0107 ES=0537 FLG=2246
 CS=0417 IP=4361 SS=0067 SP=0C14 MSW=FFFB
 CSLIM=4400 SSLIM=001F DSLIM=FFFF ESLIM=01BF
 CSACC=  FB SSACC=  F3 DSACC=  FB ESACC=F3
 ERRCD=0000 ERLIM=**** ERACC=  **

 Response:

 The above problem is known to occur with a particular Paradise VGA
 graphics card or an Everex EV-659A EGA card. The Install disk
 generates a trap 0D error, and the CS value returned after the trap 0D
 error typically equals 0417. There is an updated version of
 BVSCALLS.DLL that corrects this problem. You can download the
 corrected version of BVSCALLS.DLL from the Software Library. This file
 can be found in the Software Library by searching on the filename
 BVSCALLS.ARC, the Q number of this article, or S12065.

 You will need to use the PKXARC utility to unarc the file
 BVSCALLS.ARC. BVSCALLS.ARC contains BVSCALLS.DLL and a README file.
 Please read the README file for further instructions on how to install
 the revised BVSCALLS.DLL file.


 43. VERIFY.ARC: Use of DosSetVerify() and DosQVerify()

 When an application calls the OS/2 API DosSetVerify(), the verify
 setting specified is good only for the context of the current process.
 However, it does take effect for any child processes you create using
 DosExecPgm(). This is different than the OS/2 VERIFY command, which
 sets the verify status for the entire screen group.

 A file named VERIFY.ARC in the Software Library demonstrates how to
 use the OS/2 APIs DosQVerify() and DosSetVerify(). VERIFY.ARC contains
 PVERIFY.C, which is a mini-version of the OS/2 VERIFY command that
 works in the context of the current process. With this sample program,
 you can use "PVERIFY ON to turn on verify, and "PVERIFY OFF" to turn
 off verify, or just "PVERIFY" to display the verify status.

 If the source code is modified and "CHILD_PROCESS_TEST" is #defined,
 a child program (invoking CMD.EXE and its internal VERIFY command with
 no parameters) will be executed to display the status of verify within
 the child process. Thus, when the code inside the areas delimited by
 "CHILD_PROCESS_TEST" is enabled, PVERIFY will show scope of the verify
 state in a child process.

 VERIFY.ARC can be found in the Software Library by searching for the
 filename VERIFY.ARC, the Q number of this article, or S12207.
 VERIFY.ARC has been archived with the PKARC utility. You will need to
 unarchive it with PKXARC. A copy of PKXARC can be found on the
 Microsoft OnLine Utilities Disk 2.



 44. Killing Detached Processes

 Question:

 How can I kill a detached process from the command line?

 Response:

 DosKillProcess() will send a kill signal to any process. The process
 will be killed if it does not have a kill signal handler. If the
 process has registered a kill signal handler, that code will be
 executed. To use DosKillProcess(), you must know the PID of the process
 you wish to kill.

 A sample program that demonstrates a method of killing processes from
 the command line is located in the Software Library. This file can be
 found by searching on the filename, KILLPROC.ARC, the Q number of this
 article, or S12205.

 You will need to use the PKXARC utility to unarc the file
 KILLPROC.ARC. KILLPROC.ARC contains KILL.C. KILL.C demonstrates the
 use of DosKillProcess() to kill a process that was reference by its PID.



 45. Drawing over Mouse Pointer

 Question:

 There are some problems when I run the following:

    chaser 43 s

 Sometimes I kill a ship, but it stays on the screen.

 Response:

 You can get phantoms in any mode. This is an example of a race
 condition between separate processes. To correct this problem, the
 program should hide the mouse pointer and draw its own, under
 controlled circumstances. Since this is a demo program only, we will
 leave it for students of OS/2 to correct.

 The problem is that the mouse pointer device driver doesn't "know"
 about changes to the screen (in particular, under the pointer) that
 occur after the pointer has been drawn. When the mouse pointer is
 moved to a new position, whatever used to be in the old position
 before the mouse was moved there is restored. If the pointer is moved
 to cover a "ship," and the ship then moves away, when the mouse is
 again moved, the image of the ship will be restored, leaving a phantom.

 Semaphores are used to control access to the global data and screen
 updates for the attackers and mouse threads. However, the mouse
 pointer is controlled directly by the mouse device driver. Hence it is
 asynchronous to the attackers, and may indeed write the pointer over
 the attacker sometime between when the last mouse event was registered
 and just prior to the attacker thread moving the character.

 To really exaggerate the problem, put a DOSSLEEP of 10 to 50
 milliseconds in the loop that is waiting for a mouse event. Now try
 NOT to get phantoms!

 The demo programs in the SDK are meant to illustrate various OS/2
 features, and to provide some example code to hack on. They are not
 necessarily complete, correct programs--we are interested in problems
 when they relate to an informative topic, but in general it will be up
 to you to provide any necessary corrections. See the header at the
 start of the game program for some "enhancements" suggested by the
 author.


 46. DISKCACHE Option of CONFIG.SYS Unreliable with OS/2 SDK 1.02

 Question:

 Should I use the DISKCACHE option of CONFIG.SYS with the OS/2 SDK
 (Software Development Kit) Version 1.02?

 Response:

 The disk caching in the Version 1.06 OS/2 SDK is not 100 percent
 reliable and may corrupt files on your hard disk. This problem has
 been corrected in subsequent versions of the OS/2 SDK.


 47. OS/2 SDK: Using SIGINTR and SIGBREAK

 Question:

 How are the SIGINTR and SIGBREAK signals handled?

 Response:

 The SIGINTR and SIGBREAK signals are handled differently than other
 signals. Also, in the COOKED mode, CTRL+C is converted into a SIGINTR
 before being passed to the parent process of the current screen group.

 SIGINTR and SIGBREAK use what is called the FOCUS mechanism.
 Basically, what that amounts to is that the LAST process to do a
 DOSSETSIGHANDLER() receives the signal (in the current screen group,
 of course). It is up to that process to determine what to do with the
 signal. Under normal conditions, the SIGINT is caught by the CMD.EXE
 process. CMD then issues a DOSKILL() on any child processes.

 All other signals are applied to the indicated process and/or its tree
 of children. The USER flags (SIGFLA,B,C) have null default action.
 SIGTERM, of course, kills the process.

 Most simple applications will die if they get an interrupt. Some
 different scenarios for catching signals include daemons wanting to
 catch and deal with ALL signals that can cause termination. More
 complex foreground applications (editor, DOS shell, games) may want to
 catch certain flags only to abort the current command. Processes that
 have complex cleanup requirements (database engines) may want to
 catch ALL signals so that they can terminate gracefully.


 48. Detecting Metakeys with KbdCharIn

 Question:

 How can I use KbdCharIn to detect special keys (such as SHIFT, ALT,
 CTRL, etc.)?

 Response:

 To get the status of the SHIFT, ALT, CTRL, etc. keys, you need to set
 bit 8 in the mask field of the KbdSetStatus Call as well as bit 2 to
 turn on raw mode. Then use the KbdCharIn call to get the status of the
 shift-state keys.

 The following is a sample program to demonstrate setting the status
 and then detecting shift-state keys:

 Compile this program using cl -Lp filename.c.

 #include <subcalls.h>
 #include <doscalls.h>
 #include <dos.h>
 #include <stdio.h>

 #define NOWAIT 1
 #define WAIT 0
 #define HANDLE 0   /* for KBD */

 main()
 {
     struct KeyData CharData;
     struct KbdStatus kstat;
     int result;

     kstat.length = 10;
     KBDGETSTATUS((struct KbdStatus far *)&kstat, 0);
     kstat.bit_mask &= ~8;       /* turn off ascii mode */
     kstat.bit_mask |= 0x104;    /* turn on shift reporting and raw mode */
     KBDSETSTATUS((struct KbdStatus far *)&kstat, 0);

   do {
     CharData.char_code=0;
     CharData.status=0;
     CharData.scan_code=0;
     CharData.shift_state=0;
     result= KBDCHARIN( (struct KeyData far *) &CharData,
                (unsigned) WAIT, (unsigned) HANDLE);

    if (CharData.shift_state ||
        CharData.scan_code ||
        CharData.status ||
        CharData.char_code) {
            if(result) {
                printf("Result = %d ",result);
            } else {
                printf("Char Code=%x ",CharData.char_code);
                printf("Scan Code=%x ",CharData.scan_code);
                printf("NLS Status=%x ",CharData.status);
                printf("NLS Shift Status=%x ",CharData.nls_shift);
                printf("Shift state=%x\n",CharData.shift_state);
            }
    }
  } while(CharData.char_code != 'q');
 }


 49. OS/2 Kernel on IBM AT Supports Multiple Displays; PM Does Not

 Question:

 Is it possible to have multiple displays in OS/2? If so, how?

 Response:

 The OS/2 kernel on an IBM AT supports the same multiple-display
 configurations as MS-DOS Versions 3.x (i.e., EGA and Monochrome, CGA
 and Monochrome, etc.). The display that receives VIO output depends on
 the current mode, so VioSetMode() effectively controls display
 switching.

 The Presentation Manager (PM) does NOT support multiple displays.


 50. Hiding the Mouse Cursor in Protected Mode

 Question:
    How do I hide the mouse pointer when in protected mode? There is no
 direct equivalent to the old INT 33 function 2 Hide Cursor call.

 Response:
    The following is an example of how to hide the mouse cursor in
 protected mode:

    1. This example uses the concept of "collision areas" to hide the
 mouse cursor. A collision area is a section of the screen in which the
 device driver will not draw the mouse pointer image. It still is
 possible to move the mouse cursor into a collision area, but the
 cursor will be invisible while it is there, i.e., the pointer will not
 be drawn.
    You can hide the mouse cursor by specifying the entire screen as
 the collision area, and then indicating the position of the mouse by
 drawing your own cursor character.
    The OS/2 system call used to set a collision area is MOUREMOVEPTR.
 Declarations and data structures for this call are in SUBCALLS.H.
    Use MOUDRAWPTR to cancel the collision area, or make a second call
 to MOUREMOVEPTR to set a new collision area. Each new call to
 MOUREMOVEPTR will reset the boundaries of the collision area.
    Only one collision area (the one most recently set) is active at
 any time. MOUDRAWPTR cancels the MOUREMOVEPTR call, allowing the mouse
 pointer to be drawn anywhere on the screen.
    The documentation for MOUREMOVEPTR in the SDK is unclear as to the
 meanings of the parameters being passed. Following are the listed
 parameters:

    a. Row coordinates
    b. Coordinates
    c. Row height
    d. Column width

    A better description might be as follows:

    a. Upper-left row
    b. Upper-left column
    c. Lower-right row
    d. Lower-right column

    Notice that you must subtract 1 from the screen width and height
 supplied by VIOGETMODE. The coordinates for VIOGETMODE are 1-based,
 while the coordinates for MOUREMOVEPTR are 0-based. Specifying
 coordinates outside the range of the screen will cause the call to
 fail and no collision area will be set.
    This program should be built with the following command:

    cl -Ox -G2 -Lp -Zp mouse.c

    2. Press the left mouse button to end the demonstration.

  #include <stdio.h>
  #include <doscalls.h>
  #include <subcalls.h>

  main()
  {
   unsigned short  MouseRow,             (where it is at)
                   MouseCol;
   unsigned short  ScreenHeight,         (screen attributes)
                   ScreenWidth;
   unsigned short  Mouse;                (storage for mouse handle)
   unsigned short  ReadType = 0;         (0 => wait for an event)
   unsigned char   MouseCursor[2],       (our palette)
                   Background[2];
   struct  CursorData      NewCur;       (struct to get/set cursor type)
   struct  CursorData      OldCur;
   struct  EventInfo       MouInfo;      (struct to get mouse event info)
   struct  PtrLoc          InitMouPos;   (struct to set mouse ptr location)
   struct  ModeData        ModeInfo;     (struct to get/set video mode)
   struct  NoPointer       Collision;    (struct to set collision area)

   3. Initialize as follows:

   MouseCursor[0] = 0x09;                         (to initialize the cells we)
   MouseCursor[1] = 0x2F;                          (will be using to draw)
                                                 (our own mouse cursor and)
   Background[0] = 0x20;                     (fill in the background color)
   Background[1] = 0x27;                   (- these attributes are for EGA)
                                                             (clear screen)
   VIOSCROLLUP( 0, 0, -1, -1, -1, (char far *)Background, 0 );
   VIOGETCURTYPE( &OldCur, 0 );              (save info on old cursor type)
   NewCur.cur_start = 0;
   NewCur.cur_end = 0;                           (set cursor attributes to)
   NewCur.cur_width = 1;                         (what we want - invisible)
   NewCur.cur_attribute = -1;
   VIOSETCURTYPE( &NewCur, 0 );                         (reset cursor type)

   ModeInfo.length = sizeof( ModeInfo );                  (get screen mode)
   VIOGETMODE( ( struct ModeData far * )&ModeInfo, 0);      (so we can set)
   ScreenHeight = ModeInfo.row;                          (screen size info)
   ScreenWidth = ModeInfo.col;

    4. Open the mouse pointer device and set its location, as follows:

   MOUOPEN( 0L, ( unsigned far * )&Mouse );      (0 => default mouse image)
   if( ScreenHeight == 25 )                       (put it where we want it)
       InitMouPos.RowPos = 12;
   else
       InitMouPos.RowPos = 21;
   InitMouPos.ColPos = 40;
   MOUSETPTRPOS( ( struct PtrLoc far * )&InitMouPos, Mouse );

    5. Hide the mouse cursor by setting a collision area consisting of
 the entire screen, as follows:

   Collision.Row = 0;
   Collision.Col = 0;
   Collision.Height = ScreenHeight - 1;
   Collision.Width = ScreenWidth - 1;
   MOUREMOVEPTR( ( struct NoPointer far * )&Collision, Mouse );

    6. Loop to read mouse position and draw cursor, as follows:

   while( 1 ) {
       MOUREADEVENTQUE( ( struct EventInfo far * )&MouInfo,     (wait for)
                        ( unsigned far * )&ReadType,           (something)
                        Mouse );                               (to happen)
       if( MouInfo.Mask & 1) {                    (if the mouse has moved)
          VIOWRTCELLSTR( ( char far * )Background, 2, MouseRow, MouseCol, 0 );
          MouseRow = MouInfo.Row;
          MouseCol = MouInfo.Col;
          VIOWRTCELLSTR( ( char far * )MouseCursor, 2, MouseRow, MouseCol, 0 )
       }

       if( MouInfo.Mask & 4 ) {                   (left button pressed)
          VIOSETCURTYPE( &OldCur, 0 );
          DOSEXIT( 1, 0 );
       }
    }
  }


 51. Setting Signal Handlers in C

 Question:

 How do I set a signal handler in C?

 Response:

 Within OS/2, a signal mechanism notifies processes of external events.
 These signals are as follows:

 Signal Name     Description             Signal Number

 SIGINTR          CTRL+C                       1
 SIGTERM          Program termination          3
 SIGBREAK         CTRL+BREAK                   4
 Process flag A   User-defined flag A          5
 Process flag B   User-defined flag B          6
 Process flag C   User-defined flag C          7

 Upon receipt of a signal, the default action for a process is to
 ignore the signal, or terminate the process. For most applications,
 these defaults are unacceptable. OS/2 provides a mechanism to allow a
 process to associate a different action for each signal, if necessary.
 The specific API call used is DOSSETSIGHANDLER.

 The following program is an example of a SIGINTR signal handler. The
 program installs a signal handler for SIGINTR signals. The signal
 handler merely prints out the value of the arguments that OS/2 pushes
 on to the stack. The arguments are signal number and signal argument.

 In this example, the signal number is 1, which is SIGINTR's signal
 number. Signal argument is a flag argument used in conjunction with
 process flags via the DOSFLAGPROCESS API call; hence, its value is
 undefined.

 To run sigdemo, get into a protected-mode shell, run "sigdemo", then
 press CTRL+C.

 Compile with the following: cl -AL -G2 -Lp sigdemo.c.

 #include <doscalls.h>
 #include <subcalls.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <dos.h>
 #include <signal.h>

 extern void pascal far sig_handler();
 extern far sig_handler2();

 #define USE_SIGHANDLER 2     /* on signal trap, jump to sig_handler */
 #define SIGINTR        1     /* trap SIGINTR's, otherwise known as CTL-C */

 void main() {

     void (pascal far *address)(); /* address of previous signal handler */
     unsigned    oldaction;        /* previously set action */
     /*
      *  signal action jump to sig_handler
      */
     unsigned    action          =  USE_SIGHANDLER;
     /*
      *  signal to trap, SIGINTR's, (ctl-c)
      */
     unsigned    signum          =  SIGINTR;
     unsigned    result;           /* return code from API call */

     /*
      *  set up new action associated with SIGINTR's, jump to sig_handler
      */
     if (result = DOSSETSIGHANDLER((void(far *)())sig_handler,
                                   (unsigned long far *) &address,
                                   (unsigned far *) &oldaction,
                                   action,
                                   signum))
         fprintf(stderr,"dossetsighandler failed %d\n", result);

     DOSSLEEP(10000L);  /* hang around for 10 seconds */

     fprintf(stderr,"main exiting\n");

     exit(0);
 }

 /*
  *  sig_handler - the SIGINTR signal handler prints out the arguments
  *                on the stack, and sends an acknowledgement of signal
  *                receipt.
  *
  *      at sig_handler invocation, the stack looks like the following:
  *
  *              (SS:SP)   far return address
  *              (SS:SP+4) signal number being handled
  *              (SS:SP+6) signal argument
  *
  *      OS/2 cleans up the stack for us by restoring all register states
  *      to the value prior to the receipt of the signal. Since C normally
  *      cleans up the stack AFTER returning from a call, this function
  *      is declared as "pascal", which has the effect of not cleaning the
  *      stack, and reversing the ordering of the arguments.
  */
 void pascal far sig_handler(sig_arg, sig_num)
 unsigned sig_arg, sig_num;
 {
     unsigned prevact; /* previous action */
     long address;   /* previous address, since we're acking, this is ok */
     int  result;    /* return code */

     /*
      *  print out the argument values OS/2 pushed on the stack
      */
     fprintf(stderr,
             "signum\t%u\t(should be 1)\nsigarg\t%u\t(should be null)\n",
             sig_num,
             sig_arg);

     /*
      *  acknowledge the receipt of the signal, enabling this particular
      *  signal once again.
      */
     if (result = DOSSETSIGHANDLER((void (pascal far *)()) 0,
                                   (long far *) &address,
                                   (unsigned far *) &prevact,
                                   (unsigned) SIG_ACK,
                                   sig_num))
         fprintf(stderr,"dossetsighandler failed %d\n", result);
 }


 52. Running Files for Protected-Mode Screen Groups

 Question:

 How can I have a file executed for each protected-mode screen group
 start-up (e.g. in the same way AUTOEXEC.BAT is executed for MS-DOS
 shells)?

 Response:

 The file specified will be executed for each screen group started if
 the line ""protshell=shell.exe cmd.exe" in your CONFIG.SYS file is
 changed to "protshell=shell.exe cmd.exe /k [drive:][pathname]".
 However, the file is not executed for the first screen group; only
 STARTUP.CMD is executed.

 The most convenient file to place there would be some sort of command
 file (like INITENV.CMD of the SDK) to initialize the environment
 variables. However, any file (e.g. a command processor, an
 application) may be specified.

 To execute INITENV.CMD in the first screen group, call it from the
 STARTUP.CMD command file. (It is advisable to call INITENV.CMD before
 executing any other commands in STARTUP.CMD, as INITENV.CMD sets up
 the environment.)

 The call syntax is as follows:

    CALL INITENV


 53. Disk I/O Unreliable if 3.x Box in Foreground

 Question:

 Is floppy disk input/output reliable?

 Response:

 Floppy drive input/output is not reliable from the 3.x box, or from a
 background protected mode screen group while the 3.x box is in the
 foreground.


 54. OS/2 SDK: Sending Information between Processes

 Question:

 What is the best way to send data between two processes?

 Response:

 There are several methods that can be used to send data to and from a
 server process. They are pipes, named pipes, shared memory, and queues.

 Pipes allow distributed processing and are transparent to either of
 the processes using them. This allows the data to be sent over
 the network. Pipes also do not require extra work on your part to keep
 track of the data being transferred and can be either synchronous or
 asynchronous. (See the examples on the SDK Toolkit disk \example\pipes
 on how pipes are implemented.) Pipes have a limitation in that they
 are of a fixed length (not more than 64K) because they have to fit
 within one segment.

 Named pipes also could be used to send data between processes, even
 over a network. The difference between pipes and named pipes is that
 named pipes act like full duplex virtual circuits; regular pipes are
 only one direction. (See the LAN Manager documentation for a detailed
 description of named pipes.)

 Shared memory is the fastest method for transferring data, but it
 requires more work on your part. You have to manage the memory to keep
 the reading and writing processes synchronized with each other.

 Queues also can be used to transfer the data between the processes.
 The advantage of using queues is that only a pointer to the data is
 passed, making them somewhat more efficient than pipes. A disadvantage
 is that queues cannot be extended across a network (named pipes can be
 extended across a network).


 55. What Descriptor Table Is Active in a Registered Function Call

 Question:
    Whose descriptor table is in effect when a video registered
 function is called?

 Response:
    The descriptor table of the process that did the video call is in
 effect.


 56. OS/2 SDK: Creating Process to Poll External Devices

 Question:

 I would like to know if it is possible to create a process that will
 poll an external device at least once during a given time interval
 without taking up a lot of CPU time. The time interval would need to
 be on the scale of 1-2 milliseconds.

 Response:

 You can poll devices in the manner you describe, except that the
 smallest interval (slice) is 32 milliseconds. Under OS/2 you could
 implement this in either of the following ways:

  1. Write the routine as a stand-alone application that sleeps and
     periodically wakes up to poll the device.

  2. Write the routine as a device driver that takes advantage of
     the timing interface available to device drivers.

 Either way, because of the slicing algorithms, your routine is going
 to be the only application using the CPU. There will be little
 opportunity for the other tasks to run.


 57. OS/2 SDK: Brief Will Not Run in the Compatibility Box

 Problem:

 While running Brief Version 1.33 in the 3.x box, I am having problems
 with the system locking up. There does not appear to be any pattern to
 it; the system just stops. The system has to be turned off;
 CTRL+ALT+DEL does not work.

 Response:

 Microsoft is aware of these problems with Brief and the compatibility
 box. We have contacted the author of Brief, and he suggests that you
 acquire an update from Solution Systems, the marketers of Brief. The
 version he suggests to update to has a build date later than 5/5/87
 (ideally, the 5/6/87 build). These builds contain the necessary
 corrections to the Brief keyboard handler that will allow it to work
 with the OS/2 compatibility box. The author further suggests that when
 you invoke this version of Brief from the command line, you specify
 the "-k" option.


 58. Access and Create Date/Times in FileFindBuf

 Problem:
    The FileFindBuf used in DosFindFirst and DosFindNext has entries
 for the following:

    1. Create Date
    2. Create Time
    3. Access Date
    4. Access Time
    5. Write Date
    6. Write Time

    The Write Date and Write Time is filled in correctly, but the
 Create and Access Date and Times always appear as 0.

 Response:
    Information on Create Date and Time and Access Date and Time is not
 kept in the directory entries for files under the DOS file system used
 by Versions 1.00 and 1.10 of OS/2.
    Therefore, this information cannot be returned. These fields were
 included for use by Installable File Systems under future versions of
 OS/2.


 59. BPB Returned by DosDevIOCtl Category 8 Function 63h

    The DosDevIOCtl category 8 function 63h is used to obtain
 information about disk devices. The following are its return values:

    Bytes per sector      WORD
    Sectors per cluster   BYTE
    Reserved sectors      WORD
    Number of FATs        BYTE
    Root dir.entries      WORD
    Total sectors         WORD
    Media descriptor      BYTE
    Sectors per FAT       WORD
    Sectors per track     WORD
    Number of heads       WORD
    Hidden sectors        DWORD
    Large total sectors   DWORD
    Reserved              6 BYTES


 60. State of Processor in Device Driver After a ProcBlock

 Response:
    The processor will be in the same mode when it returns from a block
 as it was when it issued the block command.


 61. NOWAIT Option of the KbdCharIn

 Question:
    How can I determine if a character was returned from KbdCharIn
 set to NOWAIT?

 Response:
    Use the status byte. Bit six set to one indicates a character
 was returned. If this bit is set to zero, no character was
 returned.


 62. DOSDEVIOCTL, Category 5 - Function "Get Printer Status"

 Question:
    What IOCTL is used for getting the printer status?

 Response:
    The "Get Printer Status" (Category 5) IOCTL is 66H.


 63. Process and Thread Status

 Question:
    How can I access the following information?

    1. Process and thread status
    2. DLL usage and linkage
    3. A listing of system resources currently in use, such as the
 following:

       a. Queues
       b. Shared memory
       c. System semaphores

    4. Other system information

 Response:
    There is a new utility called PS (Process Status). This displays
 information about the state of the MS OS/2 environment. It displays a
 list of all running threads, DLL usage and linkage, shared memory
 allocation, and system semaphore states. It is a protected-mode-only
 program.
    A special version of the kernel must be installed. Please refer to
 Section 2.2.2 of the "Microsoft OS/2 SDK Installation" manual for
 instructions (OS/2 SDK Version 1.02) on how to install it.


 64. SUBST Command in the Protected Mode

 Question:
    Will SUBST work in protected mode?

 Response:
    The SUBST command does not work in the protected mode.


 65. Cursor Not Supported in MouSetPtrShape Call

 The current documentation of the MouSetPtrShape call implies that a
 mouse cursor is supported in video modes 0-7 as well as in some
 graphics modes.

 This is an error on Page 431 of the "Microsoft Operating System/2
 Programmer's Reference Guide." We currently do not support the drawing
 of a mouse cursor in any graphics mode.


 66. OS/2 SDK: Profiler Not Enough Memory Error

 Question:

 When I try to profile a large executable, profInit returns error 8
 (ERROR_NOT_ENOUGH_MEMORY). Is there a maximum limit on the size of a
 program that can be profiled?

 Also, is there any way that I can get profile information of time
 spent in system DLLs on a system-call by system-call basis rather than
 on a segment by segment basis (i.e., can we get the map files for the
 GPI, WIN, and DOS APIs)?

 Response:

 Yes, there is a limit on the size of the program that the profiler can
 profile. The profiler works as follows. For every code segment that
 your application has, a corresponding and equal sized data segment is
 allocated. The clock interrupt is then hooked. For every clock tick
 that comes in, the DS value is examined. If it belongs to the
 application being profiled, a dword value in the data segment
 corresponding to the code segment is incremented, based at an offset
 into the data segment corresponding to the offset into the code
 segment. This is why the resolution of the profiler is a dword. After
 incrementing the value, the clock interrupt handler returns control
 back to the system.

 Note that because the data segment is updated at interrupt time, it
 MUST be present in memory at all times. This means that it cannot be
 swapped out. That is why the memory requirements for profiling an
 application are so much larger than just running the application
 without profiling. For every code segment, there is also going to be
 one LDT slot used to allocate the corresponding data segment. You
 could potentially run out of selectors and cause the out-of-memory
 error for this reason.

 Unfortunately, we cannot release the map files for portions of the
 system like DOSCALL1.DLL or PMWIN.DLL. You can create functions that
 simply do the call that you are interested in and then create a macro
 that replaces all the occurrences of the Dos or Win call with a call
 to your routine. This will allow you to know how much time your
 application is spending doing the specified call (with the overhead of
 an additional call). Whether you want to go to this trouble will
 depend on how many system calls you are most interested in and how
 critical it is to know the time spent within them compared to the time
 spent within your application's routines.


 67. Documentation Error: Incorrect Definition for Status Field

 On Page 81 of the "Microsoft Operating System/2 Software Development
 Kit Device Drivers Guide" the definition of the status field is
 incorrect. This also affects the Open/Close request packet definitions
 on their associated pages.

 Bit 3 of the status field is set on open/close requests to indicate
 that this request originated from a DosMonOpen/DosMonClose call. If
 the request originated from a DosMonClose, you need to Deregister the
 monitor chain so that the monitor threads will die when the device is
 closed.


 68. OS/2 SDK: Launching Threads

 Problem:

 I have an application in which I need to launch and destroy threads.
 However, I cannot find any kernel function that allows me to destroy a
 thread and recover the resources associated with it.

 Response:

 If your application needs to destroy threads, they should be using
 processes. When processes are used, the OS/2 calls DosExecPgm() and
 DosKillProcess() can be used for launching and destroying. Resources
 can be shared between processes by using the Inter Process
 Communications (IPC) facilities and/or shared memory.

 Although processes are somewhat more expensive to create than threads,
 once they are running they require no more overhead than threads.

 An alternative is to design your threads so that they periodically
 check a flag or a semaphore and DosExit(0,0) when it is set. If your
 application cannot be guaranteed to check the flag, the method above
 is the best approach.

 If you choose the alternative method, think carefully about how the
 master thread will know that the dying thread died. The best approach
 is to do a DosEnterCritSec(), then clear the flag/semaphore and
 DosExit(). This will guarantee that the daughter thread will die
 before the master thread tries to launch another thread.


 69. DosSetFHandState() fsState Parameter Information

 Question:

 I have a question about the documentation for the DosSetFHandState()
 function. On Page 138 of the "Microsoft Operating System/2
 Programmer's Reference Volume 3" for Version 1.10 it states that
 fsState flag can be set to three different values. However, the
 include file BSEDOS.H shows a list of many more values that apply to
 both DosOpen() and DosSetFHandState(). Which is correct, the
 documentation or the include file?

 Also, is the fsOpenMode parameter of the DosOpen() function the same
 as the fsState parameter of the DosSetFHandState() function?

 Response:

 The values of the fsState parameter of DosSetFHandState() can be set
 to the following:

    OPEN_FLAGS_NOINHERIT
    OPEN_FLAGS_FAIL_ON_ERROR
    OPEN_FLAGS_WRITE_THROUGH

 The other OPEN_FLAGS_* value listed in BSEDOS.H, which CANNOT be used
 in the fsState parameter of DosSetFHandState() is the following:

    OPEN_FLAGS_DASD

 All four of these OPEN_FLAGS_* flags listed above can be used in the
 fsOpenMode parameter of DosOpen(). Thus, DosSetFHState() can only set
 some (three of the four) file handle state flags. Because of the way
 OPEN_FLAGS_DASD is implemented inside the OS/2 kernel, it is not
 possible to set the OPEN_FLAGS_DASD flag after the file has been
 opened; it can only be done when the file is opened via the DosOpen()
 function.

 There is another relationship between these flags and the functions
 DosOpen(), DosSetFHandState(), and DosQFHandState(): the
 DosQFHandState() function returns the equivalent of the entire
 fsOpenMode [of DosOpen()] parameter of the file handle.

 Therefore, when the file is opened, you can set all these flags and
 other file handle states with DosOpen(), and you can query the values
 of all of the flags of a handle at any time with DosQFHandState().
 However, you can only modify SOME of the file handle flags with
 DosSetFHandState() after the file has been opened.

 The other bitfields of the WORD in the fsOpenMode parameter of
 DosOpen() are as follows:

    5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
    D W F R R R R R I S S S R A A A

 where:

    AAA  the OPEN_ACCESS_* flags [3 bits]
    SSS  the OPEN_SHARE_* flags [3 bits]
    I    the OPEN_FLAGS_NOINHERIT flag [1 bit]
    F    the OPEN_FLAGS_FAIL_ON_ERROR flag [1 bit]
    W    the OPEN_FLAGS_WRITE_THROUGH flag [1 bit]
    D    the OPEN_FLAGS_DASD flag [1 bit]
    R    the reserved flags [many bits]


 70. Awake Codes for the DevHlp_Block Function

 Question:

 What are the "awake" codes for the DevHlp_Block function? The manual
 states that an awake code is returned in AL, but doesn't list the
 values.

 Response:

 The awake codes are not important. All the information is given in the
 carry and zero flags.

 The current values are as follows:

    normal      - carry unset
    timeout     - carry set, zero set
    interrupted - carry set, zero unset


 71. Minimum System OS/2 Boot Disk

 Question:

 What files are required to be on the boot disk for OS/2?

 Response:

 The following is the minimum number of files that must be present on
 your boot disk:

 OS2DOS.COM       OS2BIOS.COM      OSO001.MSG       OSO001H.MSG
 STARTUP.CMD      INITENV.CMD      AUTOEXEC.BAT     CONFIG.SYS

 CLOCK01.SYS      KBD01.SYS        SCREEN01.SYS
 DISK01.SYS       OEMHLP.SYS

 BKSCALLS.DLL     BMSCALLS.DLL     BVSCALLS.DLL
 KBDCALLS.DLL     MOUCALLS.DLL     VIOCALLS.DLL
 DOSCALL1.DLL     ANSICALL.DLL     MONCALLS.DLL
 MSG.DLL          NLS.DLL          QUECALLS.DLL     SESMGR.DLL

 You can remove the dynalink libraries from the boot floppy if you set
 the LIBPATH variable in your CONFIG.SYS file to point to the location
 of the dynalink libraries on your hard disk.

 You will also need any other device drivers (*.SYS files) for other
 devices you may have on your system such as a mouse, serial port, etc.


 72. Setting Unsupported Video Modes (Debugging)

 Question:
    How can I set my video card into 35x80 mode?  When the system
 starts up, my video card behaves like a CGA card. I can change its
 mode by outputting to a port that can set the card into the mode I
 desire. When I use VioSetmode to set the mode, I get error returns.

 Response:
    The VioSetMode will only change the video into modes that are
 documented. To change the display into another mode, you must use the
 VioModeWait API, as follows:

      1. Create a thread that calls VioModeWait.
      2. Put the video display into the desired mode, through out
         instructions. This will require an IOPL code segment (to use
         in or out instructions).
      3. When the VioModeWait thread returns, reset the video mode.
         (This includes the cursor mode).

    For some video operations, you may need to use the VioSavRedrawWait
 API. You should look up both of these API calls in the "Microsoft
 Operating System/2 Programmer's Reference" manual.
    Please note the following about debugging:

    When you have a thread for ModeWait or SavRedrawWait, debugging
 with CodeView may not perform as expected. When a screen switch
 occurs, the system waits for your application to finish its ModeWait
 or SavRedrawWait operation before the actual screen switch completes.
 OS/2 is depending on the cooperation of the application program. When
 you are debugging an application with CodeView, CodeView tends to
 "freeze" the application's threads. If a screen switch is attempted
 (by you or the debugger, i.e., the debugger is attempting to make
 itself the foreground process) when the application's threads are
 frozen, the Vio subsystem will deadlock.


 73. PhysToUVirt Call in Device Drivers

 Question:
    The documentation in the device driver guide is not clear.
    When using the PhysToUVirt call to release memory (DH = 2), should
 AX:BX still have the physical address, or is it the inverse so that it
 should have the virtual?

 Response:
    For request type 2, AX contains a selector on entry to PhysToUVirt.
 BX and CX are ignored.


 74. VioGetMode(), VioSetMode() hvio Parameter Documentation Error

 Microsoft has confirmed that Pages 213 and 242 of the "Microsoft
 Operating System/2 Programmer's Reference Volume 3" for Version 1.10
 incorrectly document the hvio parameter of the functions VioGetMode()
 and VioSetMode(). Furthermore, this documentation error also occurs in
 the version of QuickHelp that is included with Version 1.10 of the
 OS/2 Software Development Kit (SDK).

 Both the functions VioGetMode() and VioSetMode() take as their second
 parameter a 16-bit word, "HVIO hvio". In the references sited above,
 this parameter is documented as capable of being used as a handle to
 an advanced video input and output (AVIO) presentation space. The
 documentation further states that this handle must have been created
 previously with the function VioCreatePS(). These statements are not
 correct. The functions VioGetMode() and VioSetMode() are only valid
 for VIO-windowable applications; they are not supported by
 Presentation Manager (PM) and they must not be used by PM or AVIO
 applications. The parameter "HVIO hvio" is a reserved word that must
 always be zero. An error will be returned if VioGetMode() or
 VioSetMode() is called with a nonzero handle.

 Also note that when VioSetMode() is called from a VIO-windowed
 application (as opposed to an application that is running in its own
 screen group), it will not change the size of a character cell.


 75. Device Driver Timer Interrupt and Devhlp SETTIMER Problem

 OS/2 will crash if two device drivers both register "timer interrupt"
 service routines with the Devhlp SETTIMER function, and if the timer
 handlers start at the same offset, but in different code segments.

 Microsoft has confirmed this to be a problem with the Software
 Development Kit Version 1.05.  We are researching this problem and
 will post new information as it becomes available.

 The workaround is to have different offsets for the timer handlers.


 76. Default QSIZE Parameter for a Mouse

 The default value for the QSIZE parameter listed on Page 69 of the
 "Microsoft Operating System/2 Setup Guide" is 10. This information can
 be found on Page 91 of the "Microsoft Operating System/2 Desktop
 Reference."


 77. SHELL11F.AII, SHELL11F.AIF, and SHELL.LIB Descriptions

 Question:
    What are the files SHELL11F.AII, SHELL11F.AIF, and SHELL.LIB in the
 SYS directory of OS/2 used for?

 Response:
    These files relate to the Program Selector, the screen you see when
 you press CTRL-ESC.
    SHELL11F.AII and SHELL11F.AIF contain information on the entries
 you see in each of the columns on the Program Selector screen.
    SHELL.LIB contains screen-drawing information to create the Program
 Selector screen. The .LIB format was used for this file because it was
 efficient to do so; it is not a true library.
    These three files must be in the same place as SHELL.EXE, as
 pointed to by the "protshell" parameter in CONFIG.SYS.


 78. Overhead on DosRead() and DosWrite() Calls

 Question:

 When communicating to a character device through a device driver, such
 as a COM device or a user-written device driver, it is unclear what
 the overhead is in using the DosRead() and DosWrite() functions.

 In an environment where there are no monitors, is there any processing
 that OS/2 does to the data in a DosRead() or DosWrite() request to
 such a device driver? This question applies to anything from a simple
 copy to any other data processing. Would there be less overhead if I
 were to accomplish device I/O with DosDevIOCtl()?

 Response:

 OS/2 Version 1.10 does no processing to the data in a DosRead() or
 DosWrite() call. These functions operate in binary (raw) mode.

 The OS/2 overhead involved in these functions essentially consists
 of the following:

 1. Handling I/O redirection

 2. Locking the user data buffer

 3. Switching to Ring 0

 4. Calling the device driver

 5. Doing some standard error handling procedures

 Doing the read or write with a DosDevIOCtl() involves basically the
 same OS/2 overhead described above, except for locking the user data
 buffer. This is left as an option for the device driver to implement
 if necessary for that particular device.


 79. Information on How to Write a Device Driver

 Problem:
    I am unable to find a description of the steps necessary to
 construct a driver for OS/2 and install it. The driver documentation
 covers the functions available (DevHlps, etc.), but it does not
 indicate how to build the driver .EXE file and what must be done to
 convert that file to a .SYS file (if anything).
    A sample driver of any kind would be a great help. An explanation
 of how to provide an alternate base driver and what must be provided
 to completely override a base driver would also help.

 Response:
    The design and writing of device drivers was not covered in detail
 in the SDK release of OS/2. Microsoft provides a Device Driver
 Developers Kit (DDDK) that does provide this added information. You
 can request it through your account manager or a Microsoft Service
 Request.


 80. Guidelines for Interrupt Handler

    Device driver interrupt handlers must be carefully written in order
 to prevent uncontrolled stack growth of the interrupt stack. An
 interrupt handler should consume as little stack space as possible
 and should limit the depth of "interrupt nesting."
    Device drivers that do processing after sending an end-of-interrupt
 (EOI) to the interrupt controller (8259) and enabling interrupts (STI)
 can receive "nested interrupts." To prevent using excessive interrupt
 stack space, the device driver should keep internal flags to limit the
 amount of interrupt nesting.
    The amount of interrupt nesting is limited by performing all
 post-EOI processing at the first-level interrupt. Nested interrupts
 should avoid and, if possible, eliminate post-EOI processing. In all
 cases, the device driver should bound the number of nesting levels
 to as few as possible (preferably two) and should never permit the
 levels of nesting to be unbounded.

    A technique for limiting the amount of interrupt nesting to two
 levels can be implemented as follows:

    1. When the nested interrupt is encountered, a flag (or count) is set
 so that the post-EOI processing can be done again by the first-level
 interrupt if necessary.
    On a nested interrupt, the interrupts must be disabled (and remain
 disabled) before doing the EOI and returning to the Interrupt Manager.
    2. On a first-level interrupt, interrupts may be enabled before doing
 the EOI and may remain enabled during the post-EOI processing.
 Interrupts must be disabled (and remain disabled) before clearing the
 "interrupt in progress" flag and returning to the Interrupt Manager.

    As stated previously, if a device driver needs to support more than
 one level of nested interrupts, it still must limit the number of
 nested interrupts that it handles. A device driver should avoid this
 if at all possible.
    As device drivers allow more levels of nesting for their interrupt
 handlers, the potential exists for the entire interrupt stack to be
 consumed. This applies to all device drivers, regardless of the
 interrupt rate of the device being supported.
    It may seem that a device driver for a slow device need not follow
 this convention. However, if the system contains another device that
 has a high interrupt rate, or many devices with more moderate
 interrupt rates, the interrupt latency (time between occurrence of
 hardware interrupt and dispatch to interrupt handler) may become
 greater than the interrupt rate of the "slow" device, and excessive
 nesting can occur.
    The following are pseudo-code examples of the proper algorithms:

 PSEUDO-CODE EXAMPLE (using a flag for nested interrupts)

    fDoingPostEOI = FALSE;     /* TRUE => doing Post-EOI processing */
    fNestedInts = FALSE;       /* TRUE => nested interrupt(s) occurred     */

    InterruptHandler ();
      /* pre-EOI processing */  /* CANNOT get a nested interrupt before EOI */

     if (fDoingPostEOI == TRUE) {    /* This is a nested interrupt */
         fNestedInts = TRUE;         /* Indicate nested interrupt occurred */
         cli;                        /* Prevent further interrupt nesting */
         EOI;
     }
     else {                          /* first-level interrupt */
         fDoingPostEOI = TRUE;       /* flag interrupt in progress */
         fNestedInts = TRUE;         /* force one EOI processing loop */
         sti;                        /* allow NESTED interrupts after EOI */
         EOI;                        /* issue EOI to interrupt controller */

         cli;                        /* Protect fNestedInts */
         while (fNestedInts == TRUE) { /* Do Post-EOI processing */
             fNestedInts = FALSE;    /* Reset nesting flag */
             sti;                    /* allow NESTED interrupts */
             /* post-EOI processing */
             cli;                    /* Protect fNestedInts */
         }
         fDoingPostEOI = FALSE;      /* interrupt no longer in progress */
     }
     return                          /* interrupts ALWAYS disabled here */
    }

    PSEUDO-CODE EXAMPLE (using a count for nested
 interrupts)

    fDoingPostEOI = FALSE;              /* TRUE => doing Post-EOI processing *
    cNestedInts = 0;                    /* count of nested interrupts */

    InterruptHandler ();
     /* pre-EOI processing */    /* CANNOT get a nested interrupt before EOI *

     if (fDoingPostEOI == TRUE) {    /* This is a nested interrupt */
         cNestedInts = cNestedInts+1;/* Increment nested interrupt count */
         cli;                        /* Prevent further interrupt nesting */
         EOI;
     }
     else {                          /* first-level interrupt */
         fDoingPostEOI = TRUE;       /* flag interrupt in progress */
         cNestedInts = 1;            /* force one EOI processing loop */
         sti;                        /* allow NESTED interrupts after EOI */
         EOI;                        /* issue EOI to interrupt controller */

         cli;                        /* Protect cNestedInts */
         while (cNestedInts > 0) {   /* Do Post-EOI processing */
             cNestedInts = cNestedInts - 1; /* Decrement nested ints count */
             sti;                    /* allow NESTED interrupts */
             /* post-EOI processing */
             cli;                    /* Protect cNestedInts */
         }
         fDoingPostEOI = FALSE;      /* interrupt no longer in progress */
     }
     return                          /* interrupts ALWAYS disabled here */
    }


 81. File Names Longer Than 8+3 Characters

 Question:
    What happens if a file is opened with a name longer than
 8+3 characters?

 Response:
    If you use file names that are greater than 8+3
 characters the names will be truncated to 8+3 characters,
 but it will not cause any errors. However, this will be
 changed in the future to return an error because future
 file systems will allow longer names. This will not affect
 the 3x box because it will continue to truncate names
 greater than 8+3 characters.


 82. Error in Attribute Word in Device Drivers Guide for OS/2 SDK

 There is an error in attribute word on Page 79 of the "Microsoft
 Operating System/2 Software Development Kit Device Drivers Guide." The
 function level is incorrect for an MS OS/2 Device driver. It should be
 001, not 010.


 83. OS/2 SDK: Problem Using Mouse in Compatibility Box

 Problem:

 I am trying to run Windows in the DOS compatibility box, and
 Presentation Manager (PM) in protected mode. I have no problems with
 the mouse and PM, but when Windows starts up there is no response from
 the mouse.

 Response:

 There is a known problem with using a mouse with Windows Versions 2.1a
 through 2.1d running in the DOS compatibility box. The problem stems
 from a compatibility problem that occurs with the OS/2 mouse driver
 running in the DOS compatibility box.

 The patch below is intended to correct problems that might be
 encountered when running Windows Versions 2.1a-2.1d in the DOS
 compatibility box of OS/2. The patch is implemented on one of the
 files in Windows (KERNEL.EXE) on the Setup/Build disk.

 To run this patch, you need PATCH.EXE, which is supplied with OS/2.
 Refer to the OS/2 documentation regarding information on PATCH.

 To implement the patch, follow these instructions:

 1. If Windows is already set up in a directory on your hard disk, do
    the following:

    a. Place the file PATCHWIN.21X (see below) in the Windows directory.

    b. Place the Windows Setup/Build disk (disk 1) in Drive A.

    c. Go to the Windows directory and type the following at the DOS
       prompt:

          PATCH PATCHWIN.21X /A

 2. If Windows is NOT set up on the hard disk, do the following:

    a. Place the file PATCHWIN.21X (see below) anywhere on the hard
       disk.

    b. Place the Windows Setup/Build disk (disk 1) in Drive A.

    c. Go to the Windows directory and type the following at the DOS
       prompt:

          PATCH PATCHWIN.21X /A

       You will notice a series of messages appearing on the screen. Be
       sure that you see one of the following messages; do not be
       alarmed by any other messages:

       1) SYS1595: The Verification Failed for <filename>

       2) Patches applied to <filename>

 The following are the contents of PATCHWIN.21X:

 FILE a:kernel.exe               ;Windows 286/2.1C-2.1D (Slow-Boot)
      VER 000047F5 80-3E-A2-00-05-72-0B-2E-F6-06-0F-01-10-74-03
      CHA 000047F5 F6-06-0F-01-10-75-08-2E-80-3E-A2-00-05-72-03

 FILE a:kernel.exe               ;Windows 286/2.1A (Slow-Boot)
      VER 000047F5 80-3E-A0-00-05-72-0B-2E-F6-06-0D-01-10-74-03
      CHA 000047F5 F6-06-0D-01-10-75-08-2E-80-3E-A0-00-05-72-03

 FILE win200.bin                 ;Windows 286/2.1C-2.1D (Fast-Boot)
      VER 00003FC5 80-3E-A2-00-05-72-0B-2E-F6-06-0F-01-10-74-03
      CHA 00003FC5 F6-06-0F-01-10-75-08-2E-80-3E-A2-00-05-72-03

 FILE win200.bin                 ;Windows 286/2.1A (Fast-Boot)
      VER 00003FC5 80-3E-A0-00-05-72-0B-2E-F6-06-0D-01-10-74-03
      CHA 00003FC5 F6-06-0D-01-10-75-08-2E-80-3E-A0-00-05-72-03


 84. Determining What Type of Application Is Calling a DLL

 Question:

 I have a dynamic linked library (DLL) that provides functions to
 various applications. I would like to put up an error message in a
 VioPopup() if the calling application is text based, or put the error
 message in a message box if the calling application is Presentation
 Manager (PM) based. Is there any way for a DLL to determine the
 executable type of the calling application?

 Response:

 Because any DLL-provided code executes in the context of the process
 that calls it, that DLL code can call DosGetInfoSeg() and look in the
 process's local infoseg (LINFOSEG) to determine the type of the
 process. For example, the following code demonstrates how to do this:

     USHORT      usError;        /* API return code         */
     SEL         selGlobalInfo;  /* Selector to GINFOSEG    */
     SEL         selLocalInfo;   /* Selector to LINFOSEG    */
     PLINFOSEG   plis;           /* Far pointer to LINFOSEG */
     .
     .
     usError = DosGetInfoSeg( &selGlobalInfo, &selLocalInfo );
     if ( usError )
         {
         /* process the error */
         }
     plis = MAKELINFOSEG( selLocalInfo );
     switch ( plis->typeProcess )
         {
         case 0:         /* Full-screen process ...  */
                                         break;

         case 1:         /* DOS process ...           */
                          break;

         case 2:          /* VIO-windowed process ... */
                          break;

         case 3:          /* PM process ...           */
                          break;

         case 4:          /* Detached process ...     */
                          break;

         default:         /* This line should never be reached */
         }
     /*
     .
     .
     .
     */


 85. Missing Documentation on START Command

 Question:

 The "Microsoft Operating System/2 Software Development Kit User's
 Guide" lacks documentation for the START command. Could you provide
 this?

 Response:

 The Start Command is used to start another process in a different
 session. The parameter list for the command (in which "program title"
 is the title that will be displayed by the session manager, and /C
 specifies the /C option of CMD.EXE because Start goes indirectly
 through CMD.EXE.) is as follows:

    Start ["program title"] [/C] command [command inputs]


 86. Installation Documentation Errors

 Question:

 The installation program (instaid.exe) for OS/2 does not match the
 documentation on Page 2 in the "Microsoft OS/2 Setup Guide" manual.
 For instance, the documentation says that option 3 is dual-boot and
 option 4 is to update a system with a previous version of OS/2. The
 install program has these reversed. Also, option 3 (no dual boot)
 installs dual boot on the system. How do I install OS/2 without
 dual-boot?

 Response:

 The documentation is incorrect concerning options 3 and 4, as you
 described. Option 3 does not work correctly; however, option 2 will
 install OS/2 on your machine without dual-boot and without formatting
 your hard disk.

 You will need to reformat your hard disk if it was not partitioned
 with a version of DOS that used a partitioning scheme similar to
 MS-DOS Version 3.30.


 87. DosBufReset() Works Differently In 3.x Box vs. MS-DOS 3.30

 In the case of a bound family application, the DosBufReset() call
 gives different results depending on whether or not the application is
 running in the DOS compatibility box under OS/2, or under a real
 MS-DOS system (e.g. MS-DOS Version 3.30). If a specific file handle
 (not "-1") is specified in the DOS compatibility box, the function
 returns a NO_ERROR status. Under MS-DOS Version 3.30, the function
 returns an ERROR_INVALID_HANDLE status.

 Microsoft has confirmed that this is a problem in the Version 1.06
 OS/2 SDK (Software Development Kit). We are researching this problem
 and will post new information as it becomes available.


 88. OS/2 Will Not Boot on PS/2 with a 8514 Adapter

 Problem:

 I am trying to bring up the Version 1.05 of the OS/2 SDK on my PS/2,
 which has a 8514 adapter installed in it. While the system is booting,
 I receive a Trap 0D error. The CS value returned equals 0417.

 Response:

 The above problem is known to occur on PS/2 systems with an 8514
 adapter installed. The Install disk generates a trap 0D error, and the
 CS value returned after the trap 0D error typically equals 0417. There
 is an updated version of BVSCALLS.DLL that corrects this problem. You
 can download the corrected version of BVSCALLS.DLL from the software
 library. This file can be found in the Software Library by searching
 on the filename BVSCALLS.ARC, the Q number of this article, or S12065.

 You will need to use the PKXARC utility to unarc the file
 BVSCALLS.ARC. BVSCALLS.ARC contains BVSCALLS.DLL and a README file.
 Please read the README file for further instructions on how to install
 the revised BVSCALLS.DLL file.


 89. Scheduling Priority of Background Threads

 Question:

 Does OS/2 give special preference to threads belonging to foreground
 processes in CPU dispatching priority?

 Response:

 Threads are scheduled independently depending on their class and
 priority. However, a thread may be boosted in priority for one of the
 following reasons:

 1. If the thread is in the foreground screen group

 2. If the thread has a keyboard focus


 90. Function Calls in Programmer's Reference No Longer Present

 On Page 48 of the "Microsoft Operating System/2 Software Development
 Kit Programmer's Reference, the following function calls are listed:

   VioSetMnLockTime
   VioSetMxSavetime
   VioGetTimes

 However, these functions are no longer present in OS/2.


 91. OS/2 SDK: Piping Information to an I/O Port

 Question:

 I would like to know how difficult it would be to pipe information to
 an arbitrary I/O port. I would like to be able to pipe an information
 file to an I/O port. This information would be received by another
 computer.

 Response:

 This could be accomplished with either of the following methods:

  1. Your application(s) would need two parts. One part would be the
     normal application that provides the I/O and creates the pipe.
     The other part would be a detached process that receives the I/O
     and transfers/outputs the data to the port. This second part
     would have to contain an IOPL segment so that it could
     communicate with the hardware.

  2. Your application again would have two parts. The first and second
     parts are the same as above except that the detached process no
     longer needs IOPL privilege because it communicates with a device
     driver, which in turn feeds data to the ports.

 Neither method is trivial, but the first method is probably less
 difficult to implement. The second method has at least one advantage
 in that interrupts are available when using a device driver, where
 they are not available when using IOPL.


 92. Definitions of Tasking Terms (Task vs. Thread)

 Question
    Is "task" a synonym for "thread"? Is "multitasking" the
 same thing as "multi-threading"?

 Response:
    Task is not a synonym for thread. There are two terms
 used in OS/2 to describe programs in execution. The first,
 threads, can be thought of as an unit of execution. They
 own their own stack and registers. They do not own any
 other resources. Threads can access any resources owned by
 the process that created the thread. However, they cannot
 access resources owned by other processes in the system
 other than through Interprocess communication system calls
 (unless those resources were set up to be shared among
 processes, e.g. shared memory). Threads are the unit of
 scheduling within OS/2; therefore, processes with more
 threads get more CPU time.
    The second program in execution, processes, owns
 resources such as memory, semaphores, devices, and files.
 Each process also owns at least one thread of execution
 containing its current state in the system. A process also
 can create other processes, as as well as creating multiple
 threads of execution within itself.
    Yes, multitasking and multithreading mean the same
 thing.


 93. Device Driver Data Segment Header Fields

 Question:
    On Page 78 of the device driver guide, the device driver
 header structure is defined. The fourth field in the header
 is labeled "reserved". This field was the offset to the
 interrupt routine in DOS 3.x. The OS/2 documentation
 describes no such equivalent. Is this field the interrupt
 routine offset?

 Response:
    The reserved field is not used for the interrupt handler
 in OS/2. This is because more than one interrupt can be
 hooked to a particular device in OS/2. Because interrupts
 can be shared (or not shared), it may be possible that OS/2
 will refuse to allow a process to hook an interrupt.
    To register a hardware interrupt handler, use the
 DevHlp_SETIRQ call (see Page 358 of the device driver
 guide).


 94. Definitions of the Terms Program, Application, and Process

 Question:
    Are "program" and "application" synonyms for "process"?

 Response:
    No. Program, application and process are terms that have
 unique meanings within OS/2.
    An application is something you buy from a software
 company. Applications can contain more that one .EXE file
 and, therefore, more than one program.
    A program is an .EXE file that can be run either from
 the command shell or from another program using the
 DOSEXECPGM system call. A program contains at least one
 process, and each process owns at least one thread.
    Processes own resources such as memory, semaphores,
 devices, and files. Each process also owns at least one
 thread of execution that contains its current state in the
 system. A process also can create other processes, as well
 as creating multiple threads of execution within itself.


 95. OS/2 SDK: Floating Point 80387 Coprocessor Run-Time Problems

 Problem:

 After installing the OS/2 Software Development Kit (SDK) Version 1.05,
 my program, which previously worked correctly under SDK Version 1.03,
 now returns the following error:

    run-time error M6101:  MATH
    - floating point error: invalid

 Response:

 The above problem will occur with any machine that attempts to use the
 80387 coprocessor with OS/2 SDK Version 1.05. Microsoft has confirmed
 this to be a problem in Version 1.05. This problem was corrected in
 OS/2 SDK Version 1.06.

 There is a patch available in the Software Library to correct this
 problem with the OS/2 SDK Version 1.05. This file can be found by
 searching on the filename 386387.ARC, the Q number of this article, or
 S12063.

 386387.ARC has been archived with PKARC, so you will need to unarchive
 it with PKXARC. The 386387.ARC file contains the file 386_387.PAT. To
 install the patch, run the PATCH.EXE utility that comes with OS/2 on
 the file 386_387.PAT.

 Specifically, with PATCH.EXE on your path, enter the following command
 at the command prompt and then reboot your machine:

    patch 386_387.pat /a

 The SDK demos\apps\mandel\mandel.exe file also returns this error, and
 a simple C program (compiled with /AL /Lp /Od /Zi) such as the
 following also causes the machine to hang, forcing a power down to
 restart:

      #include <stdio.h>
      main()
      {   double x;
       x = 3.4;
       x += 7.2;
       printf("X = %f\n",x);
      }


 96. Interrupt Handling

 OS/2
 ISVONLY |

 Question:
    Does OS/2 provide a capability to handle interrupts at
 the application (not device driver) level? If so, does it
 also provide a capability to guarantee that an application
 buffer will remain permanently in memory for DMA
 operations?

 Response:
    To access interrupts, you must write a device driver and
 use the SetIRQ DevHelp call to set up the interrupt handler
 routine. To lock a segment while doing DMA, use the Lock
 and Unlock DevHelp routines within the device driver. (This
 method must be used because the device drivers are kept
 resident in the kernel and, therefore, are not swapped out
 as ring 3 code can be. If they were swapped out, it would
 increase the interrupt latency time greatly if the code to
 service the interrupt had to be swapped in at interrupt
 time. Also, code that handles interrupt has to have IOPL
 privilege level that ring 3 code does not have.)
    The tools supplied with the OS/2 SDK currently do not
 enable debugging at kernel level, the level at which device
 drivers operate. Tools will be supplied in a future update
 to the SDK to enable debugging of device drivers.


 97. Keystroke Monitor Example

 Question:
    Could you show us an example of DOSMONOPEN, DOSGETINFOSEG,
 DOSMONREG, DOSMONREAD, DOSMONWRITE, and DOSMONCLOSE usage?

 Response:
    See the MONITORS example program that came with the OS/2 Software
 Development kit for example of a keyboard device monitor.


 98. B1 and B2 Stepping Regarding 286 and 386

 Question:
    What are "B1 and B2 stepping" with regard to the 286 and 386?

 Response:
    They refer to different versions of the chip. MS OS/2 works with all known
 production levels of the 286 and 386, so these terms aren't important in this
 case.


 99. Hercules Display Adapter Support

 Question:
    Is graphics mode on the Hercules display adapter supported by MS OS/2,
 including the Presentation Manager?

 Response:
    The SDK does not currently support Hercules specific modes. Any OEM who
 licenses MS OS/2 can add support for additional peripherals.


 100. Using Named Pipes with DosBufReset() and DosWriteAsync()

 Question:

 I have a message-named pipe. When I write to it, I use DosWrite(). Is
 it necessary to do a DosBufReset() before doing a
 DosDisconnectNmPipe()? So far the client has already closed the pipe,
 breaking the connection; therefore, DosBufReset() is always returning
 a broken-pipe error code. This seems to be an unnecessary call. Is
 DosBufReset() necessary only with DosWriteAsync()?

 Response:

 Yes, you still may need to do a DosBufReset() before doing a
 DosDisconnectNmPipe(). If the server application has written the last
 piece of data to the pipe and the client reads this data and realizes
 that it has to close the pipe, you still need the flush. It would be
 possible for the server application to write the last piece of data,
 then disconnect the pipe before the client actually reads the "EOF"
 information that was just written (pipes can have write-behind
 capabilities; see below for more information).

 DosWriteAsync() is very different. The DosBufReset() wouldn't be
 useful until after the DosWriteAsync() semaphore has been cleared.
 DosWriteAsync() simply postpones the call to DosWrite(). In other
 words, when you call DosWriteAsync(), a thread is created that will in
 turn call DosWrite(). So, you don't have to wait for the DosWrite() to
 complete, but this also means that the data may not get written until
 the semaphore gets cleared. DosBufReset() has no effect on data that
 hasn't actually been written.

 You could get DosWriteAsync() functionality simply by queuing up all
 write requests (e.g. in a linked list) and having a thread dedicated
 to "DosWrite-ing" all the requests (in any order that you choose). If
 you coded this properly, it would be better than DosWriteAsync(),
 because DosWriteAsync() creates threads (and stacks) and destroys them
 all the time. There are other limitations of the call that could also
 be improved upon, i.e., FIFO type of writing, etc.


 101. High-Density Disks Required for OS/2

 Question:

 Why is a high-density floppy disk required for MS OS/2?

 Response:

 The disk is required because all the files needed to boot the
 installation disk will not fit on a low-density disk. Once MS OS/2 is
 installed on the hard disk, the high-density disk drive is no longer
 needed.


 102. OS/2 SDK: MouOpen() Handle Value Information

 Problem:

 When issuing a MouOpen() call multiple times in the same screen group,
 the handle that is returned from the first MouOpen() call is different
 than the handle returned by the second MouOpen() call. I thought that
 the same handle would be returned by each of the MouOpen() calls if
 they were issued in the same screen group.

 Response:

 Each process is required to do a MouOpen() call. It is not possible to
 pass this handle on to any other process. Each process within a screen
 group will be getting a handle to the same logical mouse, but the
 handle value itself may be different. No process should rely on a
 specific value of the mouse handle. Each process should just call
 MouOpen(), verify that the call did not return an error, then use the
 mouse handle that is returned on all later calls to MOU routines that
 require a mouse handle, without caring what the specific value of the
 handle is.


 103. Managing Instance Data

 Question:
    Please provide detailed documentation AND a sample
 program (in C or assembler) that demonstrates how to create
 and manage instance data in a user created dynalink
 module.

 Response:
    Unfortunately, creating and managing instance data in
 dynalink libraries is not well described in the current
 documentation. This will be fixed in the next update to the
 SDK. The next update will also provide sample programs to
 demonstrate dynalink libraries as well as managing instance
 data.


 104. Writing a Keyboard Monitor, DosMonReg Call

 OS/2
 ISVONLY |

 Question:
    I am trying to write a keyboard monitor, but am having
 trouble with the DosMonReg call. On Page 175 of the SDK
 programmer's reference, it describes the "Index" parameter
 of this call as "a word that specifies a device-specific
 value." What does this mean? What value should I be giving
 to this parameter?

 Response:
    The meaning of "Index" depends on what device the
 monitor is for. For the keyboard, it is the ID for the
 screen group to be monitored. This information can be found
 on Page 42 of the SDK device driver guide. Since a keyboard
 monitor will probably be run by being DETACHed, it will
 have no screen group associated with it--hence your
 application will want to know the ID of the current
 foreground screen group. This can be found by using the
 DosGetInfoSeg call. This call will return addresses for
 local and global information segments; the "Current
 Foreground Screen Group" field in the global infoseg
 contains the value that should be used for the "Index"
 parameter of DosMonReg.


 105. Running MS OS/2 on IBM PC-XTs

 Question:
    We are upgrading our IBM PC-XTs with accelerator cards
 containing an 80286. Will we be able to run MS OS/2 on
 these machines?

 Response:
    If the accelerator board manufacturer provides a version
 of MS OS/2 for the card it could work, depending on the
 hardware. The standard SDK version probably will not work,
 because the XT has a different hard disk controller and
 interrupts.


 106. Hardware That Supports MS OS/2

 Question:
    What hardware technology best exploits the capabilities
 of MS OS/2? For example, is a 12 MHz Compaq Deskpro 286
 faster than a 10 MHz PS/2 model 60?

 Response:
    This is a very complex question and depends on your
 application. Obviously if your application is largely CPU
 bound then a 12 MHz CPU is better than 10. If your
 application is disk bound then look at disk seek and
 transfer rates. If you expect to use the Presentation
 Manager heavily look at the quality of the graphics
 displays available.


 107. Running MS OS/2 on a 386

 Question:
    Will MS OS/2 run on a 386-based machine? It was stated
 MS OS/2 does not save the extended register set when
 performing a context switch. Although MS OS/2 does not
 necessarily have to "take advantage" of 386-specific
 instructions, shouldn't it be "aware" of the fact that it
 is running on a 386 and adjust accordingly?

 Response:
    MS OS/2 runs on a 386 and can take advantage of the mode
 switch capabilities of the 386. Other than that, the
 current version of OS/2 does not exploit 386 specific
 features, but runs as a fast 286. There is no 32 bit
 support at the application level.


 108. Mode Switching Using 286 Pin Compatible 386

 Question:
    In light of the way mode switching has been implemented on a 80286,
 how much of a performance improvement might there be if an IBM-AT
 (8 MHz) had an 80286 pin-compatible 80386 installed?

 Response:
    The mode switching technique is an OEM specific item; OEMs will
 choose the fastest way appropriate to their hardware. There is nothing
 in MS OS/2 that assumes a particular technique. In most cases the
 overhead of mode switching is negligible and not detectable, so even
 if you have a much faster mode switch method you may not detect any
 overall improvement in system performance for your particular
 environment.


 109. Disk Space Needed for OS/2 SDK and Swap File

 Question:
    How much disk space will be needed for the full MS OS/2 SDK and a
 swap file?

 Response:
    The first release contains 8 1.2 megabyte floppies, not all of which are
 filled to capacity. Subsequent releases, especially those with the
 Presentation Manager, will need more. The swap file is usually less than 1
 megabyte unless you are swapping heavily (not recommended). So, generally,
 if you have 10 megabytes available you should be safe.


 110. Error When Running Two Programs with the Same Name

 OS/2
 ISVONLY |

 Question:
    Does running two programs with the same name cause an error?

 Response:
    In the SDK release, if a program is loaded and running in the system, an
 invocation of a different program with the same name as that contained in the
 program module will run a second copy of the existing program module without
 searching the disk. The result is that the second process may end up running
 the wrong program.
    The name in the program module is defined by the "NAME" statement in the
 linker definition file. This prevents renaming a program after it has been
 linked. The temporary solution is to not rename a module after it has been
 linked. This problem will be corrected in an update to the OS/2 SDK.


 111. Summary of the Functions in Each Dynamic Link Library

 Question:

 On the OS/2 setup disk there are a number of dynamic link libraries
 (DLLs). Could you describe the function of each library?

 Response:

 The dynamic link libraries are used by the system to perform the
 system functions of OS/2. The following is a summary of the functions
 in each library.

 The following libraries contain the base subsystem calls for each
 device. These libraries are used by the associated API libraries:

 Library              Device

 BKSCALLS.DLL         Keyboard
 BMSCALLS.DLL         Mouse
 BVSCALLS.DLL         Video

 The following contain the API functions for the various sections of
 the system:

 Library               Function

 DOSCALL1.DLL          Ring 3 DOS functions (DOSXxx)
 ANSICALL.DLL          ANSI screen control (used by BVSCALLS
                                            and BKSCALLS)

 VIOCALLS.DLL          Video Input / Output (VioXxx)
 KBDCALLS.DLL          Keyboard functions (KbdXxx)
 MONCALLS.DLL          Monitor (MonXxx)
 MOUCALLS.DLL          Mouse calls (MouXxx)
 QUECALLS.DLL          Queue calls (QueXxx)
 IPCCALLS.DLL          LAN Manager calls (on LAN Manager disk)

 MSG.DLL               Message Retriever (MsgXxx)
 NLS.DLL               National Language Support (NlsXxx)
 SESMGR.DLL            Session Manager (screen-switching support
                                        for shell)

 SPOOLCP.DLL           Used for the calls that are shared between
                       the spooler routines and the print routines


 112. Value Returned Is FEOOH ORed with Error Code

 Page 81 of the "Microsoft Operating System/2 Software Development Kit
 Device Drivers Guide" is incorrect. The middle of the page incorrectly
 states that the error code that is returned is FEOOH ANDed with the
 error code. It should state that the value returned is FEOOH ORed with
 the error code.


 113. Running Programs in Protected Mode

 Question:
    When running in the protected mode, how does the system know to run
 programs in the DOS compatibility environment?

 Response:
    It doesn't; the user has to switch to the DOS compatibility environment
 in order to run real mode applications.


 114. List of Programs Not Running

 Question:
    Will you publish a list of programs that do not run in compatibility
 environment?

 Response:
    This will depend in part on the characteristics of the underlying
 hardware. We expect OEM hardware manufacturers will adapt MS OS/2 to
 their hardware and provide information on compatibility, just as they
 do today with DOS 3.x.


 115. Installing a Mouse

 Problem:

 We have been unable to get any OS/2 or real-mode application to
 recognize a Microsoft serial mouse on the COM1: port. We have an entry
 in our CONFIG.SYS that looks like the following:

    device=c:\os2sys\mousea02.sys mode=b

 The driver loads correctly (per messages at OS/2 startup), but any
 applications that use the mouse (CodeView for example) do not
 recognize it as being installed.

 Response:

 You need to also install the POINTDD.SYS device driver in your
 CONFIG.SYS file. The CONFIG.SYS file should contain the following two
 lines:

    device=pointdd.sys
    device=mouseaXX.sys   where XX is either 02,03,04 depending on
                          the type of mouse you have on your machine
                          (see the supplement to the installation guide
                          for information on which driver to use with
                          your mouse)


 116. Mode Switch Time Penalty on 386

 Question:
    What is the mode switch time penalty on a 386?

 Response:
    See the Intel 80386 Programmer's Reference Manual, Section 14.5, for a
 description of the general method used to mode switch a 386. We use something
 similar to this. You could estimate the time from this description and a
 knowledge of your machine's CPU and memory performance. Mode switching is not
 an atomic item you can observe in MS OS/2 since it is normally part of a task
 switch that involves many other things in addition to switching the CPU.


 117. OS/2 Needs Device Larger Than Disk

 Question:

 Is there any reason why an MS OS/2 workstation practically requires a
 hard disk? Can MS OS/2 swap over the network?

 Response:

 MS OS/2, with all the utility programs, is bigger than one disk, so
 you need some larger device to put the software on. This could be a
 network device. Likewise the swapper uses a file specified in
 CONFIG.SYS. This file could reside over the network if your network
 has sufficient performance to be used as a swap device.


 118. Using DosLoadModule() with a File Extension to Load DLL

 Question:

 Is it true that DosLoadModule() will not load a DLL (Dynamic Linked
 Library) if a file extension is provided for the module name (even if
 the extension is .DLL)?

 Response:

 Normally, DosLoadModule() will not accept a filename with an
 extension, even a .DLL extension. The exception to this rule is when a
 path is specified. Starting with OS/2 Version 1.10 (OS/2 SDK Version
 1.06), a pathname can be specified to a module loaded by the
 DosLoadModule() call. In this case, the extension, if one exists on
 the filename, is REQUIRED. For instance, assuming that
 LIBPATH=c:\os2\dll;c:\dll, the following module names are valid with
 DosLoadModule():

 Filename                               Module Name Parameter
 ---------------------------------------------------------------------
 c:\dll\module.dll                      "module"
 c:\dll\module.dll                      "c:\\dll\\module.dll"
 c:\app1\xxx.dll                        "c:\\app1\\xxx.dll"
 c:\app1\yyy                            "c:\\app1\\yyy"
 c:\app1\courier.fon                    "c:\\app1\\courier.fon"

 The following would NOT be valid:

 Filename                               Module Name Parameter
 ---------------------------------------------------------------------
 c:\dll\module.dll                      "module.dll"
 c:\dll\module.dll                      "c:\\dll\\module"
 c:\app1\xxx.dll                        "xxx.dll"

 Note: When the module either is not on the LIBPATH or does not have a
 .DLL extension, you must specify the full path, including the file
 extension, to DosLoadModule(). Also note the use of the double
 backslashes when using strings in the C language.


 119. BIOS Dependencies

 Question:
    Microsoft has stated several times that MS OS/2 does not
 depend upon the ROM BIOS. The compatibility environment
 does depend on the BIOS, however. Is this IBM's CBIOS or
 ABIOS?

 Response:
    Whether to implement device driver code in ROM or RAM is
 an OEM decision. On the PC/AT version (i.e., the SDK
 version) certainly we do utilize some of the ROM routines
 when running in the compatibility environment. Other OEM
 manufacturers could decide not to do this. MS OS/2 has no
 inherent dependency on driver code being in ROM.


 120. Applications That Use the EGA

 Question:
    Are there any known problems running DOS 2.x/3.x applications that use the
 EGA in the DOS compatibility environment?

 Response:
    Yes, some of the EGA registers are write-only and if the application uses
 those registers the state of the screen may not be fully restorable after a
 screen switch. Some newer EGA implementations are correcting this problem and
 we expect OEM manufacturers will take advantage of the enhanced hardware.


 121. Monitor Applying to a Screen Group

 Question:
    Does a monitor apply only to a screen group, or is it system-wide?

 Response:
    For the screen group virtualized devices (e.g. KBD, mouse) there is a
 monitor chain per screen group. For the global devices (e.g. printer) there i
 one chain per device. You can register on any chain(s).


 122. Detecting Other Device Monitors

 Question:
    Is it possible to determine if other device monitors are installed?

 Response:
    No, it is not possible at this time.


 123. Installable File System (IFS)

 Question:
    When is a replacement file system anticipated? Will it have features beyon
 just breaking the 32 megabyte barrier such as longer file names, mixed case
 file names, and links?

 Response:
    A later version of MS OS/2 will have an installable file system (IFS) that
 may have some or all of the features mentioned. The 32 megabyte limitation ma
 be eliminated sooner.


 124. MS OS/2 Interrupting Applications

 Question:
    How does MS OS/2 determine how often real mode applications will be
 interrupted?

 Response:
    They are scheduled similar to foreground protected mode tasks. The
 scheduler is driven off a periodic clock tick.


 125. OS/2 SDK: QuickHelp DosExecPgm() Documentation Error

 The example in the QuickHelp database included with the Version 1.06
 OS/2 Software Development Kit (SDK) for the OS/2 API DosExecPgm() has
 a typographical error in it. In this example, the third parameter, the
 synchronous/trace flags parameter, uses "EXEC_ASYNCH". It should
 instead use "EXEC_ASYNC". This error will be corrected in a future
 release of the QuickHelp database.

 Thus, the correct example for the DosExecPgm() API should be as
 follows:

 CHAR achFailName[128];
 RESULTCODES rescResults;
 DosExecPgm(achFailName,                 /* object-name buffer */
     sizeof(achFailName),                /* length of buffer   */
     EXEC_ASYNC,                         /* async flag         */
     "abc = 0\0",                        /* argument string    */
     0,                                  /* environment string */
     &rescResults,                       /* address of result  */
     "abc.exe");                         /* name of program    */


 126. FLAGS Is Not Preserved in OS/2 Calls

 Question:

 Is it the programmer's responsibility to save and restore the FLAGS
 register on all calls?

 Response:

 All of the OS/2 calls are specified as returning a value in AX, and
 they will preserve the state of all of the registers EXCEPT for the
 FLAGS register. On return from a system call the state of the FLAGS
 register is undefined. However, one exception is made for the
 DIRECTION flag. If the DIRECTION flag is cleared when the call is
 made, it is guaranteed to be cleared when the call returns. It is not
 guaranteed to be returned set if it was set when the call was made.


 127. Keystroke Monitor Data Packet MonFlagWord Documentation Error

 Microsoft has confirmed that there is a documentation error on Pages
 35-36 of the "Microsoft Operating System/2 Device Drivers Guide." On
 Pages 35-36, the guide states the following:

    The low byte of the MonFlagWord contains the original scan code
    as read from the hardware. The high byte of the MonFlagWord
    contains the monitor dispatcher flags.

 The correct description is that the MonFlagWord() lower byte contains
 the monitor dispatcher flags and the high byte contains the original
 scan code.


 128. OS/2 SDK: Mixing the Use of Numbers and Names in .DEF File

 Question:

 I would like to keep some of the functions that must be exported from
 a DLL (dynamic linked library) semiprivate (i.e., use numbered rather
 than named functions). However, I would like other functions to be
 named so that they can be easily called from other applications. Is it
 possible to mix both named and numbered EXPORT statements in the same
 .DEF file? If so, what restrictions are there?

 Response:

 To make a DLL function visible to an application, you must include the
 name in the EXPORTS list in the .DEF file.

 To make a DLL function available, but not visible, use the @ ordinal
 directive, which tells OS/2 to make the function loadable by ordinal
 only and removes the internal name of the function from OS/2's list of
 names for the entry points to the DLL. The ordinal number is specified
 by the programmer. OS/2 does not have defaults for the ordinal
 numbers.

 When an ordinal directive is given for a function, the name of the
 function is not visible to an application. However, if you include the
 directive RESIDENTNAME on the same line as the function export
 declaration, OS/2 will retain the name of the function so that an
 application can call the function either by ordinal or by name.

 As long as the proper syntax is used, there is no restriction on the
 combinations of attributes given to any one function, except that the
 ordinal numbers must be unique within the DLL declarations.


 129. Licensing LAN Manager

 OEMs wishing to license the OS/2 LAN Manager should contact their
 Microsoft account representative. The OS/2 LAN Manager is an OEM
 product and licensing is subject to the terms and conditions of a
 systems software contract.


 130. OS/2 SDK: IPC Support for LAN Manager for DOS 3.x

 Question:

 How can an MS-DOS Version 3.x (3.00, 3.10, 3.20, 3.21, 3.22, 3.30,
 3.30a) application access the pipes from an MS-DOS node to an OS/2
 server? What must be added to MS-DOS to make this possible?

 Response:

 The MS-DOS 3.x program must issue Interrupt 21H, Function 3DH (open
 file), where the filename is of the form \\COMPUTERNAME\PIPE\PIPENAME.
 The program could also use the Family API DosOpen() call with such a
 pathname. The remote pipe handle can now be read and written like a
 normal file or local pipe handle. An additional set of named-pipe
 specific library functions for MS-DOS 3.x supports extended pipe
 functions such as DosPeekNmPipe() and DosTransactNmPipe().

 The MS-DOS 3.x program could either issue Interrupt 21H, Function 3DH,
 or it could use sopen(). The share security flags must be set to
 something other than "0x00". If the assembler interface is used, the
 system must first establish a connection to the server's "IPC$" by
 performing the following command:

    NET USE \\SERVER\IPC$

 DosOpen() may be used only if the application is bound. There is no
 support for the DosOpen() API in real-mode-only applications.


 131. OS/2 SDK: IPC Pipes Are Not Prioritized

 Question:

 Most queuing systems support the concept of priority. Can IPC
 (inter-process communication) pipes be prioritized?

 Response:

 Pipes have no concept of priority. The mailslot API, which is more
 queue-like than pipes, does support priority of queued messages.


 132. OS/2 SDK: Pooling Devices and Using Remote Ports

 Question:

 Will special networking features such as pooling devices or using
 remote COM and LPT ports require that both the server and workstation
 run OS/2 and LAN Manager Version 1.00, or must just the server run
 OS/2 and LAN Manager Version 1.00?

 Response:

 Printer pooling for spooled print service requires a LAN Manager
 server. Existing MS-NET or IBM PC LAN workstations can print to a LAN
 Manager server and take advantage of printer pooling.

 Access to remote COM and LPT devices directly (without spooling)
 requires that both ends be running OS/2 (and therefore LAN Manager).
 This is because the remote device service supports direct I/O to the
 remote device drivers themselves, and OS/2 device drivers have
 different interfaces than MS-DOS drivers.


 133. OS/2 SDK: Client and Server Can Be One and the Same

 Question:

 With named pipes, can the client PC and server PC be one and the same?

 Response:

 Yes; both named pipes and mailslots will work between local processes
 exactly the same way that they work between remote ones. Local named
 pipes and mailslots do NOT require the client PC to be running the
 server software. The client software provides this ability for local
 IPC (inter-process communication). Remote IPC does require that at
 least one of the two ends be running the server-level function.
 Because the server software is a superset of the workstation software,
 any workstation can run both client and server functions.

 Also, in OS/2 Version 1.10, support for named pipes was moved into the
 OS/2 kernel. Thus, local named pipes can be used without the OS/2 LAN
 Manager being installed.


 134. OS/2 SDK: DOS File Sharing Functions

 Question:

 In the DOS compatibility environment, all DOS Int 21H file sharing and
 record locking functions are supported.


 135. OS/2 SDK: Freeing Memory with DosFreeSeg()

 Question:

 I would like clarification on the ability to allocate and free
 segments. I use DosAllocSeg() to generate segments for my data
 storage. I then set the segment by using DosSubSet(), and allocate
 actual memory by using DosSubAllocate(). To return the memory back to
 the operating system, I use DosSubFree() to remove the actual memory
 allocation. Then, when the segment is empty, I use DosFreeSeg() to
 free the actual segment.

 If I do not use DosSubFree(), may I free the entire segment with only
 the DosFreeSeg() function call? When I want to free the segment I have
 finished with the entire memory used in that segment.

 Response:

 Yes, you can use DosFreeSeg() to free up the memory area. The
 following program demonstrates this fact:

 #define INCL_BASE
 #include <os2.h>

 void main(void);

 void main(void)
 {

     SEL     sel;
     USHORT  usSegAttribs = SEG_NONSHARED;
     USHORT  usOffset;

     printf("Result of DosAllocSeg is %u\n",
            DosAllocSeg(200,&sel,usSegAttribs));

     printf("Result of DosSubSet is %u\n",
            DosSubSet(sel,0x0001,200));

     printf("Result of DosSubAlloc is %u\n",
            DosSubAlloc(sel,&usOffset,30));

 /* The above call keeps part of the segment in use to ensure
    that an error will occur if the procedure is invalid.        */

     printf("Result of DosFreeSeg is %u\n",
            DosFreeSeg(sel));

 }

 No errors are returned; therefore, this code is valid. Because you are
 finished with the variables involved in the DosSubAlloc() process,
 there is no need to free them up individually.


 136. OS/2 SDK: Real-Mode and Protected-Mode NetBIOS Drivers

 Question:

 What are the major differences between the real-mode and
 protected-mode NetBIOS drivers? What is the penalty on NetBIOS access
 from protected mode?

 Response:

 The protected-mode NetBIOS allows multiple NetBIOS drivers to be
 installed, even for different kinds of net cards. The interface also
 prevents conflicts among multiple applications accessing the same
 NetBIOS driver. For example, one application cannot reset an adapter
 that another application is using. The protected-mode NetBIOS
 redefines the NCP_POST@ field to be a semaphore handle rather than a
 calling address. All buffer addresses are virtual. Only one
 protected-mode NetBIOS interface is available (Interrupt 5CH).


 137. VioPrtSc() Was Removed from Version 1.10 API.LIB

 The Family API function VioPrtSc() is not included in the 1.10 release
 of API.LIB.

 VioPrtSc() was removed because it was considered unstable, and was
 also listed as an API for systems programs to use, not application
 programs. If you need to use this API, you can move it from the old
 API.LIB to the new one; however, Microsoft does not support this
 change. Otherwise, you can write your own version of VioPrtSc() for
 real mode and link with that library.


 138. OS/2 SDK: Forced User Response from Background Task

 Question:

 Is there any way to interrupt the DOS compatibility environment and
 force a user to respond to a message from a background task or notify
 the user that he or she has mail, no matter what he or she is doing on
 the system at the time?

 Response:

 Yes, the VioPopup() system call is used by a background application
 that needs to immediately display a message to the user without
 becoming the active foreground process.

 For more information on the VioPopup() call, please refer to the
 "Microsoft Operating System/2 Programmer's Reference."


 139. DevHlp Services PortUsage() and PortAccess() Do Not Exist

 Question:

 What is wrong with the Device Helper services PortUsage() and
 GrantPortAccess()?

 Response:

 DevHlp PortUsage() and GrantPortAccess() do not exist as described
 in the "Microsoft Operating System/2 Device Drivers Guide," Pages 294,
 297, 300, and 387-391. These DevHlp services were designed to be used
 on 80386 machines where we have the ability to trap all port I/O
 instructions. On the 80286-based machines, these calls are not needed
 and hence, have not been provided in the SDK release of OS/2. Since
 these two calls have been removed, the VerifyAccess() call has been
 moved from number 29H to 27H.

 The following are some other changes or additions to the DevHlp
 services and function codes:

    DevHlp_RAS			EQU 28H
    DevHlp_AttachDD		EQU 2AH
    DevHlp_AllocGDTSelector	EQU 2DH
    DevHlp_PhysToGDTSelector	EQU 2EH
    DevHlp_RealToProt		EQU 2FH
    DevHlp_ProtToReal		EQU 30H
    DevHlp_EOI			EQU 31H
    DevHlp_UnPhysToVirt		EQU 32H
    DevHlp_TickCount		EQU 33H


 140. OS/2 SDK: Competition for the Same Hotkey

 Question:

 Is it true that if two monitors are contending for the same hotkey and
 neither passes the hotkey on, you have cut out one monitor?

 Response:

 By definition, if one monitor chooses not to pass on a packet, then
 subsequent monitors will not see the packet.


 141. OS/2 SDK: Third-Party Compilers and Languages

 Question:

 Are current third-party compilers, etc., usable in the MS OS/2
 compatibility environment? Will the resulting application execute
 after LINK and BIND?

 Response:

 Yes, many real-mode language products work in the compatibility
 environment. It is likely that all current language libraries are
 real-mode specific and a bound application using them would not run in
 protected mode.


 142. OS/2 SDK: Timing-Dependent Applications

 Question:

 I understand that timing-dependent DOS applications would not run in
 the compatibility environment because they would be suspended when in
 the background. Does this mean that they may be compatible if they are
 not moved to the background?

 Response:

 When timing-dependent applications are run in the compatibility box,
 they do not behave exactly as they do under MS-DOS.

 First, there is the problem of the user switching away from the
 compatibility box to use an OS/2 screen group. This results in the
 compatibility box being suspended until it becomes the active screen
 group again.

 Another obstacle is the fact that OS/2 is a multitasking operating
 system: the entire CPU is not dedicated to the compatibility-box
 process. The OS/2 applications in the other screen groups still get
 slices of the CPU, as does OS/2 itself. Therefore, the application
 will never have sole possession of the CPU as it does under MS-DOS.


 143. OS/2 1.10 Dualboot Doesn't Work with Compaq's FDISK

 Problem:

 I am trying to install the Version 1.10 OS/2 SDK (Software Development
 Kit). I am using a version of FDISK developed by Compaq. After a
 successful installation of Microsoft OS/2, I tried to install the
 dualboot capability. The actual installation of the dualboot
 capability appeared to be successful. However, when I rebooted my
 computer, I received the following error message:

    Can't find file DBMON.COM

 Response:

 Microsoft has confirmed this to be a problem in OS/2 SDK Version 1.10.
 This problem was corrected in Version 1.10.

 DUALBOOT expects some return codes to be specific values and the
 direction flag to be reset. If these conditions are not met, the error
 above is reported.

 There is a file in the Software Library named DUALBOOT that contains a
 new version of DUALBOOT.EXE that corrects this problem. DUALBOOT can
 be found in the Software/Data Library by searching on the keyword
 DUALBOOT, the Q number of this article, or S12335. DUALBOOT was
 archived using the PKware file-compression utility.

 Keywords: DUALBOOT.ARC S12335.EXE


 144. Communications Packages That Work in Protected Mode Under OS/2

 The communications packages listed below will run in the protected
 mode of OS/2.

 There is a package available as a sample application included with the
 Microsoft OS/2 Final OS/2 SDK (Software Development Kit) Version 1.10
 sample sources on the TOOLKIT3 disk in the following subdirectory:

    \pmsdk\samples\comtalk

 The products listed below are manufactured by vendors independent of
 Microsoft. We make no warranty, implied or otherwise, regarding these
 product's performance or reliability. This information is provided
 only for your convenience.

 The following two packages can be downloaded from an IBM
 bulletin-board system:

 IBM Atlanta BBS @ (404)988-2913

 Directory 8, downloads:

 > LOG200.ARC     110464  09-27-88  Version 2 of LOGICOMM OS/2
                                    Communication Pgm

 > TERMOS2.ARC     52224  08-07-88  OS/2 Comm Prog With D/L
                                    Capabilities

 KERMIT is also available for OS/2. Please contact Columbia University
 for its availability.


 145. OS/2 SDK: DBCS Status and Shift Byte Information

 Listed below is some additional information on the DBCS status and
 DBCS shift bytes of the Keystroke Monitor Data Packet.

 The following bits define the DBCS status byte:

    Bit 0 = 1        Shift status returned without character
    Bit 1 to 4       Reserved = 0
    Bit 5 = 1        On-the-spot conversion requested

    Bit 6 and Bit 7
    ---------------
      0        0     Undefined
      0        1     Interim character
      1        0     Final character; interim character flag off
      1        1     Final character; interim character flag on

 The DBCS shift byte is reserved and is always 0.


 146. OS/2 1.10 COMMAND.COM Corresponds to MS-DOS 4.01 COMMAND.COM

 Question:

 Does the COMMAND.COM that is installed by OS/2 in the root directory
 and in the \OS2 subdirectory correspond to the MS-DOS Version 4.01
 COMMAND.COM?

 Response:

 These two versions of COMMAND.COM provide roughly the same
 functionality. Functions have been added to MS-DOS Version 4.01's
 COMMAND.COM to make it closer in functionality to the OS/2
 COMMAND.COM; however, not everything works exactly in the same way. At
 this time, no list of differences is available.


 147. General Information on OS/2 Swapper

 Question:

 I have the following questions regarding the swapper:

 1. Does the swapper use the standard DISK01.SYS driver? If so, which
    interfaces or functions are used?

 2. In what size blocks does the swapper perform output?

 3. On system initialization, does the swapper "create" a new
    SWAPPER.DAT file?

 4. Are there any swapping performance numbers?

 Response:

 The answers to the above questions are as follows:

 1. Yes, the OS/2 swapper uses the standard DISK0x.SYS driver, and
    communicates with it by using IOCtls.

 2. The swapper writes out only the number of bytes in the segment
    being swapped, rounding out to a sector boundary.

 3. During system initialization, the swapper creates or resizes the
    swap file to 640K (if SWAPPER.DAT already exists). If subsequent
    disk space is needed, the minimum disk space used is whatever the
    allocation size is for the particular hard drive OS/2 is running
    on.

 4. There are no swapping performance numbers because when a memory
    request is issued, the OS/2 memory manager first invokes the memory
    compactor. If a large enough block cannot be created this way, the
    swapper is invoked using an LRU (least recently used) algorithm.
    There are too many dynamic variables involved to come up with any
    reliable performance numbers.

 For more information on the OS/2 swapping scheme, search on the
 following keyword in the OnLine Knowledge Base:

    swapper


 148. Partial List of Changes Between OS/2 Versions 1.00 and 1.10

 Listed below is a partial list of the changes between OS/2 Version
 1.00 and OS/2 Version 1.10.

 1. The following API function calls are new to OS/2 Version 1.10:

    Function Call         Function

    DosCallBack()         Allows a ring-2 call to a ring-3 routine

    DosGetPPID()          Retrieves the PID for a process' parent

    DosGetResource()      Retrieves a resource for a module

    DosQAppType()         Retrieves the type of an executable file

    DosR2StackRealloc()   Reallocates a ring-2 stack

    DosSizeSeg()          Retrieves the size of a segment

    Fast-Safe RAM Semaphore calls (DosFS..) are new.

    Named pipe calls (Dos..NmPipe..) are new.

    Presentation Manager calls (Win.., Gpi.., Dev.., etc.) are new.

    Advanced VIO (AVIO) calls are new. They start with "Vio", except
    for the WinDefAVioWindowProc() function. As part of the support
    for AVIO, the "hvio" parameter to the VIO calls is now used to
    specify a handle to the AVIO presentation space.

 2. The following API function calls were changed in OS/2 Version 1.10:

    a. DosExecPgm() has a new exec flag.

    b. DosExit() now terminates all threads in the process, if thread
       one is exiting, regardless of the fTerminate flag.

    c. DosExitList() now allows some control over the position of the
       function in the exit list chain.

    d. DosGetInfoSeg() has new fields added onto the end of the
       GINFOSEG and LINFOSEG structures.

    e. DosMonReg() has new position codes for monitors with special
       requirements.

    f. DosSetPrty() has a new priority class called "Fixed High" that
       is between Normal priority and Time Critical priority.

    g. DosStartSession() has new fields added onto the end of the
       STARTDATA structure to support Presentation Manager sessions.

    h. VioGetMode() and VioSetMode() have had fields removed from the
       end of the MODEINFO structure.

 3. The following new programming features were added to OS/2 Version
    1.10:

    a. Load-high segments are allowed in device drivers.

    b. Device driver communication is supported (attachdd or IDC).

    c. The device driver helper dh_registerstackusage is new.

 4. Listed below are some of the command differences in OS/2
    Version 1.10:

    a. DDINSTAL was added to aid in installing device drivers on the
       hard disk.

    b. E.EXE, a system editor, was added.

    c. The FORMAT command's /s option has been removed.

    d. The FORMAT command now displays status in percentages rather
       than tracks.

    e. MODE now allows the following baud rates: 1800, 3600, and 7200.

    f. SPOOL was changed to just start the PM spooler.

    g. The START command takes new flags for support of windowed
       command prompts.

    h. The SYS command has been removed.

    i. UNPACK was added to unpack files on the installation disks.

 5. Listed below are some of the configuration differences in OS/2
    Version 1.10:

    a. OS2DOS.COM is renamed to OS2KRNL.

    b. OS2BIO.COM is renamed to OS2LDR.

    c. The SET command is allowed in the CONFIG.SYS file, and allows a
       default environment to be specified for all new processes
       started in the system.

    d. SWAPPATH allows the specification of how much space to attempt
       to leave free on the hard disk.

    e. EXTDSKDD.SYS no longer allows the /C or /N parameter.

    f. Partitions larger than 32 megabytes are allowed.

    g. The Install program is enhanced.



 149. OS/2 SDK: Call Gates

 Gates, which are four-word descriptors, are used as control transfer
 redirectors to a different code segment in the identical or higher
 privileged level in the same task. They can also redirect transfers to
 code segments in different tasks.

 Call gates are specifically used for control transfers that need to be
 transparently redirected or involve an increase in the privilege
 level. For more information on call gates or gates in general, please
 refer to the "Intel 80286 Programmer's Reference Manual."


 150. OS/2 SDK: Multiple Code Segments in a C Code File

 It is possible to declare multiple code segments inside one C code
 file if your language supports multiple code segments. (Microsoft
 languages do.)


 151. OS/2 SDK: 286 Protection Ring

 Currently, nothing runs in 286 protection ring 1; it is reserved for
 future use.


 152. OS/2 SDK: Stack Fault Handling

 Stack faults cannot be restarted on most 286 chips due to a problem in
 the silicon.


 153. OS/2 SDK: DosMemAvail() in a Virtual Memory System

 In a virtual memory system, DosMemAvail() can be used as a hint of the
 memory availability of the system so that applications can modify
 their demands. It is not a complete statistics facility.


 154. OS/2 SDK: Releasing of DLL Modules

 DLL modules are released and the real memory is returned to the system
 when the reference count goes from one to zero.


 155. OS/2 SDK: Avoiding Name Conflicts

 With dynamic links, to avoid name conflicts of added services across
 applications, use a long name with some application or vendor-specific
 component.


 156. Determining Exported Entry Points in A DLL

 Question:

 How difficult would it be to examine a DLL (Dynamic Linked Library)
 and determine the routine names and their parameters?

 Response:

 You can obtain this information by using EXEHDR with the "/v" option.
 The "v" (verbose) option allows you to display all of the exported
 entry points in a DLL.


 157. Implementing Fully Protected/Secure File System

 Question:

 It is stated that a fully protected/secure file system will be
 implemented in the 286 and 386 versions of OS/2. Does this mean that
 to implement true security, all workstations need to be 286 or 386
 machines?

 Response:

 No. The existing LAN Manager product provides a protected file system
 environment on a 286 or 386 for any remote client workstation
 accessing that server, i.e., no remote workstation can access server
 resources not explicitly permitted it. However, there is a limitation
 in that a user local to the server is not subject to permission checks
 (a local user is treated with administrative privilege). The protected
 286 or 386 file system will remove this limitation, allowing a user
 local to a server to be subject to the same permission checking that a
 remote user is.

 Please note that there is a distinction between protected and secure
 file systems. A protected file allows access only if you have
 permission. A secure file system prevents a permitted user from
 passing on information to non-permitted users. In this respect, the
 LAN Manager provides a filing system that is protected relative to
 remote users but not secure.


 158. Linking Made Easier

 Question:
    After years of making DOS and BIOS function calls in high-level
 languages, we now have a system where it is easier to do the function
 calls in high-level languages than in assembler. OS/2 assembly
 language programs seem awkward. It is not so much the pushes (we could
 have macros for those), but every DOS call must be listed in both the
 ASM file (as an external) and the DEF file (as an import). Is there
 something we can link to so we do not need the import listing in DEF?

 Response:
    Yes; link with OS2.LIB. You can create additional imports libraries
 for your own dynlink libraries using IMPLIB.


 159. DosGetEnv Returns Pointer to Asciiz String

 Problem:

 According to Page 126 of the "Microsoft Operating System/2
 Programmer's Reference Guide," DosGetEnv returns the offset of the
 command line start. If I enter "myprog cmdtail" at the OS/2 prompt,
 the command line is "myprog cmdtail". Therefore, I would expect a
 pointer to the string "myprog cmdtail". However, it seems that
 DosGetEnv returns a pointer to the asciiz string "c:\myprog.exe". This
 string seems to always be followed by the asciiz string "cmdtail";
 however, I can't find this documented.

 Response:

 This is a documentation error. The command line pointer is a pointer
 to an argument string that has the same format as the argument string
 passed from DosExecPgm. See Page 17 of the "Microsoft Operating
 System/2 Programmer's Reference Update" for a description of how
 DosExecPgm passes the environment information to a new process.


 160. Problem in Real Mode APPEND Command

 Problem:
    The real mode APPEND command does not work after being used the
 first time with Microsoft OS/2 Version 1.00.

 Response:
    Microsoft is researching this problem and will post new information
 as it becomes available.


 161. OS/2 User's Guide Error in Spool Documentation

 Question:

 How do I use a serial printer under OS/2? I have installed OS/2
 Version 1.02 and the SDK on my PS/2 Model 60. The PS/2 has a single
 parallel port and single async port. I am running with the dual boot
 option installed, with MS-DOS Version 3.30 and OS/2 installed on the
 same hard disk.

 Response:

 The documentation on Page 194 of the "Microsoft Operating System/2
 Beginning User's Guide" is incomplete. The following is the correct
 documentation for the SPOOL command:

 The Spool command initializes the printer spooler to print in the
 background while you are executing other OS/2 commands or programs.
 The following syntax should be used:

 [drive:][pathname] spool [drive2:][pathname2]   [/d:device] [/o:device2]

 [drive:][pathname]  Preceding spool, specifies the drive and path
                     that contains the spool command file.

 drive2:pathname2    Specifies the print spool subdirectory. This
                     is where the temporary spool files will be
                     created. The default is \SPOOL.

 /d                  Specifies the print device. If not specified,
                     the default device is LPT1:.

                     Any character device that supports monitors can
                     be specified. Only the output portion of the
                     device is affected.

                     COM1: and COM3: may not be specified as the input
                     print device since the Async device driver does
                     not support character device monitors. When COM1:
                     and COM3: are specified as the output print device,
                     the spooler uses DosWrite rather than the monitor
                     interface to output the data.

 /o                  Specifies the output print device. If not
                     specified, the default will be the same as the
                     /d: device.

 The Spool utility is a true spooler. It uses the Monitor facility of
 OS/2 to intercept data going to the printer device drivers. The Spool
 utility sorts the data by process so that the printer output is not
 intermixed. Print streams that are not closed (in the process of being
 updated) are placed in temporary files on the disk in the subdirectory
 specified on the Spool command line.

 The Printer Spooler (Spool Utility) serves a single printer device at
 a time. It uses the Character Device Monitor mechanism to intercept
 data passing through a device driver and to insert data back into the
 device driver data stream.

 Since printers are attached to the PC with both parallel and serial
 connections, the printer spooler will support printer devices
 (LPT1->3, PRN) and serial devices (COM1->2, AUX).

 The printer spooler will also support any other character device whose
 device driver contains monitor support compatible with the printer
 device driver.

 The Print command interfaces to the Spool command when the /t or /c
 options are specified on print.


 162. Generic Printer Ioctl

 The "Microsoft OS/2 Device Driver's Guide" documentation on printer
 function 65H (Pages 114 and 214) is incorrect in the function number.
 The correct ioctl function code to return printer status is 66H, not
 65H as documented.


 163. Corrected Version of Microsoft Segmented Executable Format

 There are a number of errors in the EXE file information in the
 "Microsoft Operating System/2 Software Development Kit Programmer's
 Reference" Pages 555-558. A corrected version of this information is
 available in the Software Library. This file can be found in the
 Software Library by searching on the filename SEGEXEC.ARC, the Q
 number of this article, or S12069.


 164. Missing Documentation on Printer Font Monitors

 Several pages of information were omitted from the OS/2 SDK
 documentation. These pages concern the writing of printer monitors to
 monitor the font commands and the data path.

 This missing documentation is available in the Software Library. This
 file can be found by searching on the filename FONTMON.ARC, the Q
 number of this article, or S12117.

 The missing information is as follows:

 Printer/Spooler

 The major functional changes to the printer device driver and the
 spooler in OS/2 Version 1.1 from OS/2 Version 1.0 are to accommodate
 code page and font switching for National Language Support (NLS) by
 providing a generalized printer font handling mechanism.

 Printer/Spooler Overview

 The printer/spooler is structured as shown in the Figure 1 below:

   .-App---Process--.    .-----------Spooler--Process----------.
   | .------------. |    | .--------------. (3) .------------. |
   | |Application | |    | |   Spooler    .----->  Code Page | |
   | |  Program   | |    | |              |     |  Switcher  | |
   | .-----.------. |  .--->  (Monitor)   <-----. (Dynalink) | |
   |       |        |  | | .-.-----A----.-. (4) .------------. |
   .-------|--------.  | .---|-----|----|----------------------.
        (1)|        (2)|  (7)|  (6)|    |(5)
           |           |     |  .--.----V----.
           |           |     |  |Spooled File|
           |           |     |  |   (disk)   |
           |           |     |  .------------.
    - - - -|- - - - - -|- - -|- - - - - - - - - - - - - - - - -
           |           |     |      .--------.         Kernel
           |           |     | (7b) | Async  |
           |           |     . - - -> Device | (8b) .---------.
           |           | (7a)|      | Driver . - - -> Printer |
           |     .-----.-----V.     .--------.      .---------.
           .----->  Printer   |
                 |  Device    | (8a) .---------.
                 |  Driver    .------> Printer |
                 .------------.      .---------.

 Printer/Spooler Structure

 The data flow shown in the printer/spooler structure above is as
 follows:

 1. This flow is the normal API to the printer. The application program
    issues DosOpen, followed by "n" DosWrites/DosIoctls to the printer.
    The file system sends an Open IOCTL to the printer device driver,
    followed by an Activate Font IOCTL. The application program's
    DosWrites go to the printer device driver until a DosClose is issued.

 2. This flow is from the printer device driver to the spooler through
    the MonRead monitor interface. The printer device driver sends an
    Open command buffer, followed by an Activate Font monitor command
    buffer, and then "n" buffers corresponding to the DosWrites.

 3. This flow is via a Call interface to the Font Switcher dynalink
    routine. This occurs when the Activate Font monitor command buffer
    is received by the spooler from the printer device driver as a
    result of the Activate Font Ioctl.

 4. This flow is the return from the call described in the flow
    previously.

    The data returned contains the escape sequences and/or font data
    necessary to cause the printer to perform the actual code page and
    font switch. This data is treated by the spooler as part of, and in
    sequence with, the data being printed by the application program
    and is put into the spool file described in the next flow.

 5. This flow is the data being written by the spooler to a temporary
    spool file on the disk using DosWrites.

 6. The spooler reads data from its temporary spool files on the disk,
    in sequence based on its spool queues, using DosReads.

 7. The spooler sends data to the device driver to be printed using the
    monitor output buffer and MonWrite function interfaces.

     a. If the spooled printer is parallel attached, the spooler sends
        the data back to the printer device driver.

     b. If the spooled printer is async attached, the spooler sends the
        data back to the async device driver.

 8. The device driver sends data to the printer through the hardware
    adapter.

     a. The printer device driver sends the data to parallel attached
        printers.

     b. The async device driver sends the data to async attached
        printers.

 Printer Device Driver Operational Description

 The printer device driver has three new printer specific Ioctl
 commands to support the code page and font switching provided in OS/2
 Version 1.1. All of the actual code page and font switching function
 for printers is provided by the spooler which is a printer device
 driver monitor. In addition, in order to support these new Ioctls,
 there are Font Monitor Buffer Command/responses added to the monitor
 interface to the spooler. The functions provided by the Ioctls and
 Font Monitor Buffer Command/responses are:

 1. Activate Font

 2. Query Active Font

 3. Verify Font

 These Ioctls and monitor code page and font buffer command/responses
 are described in detail elsewhere in this item.

 1. Activate Font

    Using Figure 1 as an illustration, when an application within a
    process issues a DosOpen for a printer, i.e., LPT1, LPT2, LPT3 or
    PRN, the file system issues an Activate Font Ioctl to the printer
    device driver to set the active code page and font according the
    active code page of the process making the open request.

    An application within a process may also issue the Activate Font
    Ioctl to the printer device driver by using the handle returned
    from the DosOpen at any time. This allows the application to change
    the active code page and font in the middle of its print job.

    When the printer device driver receives the Activate Font Ioctl, if
    the spooler or another monitor is registered, the printer device
    driver will use the Font Monitor Buffer Command to send the Activate
    Font command to the registered monitor in its monitor input buffer.
    If the spooler, or another monitor, is not registered the printer
    device driver will return the appropriate return code to the caller
    of the Activate Font Ioctl.

 2. Query Active Font

    When the printer device driver receives the Query Active Font
    Ioctl, if the spooler or another monitor is registered, the printer
    device driver will use the Font Monitor Buffer Command to send the
    Query Active Font command to the registered monitor in its monitor
    input buffer. The monitor will return the active code page and font
    information to the printer device driver in its monitor output
    buffer. The printer device driver then returns the active code page
    and font information to the caller of the Query Active Font Ioctl.

    If the spooler, or another monitor, is not registered the printer
    device driver will return the appropriate return code to the caller
    of the Query Active Font Ioctl.

 3. Verify Font

    When the printer device driver receives the Verify Font Ioctl, if
    the spooler or another monitor is registered, the printer device
    driver will use the Font Monitor Buffer Command to send the Verify
    Font command to the registered monitor in its monitor input buffer.
    The monitor will return whether the specified code page  and font
    is valid to the printer device driver in its monitor output buffer.
    The printer device driver then returns the return code to the
    caller of the Verify Font Ioctl.

    If the spooler, or another monitor, is not registered the printer
    device driver will return the appropriate return code to the caller
    of the Verify Font Ioctl.

 Printer Device Driver Interfaces

 The interfaces required by the printer device driver for code page and
 font switching are as follows:

       Activate Font Ioctl
       Query Active Font Ioctl
       Verify Font Ioctl
       Font Monitor Buffer Commands
          Activate Font
          Query Active Font
          Verify Font

 These interfaces are described in the following sections.

 Activate Font Ioctl:

    Category 5  Function 48h

    Purpose:   Activate Font

    Parameter Packet Format:

             .------------------------------------.
             |     BYTE Command Information       |
             .------------------------------------.

    Data Packet Format:

             .------------------------------------.
             |     WORD  Code Page                |
             .------------------------------------.
             |     WORD  Font Id                  |
             .------------------------------------.

    Remarks:
    Command Information: This field is currently reserved and must
                         be set to zero.
    Code Page: The value of the code page to make the currently
               active code page.

               0000h     If both the Code Page value and Font Id
                         are specified as zero (0), set printer to
                         hardware default code page and font.

               0001h-FFFFh  Valid code page numbers.

    Font Id: The id value of the Font to make currently active.

              0000h     If both the Code Page value and Font Id
                        are specified as zero (0), set printer to
                        hardware default code page and font.

                        If only the Font Id is specified as zero,
                        any font within the specified code page is
                        acceptable.

              0001h-FFFFh  Valid font id numbers, font types
                           defined by the font file definitions.

    Returns: IF AX = 0

                 NO error

             ELSE

                 AX = Error Code:

                     Code page and font switching not active
                     Unable to access specified font file
                     Unable to locate or activate specified code page
                     Unable to locate or activate specified font

 Query Active Font Ioctl:

    Category 5  Function 69h

    Purpose: Query Active Font

    Parameter Packet Format:

             .------------------------------------.
             |     BYTE Command Information       |
             .------------------------------------.

    Data Packet Format:

             .------------------------------------.
             |     WORD  Code Page                |
             .------------------------------------.
             |     WORD  Font Id                  |
             .------------------------------------.

    Remarks:
    Command Information: This field is currently reserved and must
                         be set to zero.
    Code Page: On return, this word is set to currently active code
               page.

               0000h    If both the Code Page value and Font Id
                        are returned as zero (0), the printer is
                        set to the hardware default code page and
                        font.

               0001h-FFFFh  Valid code page numbers.

    Font Id: On return, the id value of the Font which is
             currently active.

               0000h     If both the Code Page value and Font Id
                         are specified as zero (0), the printer is
                         set to the hardware default code page and
                         font.

                         A Font Id value of zero may indicate the
                         default font of a particular code page.

               0001h-FFFFh  Valid font id numbers, font types
                            defined by the font file definitions.

    Returns: IF AX = 0

                 NO error

             ELSE

                 AX = Error Code:

                     Code page and font switching not active

 Verify Font Ioctl:

    Category 5  Function 6Ah

    Purpose: Verify that a particular code page and font is available for the
            specified printer.

    Parameter Packet Format:

             .------------------------------------.
             |     BYTE Command Information       |
             .------------------------------------.

    Data Packet Format:

             .------------------------------------.
             |     WORD  Code Page                |
             .------------------------------------.
             |     WORD  Font Id                  |
             .------------------------------------.

    Remarks:
    Command Information: Reserved, must be set to zero.

    Code Page: The Code Page number to validate.
               Values may be 0 to 65535.

    Font Id: The Font Id value to validate.
             Values may be 0 to 65535.

    Note: A value of zero (0) for both the Code Page number and Font Id
          indicates the default hardware code page and font; this
          combination is always valid.

    Returns: IF AX = 0

                 NO error, Code Page is valid

             ELSE

                 AX = Error Code:

                     Code page and font switching not active
                     Code Page not valid
                     Font Id not valid

 Font Monitor Buffer Commands:

 Printer Monitor Record:

 Each monitor record can be of variable length. However, there must be
 a word of flags at the beginning of each monitor record. The flags are
 defined as follows:

       Monitor Flags

                                                 Device Driver
          Byte 0                       Byte 1    Dependent
    .--.--.--.--.--.--.--.--.    .--.--.--.--.--.--.--.--.
    | 7| 6| 5| 4| 3| 2| 1| 0|    | 7| 6| 5| 4| 3| 2| 1| 0|
    .--.--.--.--.--.--.--.--.    .--.--.--.--.--.--.--.--.
      A           A  A  A  A       A              A  A  A
      . Reserved -.  |  |  |       .-- Reserved --.  |  |
                     |  |  |                         |  |
                     |  |  .- Open                   |  |
 |                   |  .- Close  Code Page Command -.  |
 |                   .- Flush        Processed          |
                                                        |
                       Printer Code Page Monitor -------.
                       Buffer Command/Response

 When the Font Monitor Buffer Command bit is set to 1 (byte 1, bit 0),
 this indicates that the monitor buffer is a Font Monitor Buffer
 Command or a response to a previous Font Monitor Buffer Command. In
 this case, the next six bytes are as follows:

      Byte 2 & 3
    .-------------------------------------------.
    |            ProcessId                      |
    .-------------------------------------------.

      Byte 4               Byte 5
    .--------------------.----------------------.
    |  Command  Byte     |  Reserved, Set to 0  |
    .--------------------.----------------------.

      Byte 6 & 7
    .-------------------------------------------.
    |       Reserved,  Set to 0                 |
    .-------------------------------------------.

    Byte 2 & 3  Process Id WORD

    Byte 4    Font Monitor Buffer Command Byte which indicates the type of
              command or response.

    Byte 5    Reserved, and must be set to zero (0).

    Byte 6 & 7  Reserved WORD, must be set to zero (0).

 When the Code Page Command Processed bit is set to 1 (byte 1, bit 1),
 this indicates that the Font Monitor Buffer Command has been processed
 by the spooler.

 The valid Font Monitor Buffer Commands, along with the remainder of
 the buffer contents for the responses, are as follows:

    Byte 4 = 01h  Activate Font

             Command Data, starting at byte 8:

               .------------------------------------.
             08|     WORD  Return Code              |
               .------------------------------------.
             0A|     WORD  Code Page                |
               .------------------------------------.
             0C|     WORD  Font Id                  |
 |             .------------------------------------.
 |           0E|     DATA to print (optional)       |
 |             =                                    =
               .------------------------------------.

    Code Page: The value of the code page to make the currently active
               code page.

               0000h  If both the Code Page value and Font Id are
                      specified as zero (0), set printer to
                      hardware default code page and font.

               0001h-FFFFh  Valid code page numbers.

    FontId: The id value of the Font to make currently active.

               0000h  If both the Code Page value and Font Id are
                      specified as zero (0), set printer to
                      hardware default code page and font.

                      If only the Font Id is specified as zero,
                      any font within the specified code page is
                      acceptable.

               0001h-FFFFh  Valid font id numbers, font types defined
                            by the font file definitions.

    Data: Optionally, data to be printed may follow the FontId of the
          Activate Font Font Monitor Buffer Command. The length of the
          buffer indicates that there is data following the command.

          The response is a return code WORD value starting at byte 8,
          and includes the following values:

          Successful completion
          Code page and font switching not active
          Unable to access specified font file
          Unable to locate or activate specified code page
          Unable to locate or activate specified font

    Byte 4 = 02h  Query Active Font

             There is no additional command data.

             The response is as follows:

               .------------------------------------.
             08|     WORD  Return Code              |
               .------------------------------------.
             0A|     WORD  Code Page                |
               .------------------------------------.
             0C|     WORD  Font Id                  |
               .------------------------------------.

             Return Code: A WORD value starting at byte 8, and includes
                          the following values:

                          Successful completion
                          Code page and font switching not active

             Code Page: The value of the currently active code page.

                        Valid numbers are between 0 and 65535.

                        A value of 0 for both the code page and font id
                        indicates that the hardware default code page
                        and font is active.

             Font Id: The id value of the currently active font.

                      Valid numbers are between 0 and 65535.

   Byte 4 = 03h  Verify Font

             Command Data, starting at byte 8:

                .------------------------------------.
             08 |     WORD  Return Code              |
                .------------------------------------.
             0A |     WORD  Code Page                |
                .------------------------------------.
             0C |     WORD  Font Id                  |
                .------------------------------------.

             Code Page: The value of the code page to validate.

                        Values may be 0 to 65535.

             FontId: The Font Id to validate.

                      Values may be 0 to 65535. A value of zero
                      indicates that any font within the specified
                      code page is acceptable.

 The response is a return code WORD value starting at byte 8, and
 includes the following values:

     Code page and font valid
     Code page not valid
     Font not valid
     Code page and font switching not active
     Unable to access specified font file

 Spooler
 DOS Version 3.x Box Force Output to Printer

 The print spooler spools the printer output until a DosClose is
 issued. When printing from the DOS 3.x box, many applications use the
 INT17 interface which does not require DosOpen/DosClose's. In this
 case, the printer output is spooled until the program exits. The user
 may press CTL-ALT-PRTSCRN (while the DOS 3.x box is in the foreground)
 to force printed output to be printed from DOS 3.x box applications.

 Spooler Operational Description

 The Spooler uses a dynalink module called the Font Switcher to perform
 the code page and font switching.

 Initialization:

 When the Spooler is invoked by the user (user command SPOOL), it
 accesses the system data structure which contains the code page and
 font information provided by the DEVINFO command in CONFIG.SYS. If
 DEVINFO code page and font information is present for the specified
 printer name (LPTx or PRN) in the code page and font data structure,
 the spooler will call the Dos_PFS_Init entry point of the Font
 Switcher dynalink module to initialize font switching. Once the
 Spooler and Font Switcher have completed initialization, print
 spooling along with code page and font switching are enabled for the
 specified printer.

 If the DEVINFO code page and font information are not present in the
 code page and font data structure maintained by the system for the
 specified printer name, the spooler completes its initialization
 without initializing the Font Switcher for the specified printer. In
 this case spooling is enabled for the specified printer, however, code
 page and font switching are not.

 Activate Font:

 When an Activate Font Font Monitor Buffer Command is received by the
 spooler for a specific Process ID, the spooler calls the
 Dos_PFS_Activate entry point of the Font Switcher. The Font Switcher
 changes the active code page and font for the Process ID/handle, and
 uses the font file to cause the code page and font switch to occur.
 The code page and font switch occurs in one of the following ways
 depending on the font support provided by the target printer:

 1. If the specified font is contained in the printer hardware (ROM or
    cartridge, as specified by the DEVINFO command CONFIG.SYS), the
    Font Switcher writes the escape sequence required to switch the
    printer to this hardware font directly into the temporary spool
    file. The escape sequence necessary to perform this switch is
    available for the Font Switcher in the font file specified for the
    printer.

 2. If the specified font is not contained in printer hardware, and the
    printer allows multiple downloadable fonts, the Font Switcher will
    determine which font buffer to download the font to. The Font
    Switcher writes the escape sequence required to download a font to
    the printer to a font buffer in the printer along with the font
    information, followed by the escape sequence which changes the
    printer's active font buffer directly into the temporary spool
    file. If the Activate Font command specifies a font that has been
    previously loaded into a font buffer other than the one which is
    currently active, the Font Switcher writes the escape sequence
    required to switch the printer to the desired font buffer directly
    into the temporary spool file.

    All escape sequences and font information required are available
    for the Font Switcher in the font file specified for the printer.

 3. If the specified font is not contained in printer hardware, and the
    printer allows a single font to be downloaded, the Font Switcher
    writes the escape sequence required to download a font to the
    printer to a font buffer in the printer along with the font
    information directly into the temporary spool file.

    All escape sequences and font information required are available
    for the Font Switcher in the font file specified for the printer.

 Query Active Font:

 When a Query Active Font Font Monitor Buffer Command is received by
 the spooler for a specific Process ID, the spooler calls the
 Dos_PFS_Query_Act entry point of the Font Switcher. The
 Dos_PFS_Query_Act function returns the active code page and font for
 the specified Process ID(/handle) to the spooler. The spooler returns
 the information to the printer device driver using the Query Active
 Font Font Monitor Buffer Response. The printer device driver then
 returns the information to the Query Active Font Ioctl caller.

 Verify Font:

 When a Verify Font Font Monitor Buffer Command is received by the
 spooler for a specific Process ID, the spooler calls the
 Dos_PFS_Verify_Font entry point of the Font Switcher. The
 Dos_PFS_Verify_Font function returns whether the specified code page
 and font is available in the font file for the specified printer.

 Spooler Interfaces

 The interfaces required by the spooler for code page and font
 switching are as follows:

    System code page and font information
    Font Monitor Buffer Commands

    Activate Font
    Query Active Font
    Verify Font

    Font Switcher Dynalink Module

    Dos_PFS_Init             Initialize code page and font
    Dos_PFS_Activate         Activate Font
    Dos_PFS_Query_Act        Query Active Font
    Dos_PFS_Verify_Font      Verify Font
    Dos_PFS_Close_User       Close Font User Instance

 Printer Font File Format

 These interfaces are described in the following sections.

 System Code Page Information:

 The spooler must be able to access the System Code Page Information
 when it is invoked (user command SPOOL) from some system provided data
 segment. The information required is that provided by the CONFIG.SYS
 command DEVINFO. This information includes the printer name, printer
 type, code page, and fonts provided in the printer hardware and the
 path name of the font file to be used.

 Font Monitor Buffer Commands

 The Font Monitor Buffer Commands that provide the code page and font
 switch interface between the printer device driver and the spooler
 monitor are as follows:

 1. Activate Font

 2. Query Active Font

 3. Verify Font

 These commands and their responses are described in detail in "Font
 Monitor Buffer Commands."


 165. DOSMUXSEMWAIT Does Not Work with PHYSTOUVIRT Selectors


 Problem:
    When a Device Driver gives an application access to a portion of
 its Data Segment (via PHYSTOUVIRT) and the application uses that
 storage for RAM Semaphores between it and the Device Driver, the
 application cannot use the MUXSEMWAIT function when RAM Semaphores
 from that Data Segment are included in the Semaphore List. OS/2
 indicates that a General Protection Fault (Trap D) has occurred even
 though the selector of the RAM Semaphore is valid in the LDT.
    SEMWAIT on a single semaphore is able to use that PHYTOUVIRT Data
 Segment successfully but the MUXSEMWAIT does not. Currently,
 MUXSEMWAIT does not allow storage created via PHYSTOUVIRT to be used
 for RAM Semaphores.

 Solution:
    Microsoft is researching this problem for a possible solution to be
 included in OS/2 Version 1.1


 166. Cannot CALL CALL.BAT, but Can CALL CALL.CMD

 Problem:
    Consider two BAT/CMD files named CALL.BAT and CALL.CMD. Each file
 contains the command DIR. When the command "CALL CALL" is entered in
 protect mode, the file CALL.CMD is executed and you get a DIR as
 expected. When the command "CALL CALL" is entered in real mode, the
 file CALL.BAT is not executed at all.
    This same thing happens also in DOS Version 3.30. However, this is
 a problem in Version 3.30, and should be corrected in a future version
 of DOS. The command "CALL" really should have meaning to DOS only when
 it is the first lexical token on a line.


 167. Protect Mode "Dir | More" Requires Two CTRL-BREAKs to Stop

 Problem:
    Protect Mode "dir | more" or "type file | more" requires two
 CTRL-BREAKs to stop. If you press only one CTRL-BREAK, then press any
 key at "-- More --", the process ends without warning before another
 "-- More --" is encountered. The problem may be occurring because a
 new CMD.EXE is exceeded for the DIR command.

 Response:
    Microsoft is researching this problem and will post new information
 as it becomes available.


 168. VioPopUps Can Hang System

 Problem:
    The system hangs if an application does not end a VioPopUp.

 Response:
    Microsoft is researching this problem and will post new information
 as it becomes available.


 169. With ANSI.SYS, ESC in Real Mode Takes Cursor in Wrong Place

 Problem:

 With DEVICE=C:\OS2\ANSI.SYS in CONFIG.SYS, pressing the ESC key on
 the real-mode command line takes the cursor two lines down and 17
 columns to the right on a PS/2 with an 8513 display. The following
 command will be echoed starting from that position. The cursor should
 go to the first position (after the prompt) in the next line, as it
 does without ANSI.SYS in real mode and in protect mode with or without
 ANSI ON. This problem occurs on a PS/2 model 80 with 8513 color
 display, but the problem does not seem to occur on an AT with EGA.
 However, PC-DOS Version 3.30 fails in the same way on an AT with EGA.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.00. We are
 researching this problem and will post new information as it becomes
 available.

 One possible workaround is to place the following commands at the end
 of your prompt, as follows

 $e1s$e1A$_$e1u

 where the three "1" characters are replaced by cents signs, char(155).


 170. Under Topview Copy to Open Drive Hangs System

 Problem:

 Under Topview, the following steps will produce a system hang:

 1. Select command processor.

 2. Copy a file to Drive A with no disk in it.

 The system hangs without giving any message and it has to be powered
 off and back on again.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.00. We are
 researching this problem and will post new information as it becomes
 available.


 171. Mdraw Program Does Not Restore the Screen after VioPopUp

 Problem:
    When using the mdraw program in the MANDEL example, the screen is
 not restored correctly after a VioPopUp occurs. Also, the system
 sometimes locks up when running the program on the new version of OS/2
 (87294) even though it ran properly on the old OS/2 SDK (3.42.1.1).

 Response:
    We found that removing the SetScanClear call in the ModeWait thread
 eliminated the problem. Following are the ModeWait and SaveRedrawWait
 threads from the modified mdraw program.
    You will notice that the semaphore requests and clears have been
 removed; this is because they were originally put in the program as a
 workaround for a problem in the OS/2 kernel. That problem has been
 corrected in the new version and if you leave the semaphores in, then
 a deadlock condition can result.

 /**     mode_wait - wait for mode reset request
  *
  *      This routine is executed by another thread that is started
  *      by the main routine.
  *
  *      This routine calls VIOmode_wait requesting to be notified
  *      after the completion of an application or hard error pop-up.
  *      On such a notification, it puts the screen in the desired
  *      graphics mode.
  */

 void mode_wait ()
 {
         unsigned NotifyType;

         while (TRUE) {
                 /* wait for notification to restore mode */
                 VIOMODEWAIT (0, &NotifyType, 0);
                 if (NotifyType == 0 && graphics)
                         VIOSETMODE ((struct ModeData far *)&grmode, 0);
                     /*  SetScanClear ();  */
         }
 }

 /**     redraw_wait - wait for mode reset request
  *
  *      This routine is executed by another thread that is started
  *      by the main routine.
  *
  *      This routine calls VioSavRedrawWait requesting to be notified
  *      for both save and redraw. On save notification, it copies the
  *      EGA adapter memory to allocated memory segments. On redraw
  *      notification, it puts the screen in the desired graphics mode
  *      and then redraws the Mandelbrot set.
  */

 void redraw_wait ()
 {
         unsigned NotifyType;

         while (TRUE) {
                 VIOSAVREDRAWWAIT (0, &NotifyType, 0);

                 if (graphics) {
                         if (NotifyType == 0) {
                                 /* save graphics screen */
     /*     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1); */
                                 SetScanSave (curr->desc->savesel);
                                 SetScanClear ();
                                 continue;
                         }
                         else if (NotifyType == 1) {
                               /* restore graphics screen */
                               dpoffset = 0;
                               VIOSETMODE ((struct ModeData far *)&grmode, 0);
                               SetScanClear ();
                               SetDVideo ();
                               SetScanRestore (curr->desc->savesel);
                               SetEVideo ();
             /*       DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);  */
                         }
                 }
         }
 }


 172. Correct Use of Length Parameters in OS/2 API Calls

 The following considerations are necessary when calling API calls that
 require a length parameter.

 1. Check the documentation to see if a parameter must be set to the
    size of the receiving structure. If this is not done before the
    call, OS/2 will return an error code. An example is VioGetMode.
    This call takes a pointer to a structure, the first two bytes of
    which must be set to the size of the structure before the call. The
    following code fragment is an example:

    unsigned rc;
    struct ModeData VioMode;

    VioMode.length = sizeof(VioMode);       /* set to the right size*/
    rc = VIOGETMODE((struct ModeData far *) &VioMode);

 2. If the parameter is used for both informing OS/2 about a size upon
    calling the API and returning a length, it may need to be checked
    and/or reset before calling the API call again. An example is the
    ByteCnt parameter in the DosMonRead call. This must be set to the
    size of DataBuffer before calling DosMonRead but upon completion of
    the call will contain the count of bytes actually read. Therefore,
    the ByteCnt parameter might have to be reset before every call to
    DosMonRead and not just once in the initialization of the program
    using it.


 173. PS/2 Model 80 Not Booting Microsoft OS/2

 Some PS/2 Model 80s are being shipped with a parameter in their setup
 that causes the OS/2 SDK to hang when booting. The problem can be
 resolved by following the steps below.

  1. Boot up the PS/2 Model 80 Reference Configuration (Setup) Disk to
     enter setup for the PS/2.

  2. From the Main menu, enter option 3, Set Configuration.

  3. From the Set Configuration menu, enter option 5, Run Auto
     Configuration. This will reset options based on what the setup
     program can detect regarding installed hardware.

  4. Exit and save the configuration values.

  5. Attempt to boot the MS OS/2 installation disk.

  6. If it still does not boot, proceed to step 7; if it does boot,
     you're finished.

  7. Boot from the PS/2 Model 80 Reference Configuration (Setup) disk
     and go to the Set Configuration menu again.

  8. Enter option 2, Change Configuration.

  9. Go to the page that show the options for the slot number that your
     hard disk controller card is on and note the value of the adapter
     memory location.

 10. Use the F5 and F6 keys to select different values for the adapter
     memory location and then go to step 4 above.

 11. Any special options that were not detected by Run Auto
     Configuration can be added after confirming that OS/2 can be
     booted off of the machine with a minimum configuration set by the
     setup program.


 174. Differences between KBD, VIO, and MOU Calls and IOCTLs

 Question:
    An OS/2 application can call for video, keyboard, mouse, and disk
 I/O services. Some of these functions are duplicates of those
 available with the VIO, KBD, and mouse subsystems.
    Are there any differences between using the KBDxxx call and the
 equivalent IOCTL call?

 Response:
    The KBDxxx calls are mapped to the appropriate IOCTL call in the
 KBDxxx.dll library. The difference is that if you used the KbdRegister
 call to register replacement routines for the keyboard driver, the
 KBDxxx calls would go to your routine, while the IOCTLs would still go
 to the KBD driver.
    This would be useful within a registered routine that wanted to
 access the real keyboard but could not because it had re-registered the
 KBDxxx functions it wanted to use.
    This also applies to the VIOxxx calls and MOUxxx calls.


 175. Calling DosExit from within Thread 1

    There will be a change in the way DosExit behaves when it is called
 in the context of thread 1 of a process. This change will affect
 Versions 1.1 and later of OS/2. The ActionCode parameter of the
 DosExit call will be ignored and all threads in the process will be
 marked to terminate.


 176. Hiding Entry Points in a DLL

 Question:

 When you create a DLL (Dynamic Linked Library), there may be many
 entry points used by the library itself. Can you hide these entry
 points to keep other programmers from calling anything but the
 approved entry points?

 Response:

 You can use ordinals instead of names to make it a little harder to
 figure out. However, that procedure has never stopped people in the
 past from obtaining these entry points by disassembling your code.


 177. OS/2 SDK: Novell's DOS Netware Doesn't Run in DOS 3.x Box

 Novell's DOS Netware will not run in the OS/2 DOS compatibility mode;
 neither will the Microsoft Networks or DOS LAN Manager software. The
 Microsoft network software that is available for OS/2 (licensed to
 network board manufacturers, not sold retail to the public) is OS/2
 LAN Manager. Once a drive is connected in an OS/2 application (such as
 CMD.EXE), programs in the DOS compatibility mode can access the drive.
 However, they are not able to make new connections (these must be done
 in an OS/2 application). Please contact Novell for information about
 OS/2 versions of its Netware software.


 178. OS/2 SDK: Problem When Using DOSFREESEG on Locked Segments

 Question:

 Is there a problem when using DOSFREESEG on locked segments?

 Response:

 Microsoft has confirmed this to be a problem in Version 1.00. This
 problem will be corrected in a future release.

 In the SDK release, one thread in an application may free a segment
 using DOSFREESEG while the segment is locked by a device driver for
 another thread in the same process. This has the possibility of
 causing unpredictable system failures, because the memory to which the
 device driver is writing may no longer be owned by the process.

 The workaround is for the process to ensure it does not free a memory
 segment while another thread in the process may be performing I/O to
 it.


 179. VioGetConfig Adapter Type and Display Type Values

 Question:
    In the listing for the VioGetConfig call in the OS/2 SDK
 programmer's reference, possible values for the "adapter type" and
 "display type" fields in the returned ConfigData structure are listed
 as follows:

     Adapter Type
      0 = Monochrome/printer adapter
      1 = Color graphics adapter
      2 = Enhanced graphics adapter

     Display Type
      0 = Monochrome display
      1 = Color display
      2 = Enhanced color display

    Are there any others? Would it be safe to check for EGA
 compatibility by checking that the adapter type is greater than or
 equal to two?

 Response:
    The following are possible values for these fields:

     Adapter Type
      0 = Monochrome/printer adapter
      1 = Color graphics adapter
      2 = Enhanced graphics adapter
      3 = VGA or PS/2 display adapter
      4-6 = Reserved
      7 = PS/2 8514/A display adapter

     Display Type
      0 = Monochrome display
      1 = Color display
      2 = Enhanced color display
      3 = PS/2 Monochrome display 8503
      4 = PS/2 Color displays 8512 and 8513
      5-8 = Reserved
      9 = PS/2 Color display 8514

       Note that you should not interpret values above two as
 representing EGA compatibility.



 180. Recapturing Thread's Stacks

 Question:
    What is the best method for freeing the memory used for a thread's
 stack? I have several threads starting up and subsequently dying off.
 I used MALLOC() to create the thread's stacks and should free up this
 memory when the threads die because not doing so adds thousands of
 bytes of unusable memory.
    If there is a method for freeing this memory, how can I be sure it
 is serialized properly? For example, just before thread A dies, it
 clears a semaphore that signals another thread (B) that it can "clean
 up" after thread A. Thread B unblocks from the DosSemWait() call and
 issues a FREE() call that releases thread A's stack. However, if the
 DosExit in thread A has not yet been executed, this situation creates
 a "window" that could toss the stack before thread A is properly
 terminated.

 Response:
    In any case, the thread that exits cannot free its own stack. The
 best you can do is to set a flag (stack-free flag) (i.e., have the
 routine that spawns threads re-use or free the stacks).
    To clear a semaphore before exiting the process, do the following:

    DosEnterCritSec
    DosSemClear
    DosExit

    When the thread exits, the other threads in the process will be
 thawed (i.e., the equivalent of DosExitCritSec occurs at DosExit
 time). This method has some benefits (i.e., you could put the stack
 selector into a list before exiting). However, this method only works
 within one process (although this may not even be a problem because
 threads belong to processes).
    Another way to set a flag (not a semaphore) is to do the following:

      mov       flag, STACK_FREE
 ; now from this point you can't use the stack.
      mov       ax, segment  STACK_EXIT
      mov       ss, ax
      mov       sp, offset   STACK_EXIT
      call      DosExit
 ....
                dw   2 dup (0)
 STACK_EXIT     dw   2 dup (0)

    After you flag the stack as being free, you cannot use the stack
 again. However, simply switch the "ss" to point to another area, and
 call DosExit. The area you point to (reserved for doing this), always
 has two zeros (as parameters) and a place to put the return address.
 It does not matter if the return address gets overwritten (by another
 exiting thread) because it will not be used to return. (Note that the
 return address is not used anyway. DosExit API is performed through a
 call gate and the return address will be put on the threads ring 0
 stack. However, this should not be assumed.)
    Therefore, in the above example, when "flag" has STACK_FREE the
 stack can be reused/freed. This method works correctly for a program
 that creates stacks and threads as they run short (i.e., no blocking
 to wait for a stack to become available). If you will need to block, a
 semaphore will have to be added; however, you will still need to use
 the flag to prevent a "window."
    Similar to the prior solution, the thread spawning off a new thread
 could check to see if other threads are still in existence. (If there
 are no other threads, the spawning thread's stack may be reused). To
 do this, issue the DosGetPrty call with the TID of the thread you are
 checking. If the thread has already exited, this API will return an
 error (ERROR_INVALID_THREADID).
    Depending on the application, you may have a pool of threads
 waiting for functions to call, i.e., as threads become idle, they add
 on to a count (threads_waiting), and as they start performing tasks,
 they naturally subtract one from the count. (Of course, the
 count_waiting has to be protected by semaphores). The following is an
 example:

 long      SemSerialWaiting;
 int       vCntWait;
 int       vCntWorkerThreads;

 long      SemCallFnc;
 long      SemWaiting;
 void far  (*vpFncToCall)();

 SpawnThread (fnc)
 void far (*fnc)();
 {

      DosSemRequest (&SemCallFnc, -1L);
      DosSemRequest (&SemSerialWaiting, -1L);
      if (vCntWait == 0  &&  vCntWorkerThreads < MAX_THREADS) {
           ... alloc stack ...
           DosCreateThread (threadwaiting ... );
           vCntWorkerThreads++;
      }
      vpFncToCall = fnc;
      DosSemClear (&SemSerialWaiting);
      DosSemClear (&SemWaiting);
 }

 ThreadWaiting ()
 {
      void far  (*fnc)();

      for (; ;) {
           DosSemRequest  (&SemSerialWaiting, -1L);
           vCntWait++;
           DosSemClear    (&SemSerialWaiting);

           /*
            * Wait for something to do
            */
           DosSemRequest  (&SemWaiting, -1L);

           DosSemRequest  (&SemSerialWaiting, -1L);
           vCntWait--;
           fnc = vpFncToCall;
           DosSemClear    (&SemCallFnc);
           DosSemClear    (&SemSerialWaiting);

           (*fnc)();
      }
 }

    If you are creating threads quickly for small tasks, use this
 method (however, it is probably application dependent).
    When SpawnThread (fnc) is called, (*fnc)() is invoked. A "waiting"
 thread in a pool of threads calls the function. If no threads are
 waiting, a new thread may be created. If all threads are in use and no
 more threads may be created, SpawnThread may be blocked. (A useful
 modification is to put a time-out on SemWaiting in ThreadWaiting so
 that the threads exit after a couple of seconds of waiting, instead of
 waiting indefinitely. However, this modification requires some form of
 stack recapturing.)
    A combination of the above suggested solutions will probably work
 best, depending on the speed at which your application creates and
 destroys threads, the amount of CPU used, the thread life, the number
 of threads required, and so on.


 181. Semaphores on a LAN Manager Server

 Question:
    Can system semaphores created with DOSCREATESEM be used across a
 network just like named pipes and mailslots, since a file name must be
 specified as it is in named pipes and mailslots?

 Response:
    No, we do not have a "net semaphore." As an alternative (other than
 record locking) you could use a named pipe.
    On the server end you would need a thread looping on the following:

      DosConnectNmPipe
      DosDisconnectNmPipe

    From the remote end you could then use the following:

      DosWaitNmPipe  - Wait for named pipe (semaphore)
      DosOpen        - Get the named pipe (semaphore)
      DosClose       - Clear the named pipe (semaphore)

    Note: You could create a counting semaphore with multiple instances
 of a named pipe.


 182. Control-C and Control-Break Signals in the Protected Mode

 Question:
    What is the difference between Control-C and Control-Break signals
 in protected mode?

 Response:
    In protected mode, when the keyboard is in the "raw mode,"
 Control-C generates a Control-C and Control-Break is converted into
 SIGBREAK.
    If the keyboard is in "cooked mode," then Control-C and
 Control-Break will be converted into SIGBREAK.


 183. OS/2 API Calls

 Question:
    Are all of the OS/2 API calls (system calls, LAN Manager,
 Presentation Manager, etc.) reentrant? If not, which are reentrant and
 which are not?

 Response:
    All OS/2 API calls are reentrant.


 184. Shared Memory Segments and/or System Semaphores

 Question:
    What happens when a process that created a shared segment and/or a
 system semaphore dies?

 Response:
    OS/2 maintains a use-count for every shared segment. When a process
 wants to use a shared segment, the use-count is increased by one. When
 a process using a shared segment terminates (or frees a shared
 segment), the use-count associated with the segment is decremented.
 The OS/2 memory manager does not free a shared memory segment until
 its use-count is zero.
    In the case of system semaphores, when the owner dies, OS/2
 releases the semaphore and notifies the next thread that gets the
 semaphore that the owner ended while holding the semaphore.


 185. Using FORMAT Utility with "/s" Option

 Problem:
    Why does not FORMAT.COM with /s work from any given directory other
 than the root ?

 Response:
    The FORMATS.TBL must be modified so that each line is preceded by a
 backslash (\). This would allow the operating system files listed in
 the FORMATS.TBL to be to extracted correctly from the root.


 186. Units of MouGetScaleFact and MouSetScaleFact Calls

 Question:
    In what units are the scale factors? It is the same when the screen
 is in text mode or graphics mode?

 Response:
    The units of the scaling factors used in MouSetScaleFact depend on
 the current screen mode. The units field specifies the number of
 mickeys the mouse must move to change the screen position by one
 screen coordinate (either one character or one pixel depending on the
 current mode).


 187. OS/2 SDK: Track Layout Table Information

 Question:

 How can I obtain the track layout information to be used on read or
 write requests to a specific physical disk drive?

 Response:

 The IOCtl category 8 (Logical Disk Control IOCtl commands) function
 63H returns the extended BPB for the device. You can get the number of
 sectors and the sector size from this structure and prepare the track
 layout table as described in functions 44H, 64H, and 65H. The
 following is a description of the track layout table:

    Sector number for sector 1           WORD
    Sector size   for sector 1           WORD
    Sector number for sector 2           WORD
    Sector size   for sector 2           WORD
    Sector number for sector 3           WORD
    Sector size   for sector 3           WORD
                   .............
                   .............
    Sector number for sector n           WORD
    Sector size   for sector n           WORD

 The track layout table can be passed on to read or write calls.


 188. Use of Malloc() Versus Dosallocseg in C Programs

 Question:
    In the sample program ARGUMENT.C in the OS/2 SDK, the following
 space is being allocated for a child thread's stack area:

        /* since this is written in C, Dosallocseg cannot be used here
 */ if( threadStack = (int *)malloc(sizeof(int) * STACK_SIZE) ) {

    What does this mean? Can Dosallocseg be used?

 Response:
    You cannot use Dosallocseg to allocate a thread's stack area from a
 C program because the C run-time libraries expect SS=DS for small and
 medium model programs.
    Dosallocseg allocates space out of the global heap, which is not in
 the DS segment. Therefore, the thread's SS would not be the same as
 its DS.
    Since malloc() allocates space out of the local heap, which is in
 the DS segment, the thread's SS would be the same as its DS.
    If you were coding in assembler, the C run times would not matter
 and Dosallocseg would work.
    Also, in large-model C programs, the run times do not assume SS=DS.
 As a result, they also will work. Dosallocseg can be used to allocate
 space from small model programs, but that space cannot be used for a
 child thread's stack.


 189. Can CTRL-ESC and ALT-ESC Be Disabled?

 Question:
    Can I disable or set my own handler for CTRL-ESC and ALT-ESC to
 prevent someone from switching my screen groups?

 Response:
    No. These key combinations cannot be disabled or trapped by any
 method, including keyboard monitors.


 190. Disk Driver Differences Between 3.5" and 5.25" Disks

 Question:
    Why are there several different files (OS2BIO.COM, DISK01.SYS)
 between 3.5 inch and 5.25 inch MS OS/2?
    Why are DISK01.506 and DISK01.ESD found only in the 3.5 inch MS OS/2?
    How are they used?

 Response:
    These files are the drive-specific part of MS OS/2. There are
 different files for different hardware.
    The DISK01.ESD is copied to DISK01.SYS for the PS/2 equipped with
 an ESDI hard disk.
    The DISK01.506 is the installed default driver. If the PS/2 is
 equipped with an ESDI hard disk, the DISK01.ESD must be copied to
 DISK01.SYS to access the hard drive.


 191. How To Determine if a Process Is Detached

    The correct procedure used to determine if a process is running
 "detached" is as follows:

    Call VioGetAnsi and look for a return code of either zero or 465,
 ERROR_VIO_DETACHED. If you receive an error code of zero, you are not
 running a detached process. If you receive an error code of 465, you
 are running a detached process.

    It also is important not to call VioGetAnsi when a VioPopUp is in
 effect, as this will return zero even if the process doing the popup
 is detached.
    To be compatible with future releases of OS/2, a process should not
 be relying on the value of its current screen group.


 192. Loading OS/2 SDK 1.05 on Drive D and Booting off Floppy Disk

 Question:

 I wish to load the SDK Version 1.05 for OS/2 Version 1.10 onto Drive D
 and boot off a floppy. In this way I can leave my DOS environment
 unaffected. I was able to do this with SDK Version 1.03 but not with
 SDK Version 1.05. How can this be done?

 Response:

 To load the SDK Version 1.05 onto Drive D and boot off a floppy, do
 the following:

 1. Make a copy of the SDK Version 1.05 Install disk (Disk 1). It will
    later be used to boot the system.

 2. Use XCOPY to copy the first five disks to Drive D. These disks are
    Install, Program 1, Program 2, Program 3, and Supplement.

 3. In the directory D:\OS2 there is now a file called OS2.INI. This
    file contains configuration information used by Presentation
    Manager. This file also contains approximately 49 references to
    Drive C. Use a tool such as DOS DEBUG to change these references to
    Drive D.

 4. In the directory D:\OS2\DLL there two files, EGA.DLL and VGA.DLL.
    Copy the appropriate file for your environment to DISPLAY.DLL.

 5. On the copy of the Install disk, copy CONFIG.211 to CONFIG.SYS,
    OS2INIT.211 to OS2INIT.CMD, and STARTUP.211 to STARTUP.CMD.

 6. Make the modifications to OS2INIT and STARTUP that fit your
    environment.

 7. In the CONFIG.SYS, change all reference to Drive C to Drive D.

 8. Also in the CONFIG.SYS file, modify the PROTSHELL command to read
    as follows:

    PROTSHELL=D:\OS2\PMSHELL.EXE D:\OS2\OS2.INI D:\OS2\PBIN\CMD.EXE /K
           D:\OS2INIT.CMD

 9. You should now be able to boot from the disk with OS/2 loaded on
    Drive D.



 193. OS/2 DosGetMessage() Informational Messages

 OS/2 API call DosGetMessage() does not return the message number in
 the user's buffer for "I" (informational) type messages.

 The following table summarizes the behavior of DosGetMessage() for
 different types of message classifications. Please note that the
 Message ID (or classification) appears as the eighth character in the
 message number (e.g. OSO0001E, FOO0010W, BAR0001I). Only the first
 seven characters of the Message ID are returned for "E" (error) and
 "W" (warning) messages, so the message classification is not placed
 with the message number.

      Message
    Classification   Message display
    --------------   ---------------

    E, W             Includes message number (i.e., OSO0001:
                                          <message text>)

    All Other        No message number (i.e., <message text>) displayed
    messages         for "I" (informational) or other messages.

 Message classifications were created to allow the user (and the
 system) to distinguish between system messages (with Error and Warning
 classifications), and informational or help messages.


 194. OS/2 SDK: Definition of APIENTRY

 Using APIENTRY is equivalent to using the C keywords far and pascal.
 APIENTRY is defined in the C include file OS2DEF.H, as follows:

    #define APIENTRY far pascal

 All OS/2 APIs are defined as being APIENTRY. In addition to these
 system APIs, some application functions (such as thread-handling
 functions) must be defined using the far keyword. For example, an
 application function can use the following APIENTRY definition:

    int APIENTRY Foo(int bar);

 If this function is then used in a non-DOS or OS/2 environment (in
 an environment where far and/or pascal code is not supported or
 necessary), APIENTRY can be redefined as follows:

    #define APIENTRY /* defined as nothing */

 This allows more flexibility than typing "far pascal" in front of each
 function.

 For more information on the far and pascal keywords, see the Microsoft
 C compiler reference manuals.


 195. Programmer's Reference Missing Register Bitmasks

 Pages 363-365 in the "Microsoft Operating System/2 Programmer's
 Reference" do not completely list the bitmasks and function indexes
 for KBD calls. The indexes should also include the following entries:

 Bit     Function        Index

 6      KbdOpen           6
 7      KbdClose          7
 8      KbdGetFocus       8
 9      KbdFreeFocus      9
 10     KbdGetCP          0Ah
 11     KbdSetCP          0Bh
 12     KbdXlate          0Ch
 13     KbdSetCusXT       0Dh


 196. IFS and File Names

 Question:
     I have heard that the 8.3 file name convention will change
 with installable file systems. What steps should I take so that my
 applications will be able to handle this change?

 Response:
     On the OS/2 API set, note that all API calls interacting with
 the file system use a handle or, if a name is required, an ASCII
 null-terminated string (ASCIIZ).
    Your programs should follow this convention whenever possible;
 do not count on such features as 8.30, forward/backward slashes, or
 any other internal structure of the file name string.
    Applications should not parse file names; leave space for 256
 characters in your file name buffer specifications. These rules should
 ensure an application's compatibility with future installable file
 systems.


 197. OS/2 and ANSI.SYS

 Question:
    Do the ANSI sequences of MS OS/2 support redefinition of the
 keyboard?

 Response:
    In real mode, ANSI support is obtained by including the ANSI.SYS
 device driver in your CONFIG.OS2 file. This is the same as using ANSI
 under DOS.
    In protected mode, ANSI is obtained by the base video drivers. It
 also support the remapping of keys through KbdRegister. One
 KbdRegister is allowed per screen group.
    If you are using ANSI for your own purposes, then the remapping of
 the keys will not work.


 198. OS/2 Disk Volume Identification (ID) Information

 Question:

 We would like to know more about disk Volume IDs. We ran across these
 by accident when we DISKCOMPed two OS/2 disks (made with OS/2
 DISKCOPY) under DOS Version 3.30 and they did not compare. Where does
 this ID come from? Why is it different on two disks made with OS/2
 DISKCOPY, and why doesn't OS/2 DISKCOMP find this difference? What
 should we put in this field on our distribution disks?

 Response:

 The Volume ID field was added to the boot sector of OS/2 disks to
 verify whether the disk in the floppy drive has been changed. It is a
 32-bit random number that is put into the boot sector when the disk is
 formatted.

 OS/2 checks this ID field before doing I/O on the drive. If the ID is
 not correct, you receive a message asking for the correct disk.

 When a disk is duplicated under OS/2 DISKCOPY, a new value is put in
 the Volume ID field to indicate that the two disks are physically
 different, even though their contents may be the same.

 OS/2 DISKCOMP knows about the ID field, and ignores it when making its
 comparisons. DOS DISKCOMP does not know about the Volume ID, and flags
 it as a difference.

 Disks formatted under DOS do not have the Volume ID field, so OS/2 has
 a harder time telling if the disk has been changed. It is forced to
 checksum parts of the disk's root directory and FAT table, which
 requires extra disk operations for media identification. Because of
 this, we advise that you supply the Volume ID for disks to be used in
 OS/2 systems.

 Create the disk either through OS/2 FORMAT or DISKCOPY, or supply the
 Volume ID value by some other method. You can use anything you like
 because the number is truly random.


 199. OS/2 Does Not Recognize InPort Mouse as Bus Mouse

 Question:
    I have a Microsoft Bus Mouse, and I am using the MOUSEA03.SYS
 device driver. The mouse is not working properly. What is wrong?

 Response:
    There seems to be some confusion about mouse types. The InPort
 mouse is a Bus-type mouse, and has been marketed under that
 description. However, OS/2 considers the InPort mouse to be different
 from a Bus mouse.
    You may actually have an InPort mouse, not a Bus mouse. If this is
 the case, using the MOUSEA04.SYS driver will solve your problem.
    An easy way to confirm which type of mouse you have is to look at
 the connector with which your mouse plugs into the machine.
    If the connector is a round 9-pin connector, you have an InPort
 mouse.
    If it is a D-shaped 9-pin connector, as pictured in the following
 diagram, you have a Bus mouse:
                     ___________
                    | o o o o o |
                     \ o o o o /
                       -------


 200. MouRegister Bitmasks Incomplete in Programmer's Reference

 Question:

 Page 418 of the "Microsoft Operating System/2 Programmer's Reference"
 specifies bitmasks for registering replacement MOU calls. Are these
 masks complete?

 Response:

 No, the masks are incomplete. The high word also should contain the
 following entries:

 Bit    Meaning             Code

 20     MouFlushQue         14H
 21     MouSetDevStatus     15H


 201. Getting Selector to Video RAM

 Question:
    Is there an API call that will allow me to convert a physical
 segment to a valid segment selector, e.g. the DevHlp function
 PhysToVirt?
    I am trying to clear the video memory at segment B000h. I linked
 the program with IOPL. I am able to initialize the video card through
 in/out instructions, but I can not talk to its memory.

 Response:
    To get selectors for direct access to the video buffer, you can use
 the VioGetPhysBuf API call.
    In the more general case of nonvideo memory, you need to write a
 device driver that will communicate with your application through
 IOCTLs.


 202. Volume Label Error

 Page 161 of the "Microsoft Operating System/2 User's Reference" manual
 incorrectly states that the LABEL.EXE command will delete the volume
 label on the disk; Microsoft does not recommend using MS OS/2 without
 a volume label.

 The LABEL.EXE command will only allow you to change the existing
 label.

 The OS/2 user's guide incorrectly states the following:

    Type the volume label that you want and press the ENTER key. A
    volume label may be up to 11 characters in length and may include
    spaces, but not tabs. Or, you can press the ENTER key immediately
    if you want to delete the volume label. MS OS/2 will prompt with
    the following message:

    Delete current volume label  (Y/N)?_

    If you type "Y", MS OS/2 deletes the volume label on the disk.
    Otherwise, the volume label stays the same.

 If you press the ENTER key, the "no volume update" message may appear.


 203. PTrace Documentation Update

   Many of the functions and return codes for DosPTrace are not
 documented or are incorrectly documented.
    There is a file called PTRACE.ARC in the Software Library with more
 complete documentation on return values, functions, and how to use
 DosPTrace. This file can be found in the Software Library by searching
 for the filename, the Q number of this article, or S12008.


 204. Process IDs and Kill Signals

    The DosKillProcess API will unconditionally terminate any process
 (i.e., orphaned grandchildren processes). The only exception is if the
 process has installed a signal handler for the SIG_KILLPROCESS signal.
 This signal handler ignores or otherwise disables the SIG_KILLPROCESS
 signal.
    To use DosKillProcess, you must know the PID of the process you
 wish to kill. The PID is returned by the DosExecPgm call when you
 start the process. You must save this value and, if necessary, pass it
 to the process sending the kill signal because there is no subsequent
 means of determining the PID of a process.


 205. Windows 2.03 in OS/2 Compatibility Box: Mouse Cursor Nonmoving

    In the OS/2 compatibility box under Windows Version 2.03, the mouse
 cursor will not move. Adding "mode=B" to the mouse DEVICE statement in
 the CONFIG.SYS file will not correct this problem.
    This is a known problem in machines with VGA video adapters.
    A workaround is to remove the MOUSEA0x.SYS and POINTDD.SYS mouse
 driver files from the CONFIG.SYS file; this will enable your mouse
 under Windows in the 3.x box. Please note that removing these files
 will disable the mouse in the protect mode.


 206. Keystroke Information for OS/2

 Question:
    How can I get information about key presses and releases for keys
 other than the SHIFT state keys?
    Only the press generates a KbdCharIn record for normal keys. Also,
 the SHIFT state keys always return 00 for the scan code. How do I get
 the original untranslated scan code?

 Response:
    This information is not available in the data packet returned by
 the KbdCharIn call.
    If you register a keyboard monitor, however, you will receive data
 packets that have the KbdCharIn packet embedded, and that also contain
 the untranslated scan code and information about whether the event was
 a press or release. A monitor packet is generated for all presses and
 releases.


 207. Running Epsilon Text Editor in 3.x Box in OS/2

 Problem:

 We have a problem with the Epsilon Text Editor when running a program
 in the 3.x box of the current release of OS/2. Sometimes when we type
 a key, a different key appears.

 Response:

 The Epsilon Extension Language source that follows provides a
 workaround for those Epsilon users who use OS/2. It causes Epsilon to
 operate correctly in the DOS 3.x box, but makes it impossible to bring
 up most resident programs while Epsilon runs.

 To use it, perform the following steps:

 1. Download the following source text and put it in a file (e.g.
    OS2BOX.E).

 2. Run the EEL compiler on the file by typing the following:

    eel os2box

 3. Start Epsilon, and load the file by typing the following:

    F-3 os2box

 4. To make the change permanent, use the write-state command.

 (This information was provided by Steven Doerfler, Lugaru Software
 Ltd. "Epsilon", "EEL" and "Lugaru" are trademarks of Lugaru Software,
 Ltd. Copyright (C) 1987 Lugaru Software Ltd. All rights reserved.

 Limited permission is hereby granted to reproduce and modify this
 copyrighted material provided that the resulting code is used only in
 conjunction with Lugaru products and that this notice is retained in
 any such reproduction or modification.)

 Epsilon's normal keyboard-handling scheme involves intercepting all
 keys and passing some through the BIOS and whatever resident software
 may be present. Specifically, Epsilon passes all keys except those the
 BIOS would discard as an unrecognized combination, but which Epsilon
 recognizes. The current beta release of OS/2 occasionally gets
 confused by this, and mixes up the keys when Epsilon runs in its
 compatibility box.

 This file instructs Epsilon to keep all keys, so that Epsilon works in
 OS/2's compatibility box. Loading it with F-3 makes the change in the
 running version of Epsilon. The following write-state command may be
 used to make this change permanent:

    #include "eel.h"

    when_loading()
    {
    int k, tokey;

    for (k = 0; k < NUMKEYS; k++)/* keep all keys */
    keytran[k] = k;
    /* and translate some grey keys */
    for (k = GREYPLUS; k <= GREYESC; k++) {
    tokey = "+-*\r\b\t\033"[k - GREYPLUS];
    keytran[k] = tokey;
    keytran[NUMALT(k)] = ALT(tokey);
    }
    keytran[NUMCTRL(GREYBACK)] = DEL;
    keytran[NUMCTRL(GREYENTER)] = '\n';

    keytran[NUMCTRL(GREYESC)] = -1;/* but pass these to OS/2 */
    keytran[NUMALT(GREYESC)] = -1;
    }


 208. Providing Display Device Driver Support

 Question:

 My application needs to run using the features of many types of
 display adapters and displays (e.g. Tseng Labs, Paradise, STB). I
 have the following questions about how display manufacturers and
 applications get support from OS/2.

 First of all, will the hardware manufacturers supply device drivers
 and replacement Vio DynaLinks for their hardware? If so, will there be
 some sort of standardization of return values of calls such as
 VIOGETCONFIG [VioGetConfig() in Version 1.06 and above]?

 Also, if the hardware manufacturers do not supply these components,
 will each and every software application have to supply its own?

 Response:

 Most hardware manufacturers will need to supply a device driver to use
 their hardware if it is not standard. As far as the type of standards
 for return values, we will provide only what already is documented.
 The hardware manufacturers may decide some other type of information
 is important, and include that information in their version of OS/2.

 If the hardware manufacturers do not supply the components, each
 software application will have to do the work.


 209. Internal Error Occurs When MAXTHREADS is Too Low

 Problem:

 I am having problems running the product version of Epsilon with the
 new SDK release. I get the SYS0164 error message when I try to execute
 the program.

 Response:

 This error occurs when the maximum number of threads has been reached.
 It is documented in the BSEERR.H file. To avoid this problem, change
 the value of MAXTHREADS in your CONFIG.SYS file to a higher number
 when running this program.


 210. DosFindFirst/FindNext in Real Mode

 Problem:

 I have written a program in MS-DOS Version 3.20 that displays all the
 files on a disk. The program uses INT 21h with the functions
 FindFirst/FindNext to traverse the directory tree structure. I
 converted the program to OS/2 using DosFindFirst/FindNext and it
 worked in protected mode. However, it failed when I tried to bind it
 to run in real mode.

 Response:

 There is a restriction on DosFindFirst/FindNext in the real mode box
 (dirhandle=1) that does not allow allocation of new dirhandles as you
 descend the directory tree. This makes it difficult to write a program
 that displays all the files on a disk, and that will run in real, as
 well as protected, mode.

 This restriction occurs because you would have to malloc a new DTA
 whenever a FindFirst (with a handle = FFFFh) to emulate the full
 functionality of DosFindFirst/FindNext in real mode. Memory
 fragmentation would result, causing problems for many application
 programs.

 There are three solutions to this problem. First, use the function
 DosGetMachineMode to determine whether you are in the 3.x box or in
 protected mode at run time. If you are in protected mode, do
 DosFindFirst/FindNext calls, recursively allocating a new dirhandle
 (dirhandle=-1) as you descend the tree. If you are in real mode, use
 the program in the same way as you tried under DOS Version 3.x, using
 INT 21 calls and allocating a new DTA each time you descend the tree.

 The second method consists of using the program with the
 DosFindFirst/FindNext calls. However, remember where you left off in
 the parent directory when descending into a child. When you finish
 displaying the child tree's files, continue where you left off on the
 parent's files. Write the program without using recursion so that
 allocation of new dirhandles is not needed as you descend the tree.

 The final option is to write your own FAPI support module to expand
 the functionality of DosFindFirst/FindNext; then, link this module on
 the BIND command line. This object would be substituted for the
 API.LIB FindFirst/FindNext. See the MS OS/2 Application Program
 Interface section of the programmer's guide for more information on
 expanding FAPI functionality.


 211. Set Typamatic Rate IOCTL Documentation Error

 Problem:

 The KBD Set Typamatic rate IOCTL call does not work correctly.

 Response:

 The problem you encountered was an error in our documentation of the
 KBD Set Typamatic rate IOCTL call. The parameter packet format should
 have been two words, not two bytes, for delay and rate, respectively.
 KbdSetRate is described on Page 190 of the "Microsoft Operating
 System/2 Software Development Kit Device Drivers Guide."


 212. Using OS/2 API Calls in Presentation Manager Applications

 Question:
    For the Presentation Manager, should I use OS/2 API functions in my
 PM application and DLL or strictly use all PM functions--e.g.
 DosAllocSeg vs. WinCreateHeap and WinAllocSeg; DosOpen versus
 WinOpenFile?

 Response:
    You can use both OS/2 API and PM API functions in PM applications
 depending on what you want to do. Similar OS/2 and PM functions will
 generally have some differences that determine which one you would use
 in a given situation.


 213. Using DosStartSession() to Create a Related Session

 Problem:

 I am having difficulty using DosStartSession() to create a related
 session.

 Response:

 The documentation for DosStartSession() is out of date. (See the
 "Microsoft Operating System/2 Programmer's Reference," Page 306.) The
 current calling sequence is as follows:

    push @other StartData
    push @word Sessionid
    push @word ProcessID
    CALL DOSSTARTSESSION

 The following three things should be noted:

 1. ProcessID has been added to the call and is the address of where
    the operating system may place the ProcessID.

 2. The description for PgmName (on Page 307 of the programmer's
    reference) is actually the description of PgmInputs; PgmName is the
    far address of an ASCIIZ string containing the fully qualified
    drive, path, and filename of the program to be loaded.

 3. TraceOpt (a word parameter that comes after FgBg) specifies whether
    the program started in the new session should be executed under
    conditions for tracing with DOSPTRACE:

    TraceOpt = 0 ; no trace
    TraceOpt = 1 ; trace

 No parameter currently exists for passing environment variables. One
 option is to start CMD.EXE with the /k switch to run a CMD file to set
 the environment before executing the program. An example is as follows:

    PgmName = CMD.EXE
    PgmInputs = /k initenv.cmd

 The following is an example of using DosStartSession() with the OS/2
 application BIGBEN:

 #include    <doscalls.h>
 #include    <subcalls.h>

 char    PgmTitle[]  = "BIGBEN";
 char    PgmInputs[] = "";

 char    PgmName[]   =

  "D:\\PROJECTS\\DEMOS\\APPS\\BIGBEN\\BIGBEN.EXE";

 main(argc,argv)
 int     argc;
 char    *argv[];
 {
     struct StartData    StrtData;
     unsigned            SessID;
     unsigned            ProcessID;
     unsigned            rc;

     StrtData.Length    = sizeof(StrtData);
     StrtData.Related   = 1;
     StrtData.FgBg      = 0;
     StrtData.TraceOpt  = 0;
     StrtData.PgmTitle  = (char far *)PgmTitle;
     StrtData.PgmName   = (char far *)PgmName;
     StrtData.PgmInputs = (char far *)PgmInputs;
     StrtData.TermQ     = (char far *)0;
     rc = DOSSTARTSESSION((struct StartData far *)&StrtData,
                                  (unsigned far *)&SessID,
                                  (unsigned far *)&ProcessID);

     printf("DOSSTARTSESSION return code = %d\r\n", rc);

     while ( 1 )
         DOSSLEEP(0L);
 }


 214. Error Codes Returned from DosSetFileMode()

 Problem:

 I have encountered two error messages listed below:

 1. When DosSetFileMode() is given a path that begins with an invalid
    drive letter (e.g., Q:SOMENAME.DOC), it returns the message
    "error code 3, path not found". This is inconsistent; the proper
    return code should be "error code 15, invalid drive".

 2. When DosSetFileMode() is given an improper attribute word, i.e.,
    one containing one of the bits FFE8H, it returns the message "error
    code 5, access denied". This is incorrect; the error has nothing to
    do with access. Other calls that take attribute parameters return
    "error code 87, invalid parameter" when given an improper attribute
    word.

 Response:

 Both of these errors exist for compatibility reasons. The Interrupt 21H
 equivalent of the DosSetFileMode() call is Function 43H. If a path with
 an invalid drive is passed in, it returns error 3. If an invalid
 attribute is passed in, it returns error 5. The DosSetFileMode() was
 written to be compatible with the Interrupt 21 function.


 215. OS/2 SDK: Internal Format of OS2.INI

 The internal format of OS2.INI is subject to change; therefore, it is
 not documented. The following is a list of the APIs specifically
 provided for reading and modifying entries in OS2.INI:

 1. WinQueryProfileData()

 2. WinQueryProfileString()

 3. WinQueryProfileInt()

 4. WinQueryProfileSize()

 5. WinWriteProfileData()

 6. WinWriteProfileString()


 216. DOSEXECPGM : Asynctraceflags 4 and 5 Information

 Question:

 What do the DosExecPgm : asynctraceflags 4 and 5 do?

 Response:

 With DosExecPgm : asynctraceflag 4, the program executes asynchronous
 to the parent process, detached from the parent process's screen
 group. If the parent process is stopped, it is treated as an orphan
 process and does not affect the detached process. The process should
 not require any input from the keyboard or output to the screen other
 than VioPopups. It should not use any console I/O calls, e.g. VIO,
 KBD, or MOU calls.

 With DosExecPgm : asynctraceflag 5, the program is loaded into storage
 and made ready to execute, but is not actually executed until the
 session manager issues a DosSystemService() thaw process request.


 217. DosSearchPath Documentation Error in Programmer's Reference

 The entry for DosSearchPath on Pages 257-259 in the "Microsoft
 Operating System/2 Programmer's Reference" is in error. The fifth
 parameter is shown as follows:

    PUSH@ OTHER ResultBufferLen

 This is incorrect because no indirection is required. The entry should
 be as follows:

    PUSH WORD ResultBufferLen

 This documentation error can be verified by looking in DOSCALLS.H.


 218. Setting Timestamps with DosSetFileInfo()

 Problem:

 DosSetFileInfo() is supposed to allow the setting of the three
 timestamps (creation, last access, last write). However, only the last
 write stamp can be set: if either of the other date/time word pairs
 contains nonzero values, the function returns "error code 87, invalid
 parameter." This restriction is not documented. It would be useful to
 allow an OS/2 program to update these fields, which neither MS-DOS nor
 OS/2 maintain.

 Response:

 The extra date fields are there for future use; therefore, we could
 have allowed the programmer to do either of the following with these
 fields at the present time:

 1. Let the caller pass in data but ignore the data.

 2. Let the caller only pass in zeros in the unused fields (the zero
    means to leave the value untouched).

 We chose to do the latter. The problem with the first solution is that
 many programs might not put valid data in the fields. When we begin
 using the fields, these programs break.


 219. Creating a Unique Temporary Filename

 Problem:

 OS/2 appears to have no equivalent of the function supplied by MS-DOS
 Interrupt 21H subfunction 5AH, "make a scratch file with a unique
 name". It would seem that it is nearly impossible for a program to
 generate a unique scratch filename in OS/2, but fairly easy for the
 kernel to do so.

 Response:

 You are correct: there is no equivalent function. The best method to
 create a unique name is to use your process ID [DosGetPid()] and
 append an application-specific prefix to it. The kernel guarantees
 that there are never two processes with the same ID. If you have
 multiple threads creating temp files, append the thread ID to the
 name. This must fit into the 8.3 file name restrictions.

 After generating the name, the program should use the flag of the
 DosOpen() command to fail if the file already exists. If, for some
 reason, the file happens to exist, the DosOpen() command fails. You
 can attempt to generate another unique name in either a random fashion
 or by using another method of your choice.


 220. Definitions of Attribute Byte for VIO Calls

 Question:

 I can't seem to find a description of the attribute codes for the
 VIOXXXXX calls that require them, such as VIOWRTCELLSTR().

 Response:

 The definitions for the attributes are not currently listed in the
 OS/2 manuals. However, they are the same as they were for MS-DOS,
 since the attributes are hardware dependent.

 The following is a description of each bit of the attribute byte. For
 a more detailed description, see Pages 76-80 of Peter Norton's
 "Programmers Guide to the IBM PC."

 Bits of attribute byte are as follows:

 7 6 5 4 3 2 1 0

 1 . . . . . . .   Blinking of foreground character
 . 1 . . . . . .   Red component of background color
 . . 1 . . . . .   Green component of background
 . . . 1 . . . .   Blue component of background
 . . . . 1 . . .   Intensity of foreground color
 . . . . . 1 . .   Red component of foreground
 . . . . . . 1 .   Green component of foreground
 . . . . . . . 1   Blue component of foreground


 221. Errors in LAN Manager Overview Documentation Page Sequence

 The version of the document, part number 00261, "Microsoft OS/2 LAN
 Manager Version 1.0 Introduction and Technical Product Overview"
 shipped with the recent OS/2 developer's kit update package #1 (cover
 letter dated August 1, 1987) appears to have been miscollated in
 reproduction.

 Pages 1 and 2 appear to be in sequence. Page 3 begins with "The data
 buffer is filled in..." and continues with the NetbiosLinkage
 structure description. It appears to be out of place (actually, it
 appears not to belong in the Introduction and Overview at all). Page 4
 begins with item 8 in a numbered list, the first seven items of which
 are nowhere to be found. Pages 5 to 9 appear to be in sequence.

 Microsoft is aware of this problem. The problems with the LAN manager
 documentation will be corrected when the LAN manager is available in
 an update to the OS/2 SDK.


 222. Context Switches at Ring 2

 Question:

 According to the "Operating System/2 Device Drivers Guide", a context
 switch cannot occur while a process is executing in kernel mode (ring
 0), unless the process explicitly relinquishes control. Can a
 system-imposed (e.g., time-slicing, or a higher priority thread being
 unblocked by an interrupt, or by the executing thread) context switch
 occur while a thread is executing at ring 2 (i.e., while executing a
 DLL module with IOPL privilege)?

 Response:

 Context switches can occur in ring 2. You must use a semaphore to
 control access if you need to serialize or protect a code segment from
 a context switch.


 223. Keyboard Locked Out When Running Word

 If you press either the NUM LOCK key or the CAPS LOCK key when
 Microsoft Word is running in the compatibility box, the entire
 keyboard is locked out. The indicator lights remain the same and
 background processes continue, but there is no way to switch modes.

 Microsoft has confirmed this to be a problem in Version 1.00. This
 problem was corrected in Version 1.10.


 224. OS/2 SDK: Cursor Addressing Using Escape Codes

 Question:

 Does OS/2 currently honor the escape sequences to control the screen,
 as in the MS-DOS driver ANSI.SYS, and as described in the MS-DOS
 technical reference manual? I have an application that I want to
 convert from MS-DOS to OS/2 that makes heavy use of screen control
 sequences (ESC+BRACKET+<keyname>) for changing color and cursor
 position. What problems can I expect to run into?

 Response:

 ANSI escape sequences are supported in protected mode, but they must
 be sent to the console for the ANSI driver to intercept them.

 OS/2 does support terminal-like character-code controlled cursor
 addressing. Use the system call VIOSETANSI to set the system into ANSI
 mode. To be the most friendly to other applications, do a VIOGETANSI
 to get the current state, store it somewhere, and restore the system
 to that state upon exit from your program.

 There should be no problem porting your application to OS/2.
 Single-thread C programs basically just need to be compiled for
 protected-mode operation, or they need to be compiled and then bound
 with the BIND utility to run in either protected or real mode.


 225. Using DosExecPgm to Execute CMD.EXE

 Problem:

 I can start a session with DOSSTARTSESSION (e.g., "cmd.exe /c start
 "session 1" c:\bigben.exe"), but the documentation is confusing on how
 to execute this same command through DosExecPgm.

 Response:

 Below is an example of how to use DosExecPgm to execute CMD.EXE, which
 then executes the program passed to it. The program EXECPGM.EXE uses
 DosExecPgm to execute CMD.EXE and to pass CMD.EXE the program PGM.EXE.
 Both programs were compiled with the following switches: "cl -AL -G2
 -Lp <filename.c>". The programs are as follows:

 -----------------------EXECPGM.C----------------------------------------

 #include <stdio.h>
 #include <doscalls.h>
 #include <subcalls.h>

 #define LEN_OBJ_NAME_BUF        64   /* length of error message buffer */
 #define ASYNC_TRACE_FLAGS       4  /* run child processes asynchronously */

 /*---- structures for creating processes ---*/

 struct ResultCodes return_codes;      /* 1st word is child process id */
 char obj_name_buf [LEN_OBJ_NAME_BUF]; /* buffer for error information */

 main()
 {
     int    rc;
     struct KeyData c;

 /*  create process, set the path for CMD.EXE and PGM.EXE to fit your system *
 /*  Note that a \0 is needed to separate the program name from the  */
 /*  arguments and that two \0s are needed to end the argument line. */

     rc = DOSEXECPGM (obj_name_buf,
                      LEN_OBJ_NAME_BUF,
                      ASYNC_TRACE_FLAGS,
                      (char far *) "CMD.EXE\0/C C:\\work\\PGM.EXE\0\0",
                      0L,
                      &return_codes,
                      (char far *) "C:\\OS2\\BIN\\CMD.EXE\0\0");
     if (rc) {
         printf ("*** error creating Pgm.exe - %d\n", rc);
         DOSEXIT (1,4);
     }

     DOSSLEEP(3000L);

     printf("Exiting ExecPgm.exe\n");
 }

 ---------------------------------PGM.EXE------------------------------------

 #include <doscalls.h>
 #include <subcalls.h>

 /* simple pop up window example */

 main ()
 {
     char text[50];
     struct KeyData;
     unsigned waitflags, length;

     waitflags = 0;
     strcpy(text, "Hello from PGM.EXE");
     VIOPOPUP(&waitflags, 0);
     length = strlen(text);
     VIOWRTCHARSTR ((char far *)text, length, 12, 15, 0);
     DOSSLEEP(4000L);
     VIOENDPOPUP (0);
 }
 ---------------------------------------------------------------------------


 226. Documentation Error in Request Queue Device Help Routines

 Question:

 The following is the calling sequence for Device Helper PushReqPacket:

  LDS SI,[Queue]
  LES BX,RequestPacket
  MOV DL,DEVHLP_PUSHREQPACKET
  CALL [Device_Help]

 Since both DS and ES are used to pass parameters, how do I call
 Device_Help? The address of Device_Help is passed by the system at
 initialization time and has to be saved at some place. To call
 Device_Help, I must have DS point to my DATA segment. If DS must point
 to my DATA segment, it cannot be used to pass parameters to
 Device_Help. What should I do?

 Response:

 There is an error in the documentation of the Device Help routines
 (Pages 320-329 of the "Microsoft Operating System/2 Device Drivers
 Guide") that deal with request queue management. The correct
 parameters for dh_PushReqPacket are as follows. (This also applies to
 the other Request Packet management device help calls.) The following
 is the correct calling sequence:

     MOV     SI,OFFSET DS:queue      ; Pointer to DWORD queue head
                                     ;   (which points to the first request
                                     ;   packet in the queue)

     LES     BX,request_packet       ; Pointer to device request packet
     MOV     DL,DevHlp_PushReqPacket
     CALL    [Device_Help]


 227. Not Passing Keystrokes Through with a Keyboard Monitor

 Question:

 I have the following questions on keyboard monitors:

 1. Can a keyboard monitor choose to not pass on a particular hotkey
    that it wants to use?

 2. If DosMonWrite() must still be called (to allow the driver to clean
    up), should the count be set to 0 to indicate that the hotkey was not
    passed?

 3. I find that putting a DosMonClose(KBDHandle) in a clean-up routine
    in a DosExitList() chain consistently returns nonzero (381
    ERROR_MON_INVALID_HANDLE). Is this normal?

 Response:

 The following are answers to the above questions:

 1. Yes. It is not necessary to pass on every packet that comes through
    a monitor chain. Flush packets are an exception, and should always
    be quickly passed through. It is fine to "consume" keystrokes by
    not passing them through.

 2. No; the count parameter of DosMonWrite() is the count of bytes to
    pass through. It would be invalid to give it a zero size.

 3. Yes; in the exiting process, the first thing that is done is that
    all extra threads are destroyed. Then, any open monitors are closed
    and the exit list routines are called (in an indeterminate order if
    there is more than one). This is why you are getting the error from
    DosMonClose(). It doesn't hurt to leave the DosMonClose() call in,
    as it helps document the intent of your code.


 228. KbdPeek Determination of Empty Buffer

 Question:

 I am using KbdPeek to determine if there are any characters in the
 stdin buffer. How does KbdPeek indicate that the buffer is empty?

 Response:

 There is a documentation error in the KbdPeek call. Page 360 of the
 "Microsoft Operating System/2 Programmer's Reference" manual should
 read as follows:

    A returned character is indicated by the final character flag, bit
    6 of the status byte, being set to one. Bit six set to zero
    indicates that no character was returned. KbdPeek will only
    complete when the handle has the focus or the handle is zero and no
    other handle has the focus.


 229. OS/2 SDK: Permanently Disabling Compatibility Box

 Question:

 Can I permanently disable the compatibility box beyond what can be
 done by setting PROTECTONLY to YES in CONFIG.SYS?

 Response:

 Yes, you can. You need to remove the SHELL statement from the
 CONFIG.SYS file, along with any references to MS-DOS device drivers.
 Also, remove any references to C:\COMMAND.COM and C:\OS2\COMMAND.COM,
 and set PROTECTONLY to YES.

 Thus, the only way anyone could ever get the DOS 3.x box up and
 running again would be to change the CONFIG.SYS file. It would also be
 necessary to obtain a copy of COMMAND.COM (for OS/2).

 If a user were to change the CONFIG.SYS file to "PROTECTONLY=NO" and
 insert a SHELL statement, he or she would still get an error on the
 screen at boot time indicating that the DOS 3.x box could not be
 loaded.


 230. OS/2 SDK: Calling of Exit List Routine

 Question:

 Assume a process uses DosExitList() to request the OS/2 kernel to call
 a routine to be executed during process exit, and that same process
 uses DosOpen() to open a device. When that process exits due to, say,
 a CTRL+C, does the kernel call the exit list routine before calling
 the device driver with a close request, or does the device driver get
 called first?

 Response:

 Currently, the exit list routines are all allowed to complete before
 the system cleans up files by closing them. The exceptions are devices
 that are opened for device monitors. These will be closed before the
 exit list routines are called. This exception isn't documented; please
 note that it might be subject to change.


 231. Root Directory Clutter

 Question:
    It appears that the root directory needs to be cluttered with
 device drivers and several executable files. Why can I not put all of
 my device drivers into a subdirectory of the root and have the path to
 these drivers specified in my config.sys file (i.e., c:\sys\*.sys)? I
 prefer to maintain my root directory with only the minimum number of
 files.

 Response:
    At boot, the file system does not know enough about directory
 structures to be able to access the files in a subdirectory,
 Therefore, it cannot look for the files that it needs except in the
 root directory of the boot drive.


 232. Overview of OS/2 Dispatch Scheduler

 This article provides an overview of the OS/2 Dispatch Scheduler.

 Introduction
 ------------

 The OS/2 scheduler uses time slicing to share CPU time among all
 running programs and their threads. It does not share the CPU's time
 equally among all programs. The dispatching entity of the OS/2
 scheduler is the thread, rather than the process. Each process
 contains at least one thread, and each of the threads of a process run
 is given the same priority.

 The scheduler is a priority-based scheduler. It assigns each thread a
 priority and uses this priority to decide when to allot CPU time for a
 particular thread. The scheduler is preemptive, meaning that if a
 higher-priority thread is ready to run, the scheduler preempts a
 running lower-priority thread to accommodate the higher-priority
 thread. Later, the lower-priority thread is allowed to continue where
 it left off.

 The scheduler's algorithm, simply put, is to execute the
 highest-priority thread for as long as the thread wants to use the
 CPU. When the thread is blocked, e.g. waiting for a peripheral (such
 as a disk drive) to complete an operation, the scheduler executes the
 next-highest priority thread that is ready to run. Therefore, the
 system is always running the highest-priority thread.

 Program Classes
 ---------------

 The OS/2 scheduler classifies programs as follows:

    Time-critical threads (system and application)
    Foreground threads (application)
    Regular threads (application)
    Idle threads (system and application)

 The higher the class, the more precedence a process has. Programs at a
 higher class are run before programs at a lower class. Programs can
 change themselves to be in the time-critical, regular-application
 (default), and idle classes.

 Priority Level
 --------------

 Within a class, there is a numeric priority level that prioritizes
 threads running within the same class. If two or more threads are in
 the same class and have the same priority level, OS/2 shares the CPU
 time to the threads in a round-robin manner.

 User-Configurable Areas
 -----------------------

 Some portions of the OS/2 scheduler are user configurable. There are
 entries in the OS/2 configuration file CONFIG.SYS, most notably
 MAXWAIT, PRIORITY, and TIMESLICE, that affect the way the scheduler
 works.

 The TIMESLICE Configuration Option
 ----------------------------------

 The TIMESLICE configuration command determines the amount of time in
 milliseconds that the CPU allocates to a thread before giving CPU time
 to another thread of the same priority level to execute. This ensures
 that threads of equal priority level are given an equal, round-robin
 opportunity to execute. There are minimum and maximum values that are
 given on the TIMESLICE command line. The default minimum value is 32
 milliseconds, and the default maximum is 248 milliseconds. If only one
 value is specified, both minimum and maximum ranges are set to the
 value of the first/only value specified. Changing this value is not
 usually recommended, unless specified by an application that has to
 perform timing-dependent activities (and this would normally require
 that the value be lower, to ensure that applications are given a slice
 of the CPU more frequently). However, the lower the value, the more
 time the OS/2 scheduler has to spend scheduling time.

 The PRIORITY Configuration Option
 ---------------------------------

 The PRIORITY configuration command determines how the OS/2 scheduler
 will behave. If set to PRIORITY=ABSOLUTE, many of the tricks that the
 scheduler could perform are not done, and the scheduler uses a much
 simpler, static algorithm. If set to PRIORITY=DYNAMIC, the scheduler
 tries to get performance boosts for threads running by temporarily
 boosting the priority level of an application within a class.

 One such performance boost is the MAXWAIT configuration command. The
 scheduler boosts the priority level of a thread if it is
 "starving." This scheduling logic is only available when
 PRIORITY=DYNAMIC and the thread is in the regular application class.

 There are some situations when the OS/2 scheduler boosts the priority
 level (staying within the same class) of a thread if it is spending an
 inordinate amount of time blocking on an I/O device. This is called an
 I/O boost. This scheduling logic is available only when
 PRIORITY=DYNAMIC and the thread is in the regular-application class.

 When a thread is in the regular-application class and is part of a
 process being selected by the user in the foreground, the thread is
 given a boost to the foreground-application class while it is in the
 foreground (however, this class is not selectable by an application).
 This is called a foreground boost. Foreground-application-class
 threads are higher than regular-application-class threads; thus, the
 scheduler runs foreground threads before regular threads. This
 scheduling logic is available only when PRIORITY=DYNAMIC and the
 thread is in the regular-application class.

 Again, if PRIORITY=ABSOLUTE, the scheduling optimizations, starvation
 boosts, I/O boosts, and foreground-application boosts will not take
 place.

 The MAXWAIT Configuration Option
 --------------------------------

 The MAXWAIT configuration command roughly determines the amount of
 time an eligible thread waits before being given a temporary boost in
 priority level. This is also known as the starvation boost. The
 scheduler, after the amount of time specified on the MAXWAIT command
 line, temporarily boosts the priority level of the thread to a higher
 value within the same class to give it CPU time. This scheduling logic
 is available only when PRIORITY=DYNAMIC and the thread is in the
 regular-application class.

 Application Configurable Areas
 ------------------------------

 An application can also change the way the OS/2 scheduler treats it.
 The API DosSetPrty() can be used to do this. This API can change the
 class of the application (being one of the idle-application,
 regular-application, and time-critical-application classes).
 DosSetPrty() also specifies the priority level with the priority
 class. This value can be from 0 to 31, where 0 is the lowest priority.
 Related to DosSetPrty() is the DosGetPrty() call, which retrieves the
 current process priority information from the system.

 System Threads
 --------------

 The threads of system programs are located at various levels. There
 are some, such as the spooler, that are in the idle-time class. Other
 threads are time critical. Also, there are classes between the
 regular-application and the time-critical classes that are reserved
 for system threads. An application program can set only its class to
 be in the idle, regular-application, or time-critical classes.

 Conclusion
 ----------

 For a general overview of the scheduler, please refer to Chapter 5 of
 Gordon Letwin's book, "Inside OS/2." For more information on the
 CONFIG.SYS commands PRIORITY, MAXWAIT, and TIMESLICE, refer to the
 "Microsoft OS/2 User's Reference" for Version 1.00. For more
 information on the DosGetPrty() and DosSetPrty() APIs, refer to the
 "Microsoft Operating System/2 Programmer's Toolkit Programmer's
 Reference" for Version 1.00.


 233. DosGetPid() Function Not Documented in Programmer's Reference

 Question:

 The DosGetPid() function is not documented in the "Microsoft Operating
 System/2 Software Development Kit Programmer's Reference." How is it
 used and what parameters are required?

 Response:

 Although the DosGetPid() function was not included in the SDK
 documentation, the API call works correctly. The following is a short
 example demonstrating how the call works (see the structure and
 function declarations in DOSCALLS.H for a description of the
 parameters of the DosGetPid() call):

 #include <doscalls.h>

 main()

 {
    int rc;
    struct ProcIDsArea ID;

    rc=DOSGETPID(  (char far *) &ID );
    printf("result of call is %d\n",rc);

    printf("curr pid is %d\n",ID. procid_cpid);
    printf("curr tid is %d\n",ID. procid_ctid);
    printf("parents pid is %d\n",ID. procid_ppid);
 }


 234. Mouse Driver Problems

 Problem:
    My application uses the mouse driver to handle the mouse movement
 and event processing. It simply reads the event queue and acts upon
 the events. Unfortunately, the current implementation of the mouse
 driver does not simply move a block cursor around the screen by just
 modifying attributes or something similar, but it actually copies the
 character that will be replaced by the mouse cursor and then replaces
 the character when the mouse moves from that position. This causes a
 problem for me because when a mouse click occurs, the character
 changes to reflect a click, but when the mouse driver moves the cursor
 from the current position, it destroys the new character.

 Response:
    The way the mouse driver works now is not likely to change in the
 near future. One workaround is to replace the character most recently
 clicked on when the mouse moves to another position at the time you
 detect a move (i.e., insert into your mouse movement response routine
 a flag for "just clicked somewhere, need to replace character at xy").
    A second workaround is to hide the mouse cursor and have the
 application paint its own cursor, e.g. by modifying attributes.


 235. OS/2 SDK: DosReadQueue() Documentation Error

 This article contains information on the documentation errors for the
 DosReadQueue() function call in the "Microsoft Operating System/2
 Programmer's Toolkit Programmer's Reference" for Version 1.00.

 Page 195 of the "Microsoft Operating System/2 Programmer's Toolkit
 Programmer's Reference" for Version 1.00 incorrectly states the
 following:

    PULONG pulBuf;       pointer to buffer for element

    It copies the element to the buffer pointed to by the pulBuf
    parameter.

    pulBuf               Points to the buffer that receives the
                         element being retrieved from the queue

 Instead, it should state the following:

    PULONG pulBuf;        pointer to buffer for element

    It sets the indicated buffer pointer to the address of the queue
    data.

    pulBuf                Points to the pointer that receives the
                          address of the element in the queue

 Page 197 of the "Microsoft Operating System/2 Programmer's Toolkit
 Programmer's Reference" for Version 1.00 incorrectly states the
 following:

    If the function waits, it clears the semaphore identified by the
    hsem parameter as soon as the element is retrieved.

 It should instead state the following:

    If fNoWait is DCWW_WAIT and there is no element available,
    DosReadQueue() will return immediately without retrieving an
    element from the queue, and the semaphore identified by the hsem
    parameter will be asynchronously cleared as soon as an element is
    written to the queue.

 These documentation errors were corrected in the "Microsoft Operating
 System/2 Programmer's Reference Volume 3 for Version 1.10." Included
 below is a copy of the documentation for DosReadQueue() from the
 Version 1.10 documentation:

 #define INCL_DOSQUEUES                                         [1.1]

 USHORT DosReadQueue(hqueue, pqresc, pcbElement, ppv, usElement,
     fWait, pbElemPrty, hsem)
 HQUEUE hqueue;          /* handle of queue to read                */
 PQUEUERESULT pqresc;    /* pointer to structure for PID and request
                            code                                   */
 PUSHORT pcbElement;     /* pointer to variable for length of
                            element                                */
 PVOID FAR * ppv;        /* pointer to buffer for element          */
 USHORT usElement;       /* element number to read                 */
 UCHAR fWait;            /* wait/no wait indicator                 */
 PBYTE pbElemPrty;       /* pointer to variable for priority of
                            element                                */
 HSEM hsem;              /* semaphore handle                       */

 The DosReadQueue function retrieves an element and then removes it
 from a queue. It copies the address of the element to the supplied
 pointer and fills a structure with information about the element.

 Parameter   Description
 --------------------------------------------------------------------
 hqueue      Identifies the queue to read. This handle must have been
             created or opened by using the DosCreateQueue or
             DosOpenQueue function.

 pqresc      Points to the QUEUERESULT structure that receives
             information about the request.

 pcbElement  Points to the variable that receives the length (in bytes)
             of the element.

 ppv         Points to the pointer that receives the address of the
             element in the queue.

 usElement   Specifies where to look in the queue for the element. If
             this parameter is 0x0000, the function looks at the
             beginning of the queue. Otherwise, the function assumes
             the value is an element identifier retrieved by using the
             DosPeekQueue function and looks for the specified element.

 fWait       Specifies whether to wait for an element to be placed in
             the queue, if the queue is empty. If this parameter is
             DCWW_WAIT, the function waits until an element is
             available. If this parameter is DCWW_NOWAIT, the function
             returns immediately with a code that indicates there are
             no entries in the queue.

 pbElemPrty  Points to the variable that receives the priority value
             specified when the element was added to the queue. This
             is a value in the range 0 through 15; 15 indicates the
             highest priority.

 hsem        Identifies a semaphore. This value can be the handle of
             a system semaphore that has been created or opened by
             using the DosCreateSem or DosOpenSem function, or it can
             be the address of a RAM semaphore. This semaphore would
             typically be used in a call to the DosMuxSemWait
             function to wait until the queue has an element. If the
             fWait parameter is DCWW_WAIT, hsem is ignored.

 Return Value
 ------------

 The return value is zero if the function is successful. Otherwise, it
 is an error value, which may be one of the following:

    ERROR_QUE_ELEMENT_NOT_EXIST
    ERROR_QUE_EMPTY
    ERROR_QUE_INVALID_HANDLE
    ERROR_QUE_INVALID_WAIT
    ERROR_QUE_PROC_NOT_OWNED

 Comments
 --------

 If the queue is empty, the DosReadQueue function either returns
 immediately or waits for an element to be written to the queue,
 depending on the value of the fWait parameter.

 Only the process that created the queue can call the DosReadQueue
 function.

 Example
 -------

 This example reads the queue and waits until an element is received.
 After the element is read and the data processed, the process frees
 the shared memory that was passed to it. This assumes the process
 writing to the queue created a shared-memory segment. For more
 information, see the DosWriteQueue function.

 QUEUERESULT qresc;
 USHORT cbElement;
 PVOID pv;
 BYTE bElemPrty;

 DosReadQueue(hqueue, /* queue handle                        */
     &qresc,          /* address of result structure         */
     &cbElement,      /* receives element number             */
     &pv,             /* receives data address               */
     0,               /* element number to read              */
     DCWW_WAIT,       /* waits until something is written    */
     &bElemPrty,      /* receives priority level             */
     NULL);           /* semaphore not needed, since waiting */
     .
     .   /* Process the data. */
     .
 DosFreeSeg(SELECTOROF(pv));    /* frees shared memory */

 See Also
 --------

 DosCreateQueue, DosMuxSemWait, DosOpenQueue, DosOpenSem, DosPeekQueue,
 DosWriteQueue, QUEUERESULT


 236. Getting Mouse Coordinate Information in Pixels

 Question:

 How do I get the MouReadEventQueue() call to return information in
 pixel coordinates instead of in character coordinates?

 Response:

 Getting the mouse to return information in pixel coordinates is not
 straightforward. You need to perform the following steps, in order,
 for it to work properly:

 1. MouOpen( )          -  Opens the mouse device driver

 2. MouSetDevStatus( )  -  Tells the mouse driver not to draw the pointer

 3. VioGetMode()        -  Gets the current state of the screen

 4. type=3              -  Changes it to graphics mode

 5. VioSetMode()        -  Sets screen to graphics mode

 6. MouReadEventQueue() -  Gets mouse events in pixel coordinates

 You need to do the VioSetMode() after the MouSetDevStatus() so that
 the mouse driver does not get confused by trying to draw a pointer
 that it does not know how to draw in graphics mode.

 The following is a short program that performs the above steps and
 then reads either up to 50 mouse events or until you push both buttons
 (you can run this with output redirected to a file and then look at
 the file and see the coordinates of the mouse events):

 #include "stdio.h"

 #include "doscalls.h"
 #include "subcalls.h"

 typedef unsigned int    Word;
 typedef unsigned long   DWord;

 struct {
          int row;
          int column;
        } point[50];

 main()

 {

    int i;
    unsigned short DeviceHandle;
    Word  Status;
    Word  NumberOfButtons;
    Word  NumberOfMickeys;
    Word  EventMask;
    Word  DeviceStatus;
    Word  ButtonMask;
    Word  ReadType;
    struct PtrLoc PtrPos;

    struct EventInfo Buffer;
    struct ModeData DisplayMode;
    int count;
    DisplayMode.length=12;

    Status = MOUOPEN( 0L, (unsigned far *) &DeviceHandle );
    printf("Open Status         : %5d  Handle=%d\n", Status,DeviceHandle);

    DeviceStatus = 0x0100;
    Status = MOUSETDEVSTATUS( &DeviceStatus, DeviceHandle );
    printf("SetDevStatus Status : %5d\n", Status );

    Status= VIOGETMODE( (struct ModeData far *) &DisplayMode, 0);
    printf("Status =%d\n",Status);

    DisplayMode.type=3;

    Status=VIOSETMODE( (struct ModeData far *) &DisplayMode, 0);
    printf("Status of viosetmode is %d\n",Status);

    ReadType = 1;       /* 1= wait */
    Buffer.Mask = 0;
    count=1;
    while ( (Buffer.Mask & 0x0014) != 0x0014 && count < 50) {
       Status = MOUREADEVENTQUE( &Buffer, &ReadType, DeviceHandle );
       point[count].row =   Buffer.Row;
       point[count].column = Buffer.Col;
       count ++;
    };

    Status = MOUCLOSE( DeviceHandle );
    DisplayMode.type=1;   /* reset to text mode */

    Status=VIOSETMODE( (struct ModeData far *) &DisplayMode, 0);

    for(count=1; count < 50; count++)
       printf("point  %d  are  row= %d    column=%d  \n",
              count,point[count].row,point[count].column);

    printf("Close Status        : %5d\n", Status );

    return 0;

 }


 237. Using Two Monitors with OS/2

 Problem:

 I have two monitors on my system (EGA and MDA). When I do the
 following, the monochrome screen group has its output frozen:

 1. Start an OS/2 CMD session and start something, e.g. a MAKE,
    running

 2. Switch to a screen group on the EGA (or the SHELL)

 Response:

 OS/2 does not support two monitors operating concurrently with each
 monitor in its own screen group. When a screen group is in the
 background, all of its output is sent to its virtual screen buffer and
 not to the actual screen. Therefore, the output on the other monitor
 is frozen.

 You can use the second monitor with CodeView and it will work properly.


 238. Determining the PID of the Current ForeGround Screen Group

 Question:

 Would you please clarify the documentation of the Global and Local
 information segments on Pages 130-132 of the "Microsoft Operating
 System/2 Programmer's Reference"? When I examine the word "PID of
 current foreground process," it is always the same as the local
 segment word, "Process ID of Parent." It is never the same as the PID
 of the executing program, even when the executing program was started
 from the Start a Program menu of the Program Selector so that it would
 be the root process in its screen group. Furthermore, I have not found
 any way to cause a nonzero value in the word "Current process is in
 foreground."

 Response:

 We consider the current foreground process to be the last process to
 read something from the keyboard (i.e., do a KBDCHARIN call). If you
 insert a KBDCHARIN call before the DosGetInfoSeg(), it will return the
 values you expect for current foreground PID and "Current process is
 in foreground."


 239. Booting OS/2 Directly into Real Mode

 Question:

 Is there a (programmatic) way under OS/2 to go straight into the DOS
 3.x box at boot time?

 Response:

 No, there is no way to go straight into the DOS 3.x box at boot time.
 OS/2 was primarily designed to be a protected-mode operating system
 so as to take advantage of the increased capability of the 80286 in
 protected mode. The real-mode box was provided as a way to maintain
 compatibility with old applications that have been written for MS-DOS.
 Therefore, OS/2 boots into the session manager or into a protected
 mode program, and from there you can enter real mode if you wish.


 240. Use of DosKillProcess to Kill Processes in Other Sessions?

 Question:
    To terminate(kill) processes in other sessions, can an
 application program use the DosKillProcess call? Can
 application programs know Process IDs in other sessions?

 Response:
    Processes can call DosKillProcess and terminate other
 processes in the system. However, the only way for a
 process to determine the PID of another process is the
 following:

    1. The process created the other process with
 DosExecPgm.
    2. A process uses some method of IPC to tell the other
 process its PID.


 241. Writing Device Drivers for Microsoft

 Are you an experienced device driver writer? Have you written both DOS
 and OS/2 device drivers? Are you interested in possible contract
 device driver development work?

 Please contact Microsoft if you are interested. Email "markmac" your
 name, phone number(s), and Microsoft will contact you. Please indicate
 that you are responding to this bulletin board item.


 242. Windowable Applications in Presentation Manager

 Question:

 Which OS/2 Version 1.00 applications will be windowable by the
 Presentation Manager in OS/2 Version 1.10?

 Response:

 A broad class of applications will be windowable by the Presentation
 Manager in its screen group. The following is a brief summary of OS/2
 Version 1.00 functionality that is not supported (the Presentation
 Manager specification included in the Microsoft OS/2 SDK describes
 these restrictions in more detail):

  1. Nonalphanumeric modes
  2. Asking for the selector of the physical screen buffer
  3. Keystroke and mouse monitors
  4. VioRegister, KbdRegister, and MouRegister
  5. VioSavRedrawWait
  6. VioSavRedrawUndo
  7. VioScrLock
  8. VioScrUnlock
  9. VioModeWait
 10. VioModeUndo
 11. VioSetFont
 12. VioGetFont
 13. VioSetState
 14. VioGetState
 15. Any of the mouse calls that attempt to set driver parameters (set
     scale factor, set hot key, ...) that would affect its use as a
     shared resource.


 243. Using KbdCharIn() from Multiple Threads of Same Process

 Question:

 We are having a problem using KbdCharIn() from multiple threads of the
 same process. One thread consists of a call to KbdCharIn() with wait
 specified. The other thread does a call to KbdCharIn() with no_wait
 specified to determine the scroll lock status.

 Using versions of OS/2 prior to the OS/2 Software Development Kit
 (SDK) Version 1.06, the no_wait thread returns immediately. However,
 using Version 1.06, the thread using no_wait waits until the key is
 pressed. Which behavior is correct?

 Response:

 The proper behavior is for the second thread doing the KbdCharIn()
 call to wait until the first KbdCharIn() is complete. This is the same
 for any of the subsystems: VIO, KBD, or MOU. There are
 per-screen-group semaphores that will only allow one thread per screen
 group to be executing within these subsystems. When you do a
 KbdCharIn() with wait specified, it claims a semaphore that the second
 call to KbdCharIn() should block on until the first call completes and
 the semaphore is released. If you have a requirement for another
 process in the same screen group to use the keyboard to interact with
 the user, one of the processes would have to open its own logical
 keyboard and use that keyboard, after getting the focus, so that the
 keystrokes go to the different processes in a controlled manner.

 You may want to look into using KbdGetStatus() to get the status of
 the keyboard and saving this information for your second thread to
 use, instead of using a second KbdCharIn() call, which might
 potentially consume another keystroke.


 244. Programmer's Reference Missing Documentation for DosSendSignal

 Problem:

 The DosSendSignal() call is not documented in the OS/2 SDK manuals.

 Response:

 The following is the documentation for DosSendSignal that should
 appear on Page 274 of the "Microsoft OS/2 Software Development Kit
 Programmer's Reference":

 int DOSSENDSIGNAL(ProcessID, SigNumber)
 unsigned ProcessID;   /* pid of root of subtree */
 unsigned SigNumber;   /* signal to send */

 The DosSendSignal() function sends a CTRL+C or CTRL+BREAK signal to
 the last descendant process in a command subtree that has a
 corresponding signal handler installed, as follows:

 Function                Meaning

 ProcessID    Specifies the process identification code (PID) of the
              root process of the subtree. It is not necessary that
              this process still be running, but it is necessary
              that this process be a direct child of the process
              that issues this call.

 SigNumber    Specifies the signal to send. It can be one of the
              following values:

              Value           Meaning
              0x001           SIGINTR (CONTROL-C)
              0x004K          SIGBREAK (CONTROL-BREAK)

 The return value is zero if the function is successful. Otherwise, it
 is an error value.

 The signal is sent by descending the process tree to the "leaf-most"
 process and then, starting with that process, look for one that has a
 handler installed for the corresponding signal. (The leaf-most process
 is the last process in the command subtree.) If a handler is found,
 give the signal to that process; otherwise, look at the parent
 process. Continue until either the signal is sent or the original
 process is looked at; the latter case is indicated by a unique error
 code.


 245. Which VIO Calls Are Allowed in a Window

 Question:
    If a full screen application is written using only the VIO and KBD
 subsystems, will it run in a window under Presentation Manager? Please
 give me as much detail as you can.

 Response:
    See Page 353 (and following) of the Presentation Manager
 Specification Volume 2 for a list of which VIO calls will be allowed
 for an application to be able to run in a window under PM. A beta
 version of the PM is scheduled to be shipped in the first quarter of
 next year and will contain further information on writing programs
 that will work with the Presentation Manager.


 246. Booting DOS and OS/2 From the Same Hard Disk

 Question:
    I have a Compaq 386, currently with DOS 3.1, and am doing Windows
 development. I will be getting one of the $3K OS/2 kits, and have the
 following question: If I had a 70M disk in my Compaq, would it be
 possible for me to set it up with two partitions, one with DOS 3.x,
 and one with OS/2, so I can do development on either environment,
 depending on how I boot the machine?
    I have heard of a machine having both DOS 3.x and XENIX in separate
 partitions.

 Response:
   The next update to the OS/2 SDK will contain an installation program
 that will let you install OS/2 on your hard disk in such a way that
 you can decide at boot time whether to boot MS-DOS or OS/2. Both
 MS-DOS and OS/2 will both be on the same hard disk, but after you boot
 you can organize your files on the two partitions as you wish.


 247. Problem in SSE Screen Editor

 Question:
    When I use the SSE screen editor built from the example programs in
 the SDK, the CARRIAGE RETURN LINE FEED pair at the end of each line in
 my source file is replaced with a LINE FEED when the file is resaved.

 Response:
    This editor is found in the directory /DEMOS/APPS/SSE.
    You are correct, the editor as shipped exhibits the problem you
 describe. The CARRIAGE RETURN LINE FEED pair delimiting the end of
 each line of text is not preserved--only the LINE FEED is kept. In
 other words, byte pairs of 0x0D,0x0A in the original file will be
 replaced with 0x0A only.
    The broken code is in the file SSEFILE.C, in the routine SAVEFILE.
 The code change necessary to correct this problem is as follows:

 OLD CODE

 /*  place lines in fbuffer */
     for (i = 0, j = 0; (i < TotalLines) && (!rc); i++) {
         if ((LineTable[i]->linelength) < (FBUFFSIZE - j)) {
             for (k = 0; k < LineTable[i]->linelength; k++, j++)
                 fbuffer[j] = LineTable[i]->firstchar[k];
             fbuffer[j] = '\n';
             j++;
         }

 NEW CODE

 /*  place lines in fbuffer */
     for (i = 0, j = 0; (i < TotalLines) && (!rc); i++) {
         if ((LineTable[i]->linelength) < (FBUFFSIZE - j)) {
             for (k = 0; k < LineTable[i]->linelength; k++, j++)
                 fbuffer[j] = LineTable[i]->firstchar[k];
             fbuffer[j] = '\r';
             j++;
             fbuffer[j] = '\n';
             j++;
         }


 248. Use Presentation Manager for Display Code

 Question:
    Should I write my new application using "ANSI.SYS" calls, or the
 Microsoft OS/2 Windows Presentation Manager?

 Response:
    Microsoft's OS/2 Windows Presentation Manager is the screen
 handling vehicle of choice for OS/2. The OS/2 Windows Presentation
 Manager (OS/2 PM) provides a superset of Microsoft's Windows for DOS
 functionality, and thus allows your application to have a standard
 interface on both OS/2 and MS-DOS. Using ANSI.SYS within a window
 running in the OS/2 PM domain will be possible, but is not the I/O
 handling method of choice. Some possible problems one may encounter
 are handling different window sizes, resizing, not having the ability
 to adapt to differing character sets, having to handle ALL keyboard
 and mouse I/O, etc. Even if your application is a character based
 application, the OS/2 PM provides you with a much richer environment
 and tool chest to work with. If you'd like to get a feel for what
 writing an application for the OS/2 PM is like, while still using DOS,
 purchase a Microsoft Windows for DOS Software Development Kit. The
 Windows for DOS and the OS/2 PM programming models are the same.


 249. Error in Make File for Huge-Memory Model Sample Application

    There is an error in the make file for the HUGE sample application
 that is included on the "Sample OS/2 System Programs Disk 2" (which is
 mislabeled Disk 1) for the Microsoft Operating System/2 Programmer's
 Toolkit. The original make file used the large-memory model compile
 option, -AL, instead of the huge-memory model option, -AH. The
 corrected make file follows:

    # Makefile for huge

    INC=..\..\..\include
    LIB=..\..\..\lib
    OPT=-AH -G0 -Lp -I$(INC)

    huge.exe: huge.c huge
       cl $(OPT) huge.c
       bind huge.exe $(LIB)\api.lib $(LIB)\doscalls.lib


 250. System Resource Limits for OS/2 Version 1.20

 Question:

 Is there any documentation on the limits set by OS/2 for system
 resources: file handles, pipe handles, semaphores, shared and
 nonshared segments, processes, threads, timers, sessions, queues, and
 queue entries? This information is very important for the system
 planner, because I'm sure that OS/2 cannot maintain an infinite number
 of these resources.

 Response:

 Below is a list of the current maximum values for the resources you
 listed. These values may change in future versions of OS/2.

 The following list is for the final version of OS/2 1.20. The SDK that
 you have may differ in some areas.

 Memory Segments
 ---------------

 There is an overall system limit of 7680 segments of all kinds. This
 includes: shared, nonshared, code, data, and swapped-out segments.
 Also included in this limit are: discarded segments (read-only or
 execute segments that will be reloaded later) and segments that could
 be demand loaded (for an application that is currently running) in the
 future.

 If swapping is enabled, there is a system limit of 2000 swappable
 segments. Once this limit of 2000 swappable segments is reached,
 further requests for swappable memory [which is what DosAllocSeg()
 gets] are denied.

 There is an overall limit of 6144 segments for all types of shared
 segments. These types are: shared, name-shared, code, and CS-aliased.
 For each process there is a limit of 30 name-shared segments.

 Each process is limited to 2048 nonshared segments.

 The recommended maximums for one application are: 300 shared segments,
 100 nonshared segments, and 10 name-shared segments.

 Processes and Threads
 ---------------------

 The maximum number of threads that can exist in the system at any one
 time is 512. Each process must have at least one thread; therefore,
 the maximum number of processes is also 512. Currently, the default
 maximum number of threads is set to 128. This can be changed by using
 the THREADS command in the CONFIG.SYS file. Each process is limited to
 no more than 56 threads.

 The recommended maximum number of threads for one application is 12.

 Screen Groups
 -------------

 Currently, there is a maximum of 16 screen groups.

 Timers
 ------

 DosStartTimer() and DosTimerAsync() start timers. The maximum number
 of active timers is equal to the current maximum number of threads.
 Each timer also requires a system semaphore; however, one system
 semaphore can be used for more than one timer.

 The recommended maximum number of timers for one application is 6.

 System Semaphores
 -----------------

 Currently, the maximum number of system semaphores is 256.

 The recommended maximum number of system semaphores for one
 application is 6.

 Queues
 ------

 The maximum number of queues is related to the number of queue
 entries. The more queue entries there are, the fewer queues there can
 be, and vice versa. With no queue entries, the maximum number of
 queues in the system is 409. If there is only one queue, the maximum
 number of queue entries is 3268.

 For each application, the recommended maximum number of queues is 6
 and 100 queue entries.

 File, Device, and Pipe Handles
 ------------------------------

 Each file or device needs one handle to reference it. Each pipe
 requires two handles. The maximum number of handles in the system is
 limited to 255. Handles created by DosDupHandle() have a system limit
 of 999 dup'd handles.

 The recommended maximum number of file handles for one application is
 20.

 Directory Handles
 -----------------

 DosFindFirst() allocates a directory handle. Each process is limited
 to 1000 directory handles.

 The recommended maximum number of directory handles for one
 application is 10.


 251. Incorrect Documentation on Category 9 IOCTL Call

 Problem:

 I am getting an invalid parameter error when I try to use the Category
 9 function 64 (read physical track command) IOCTL call.

 Response:

 This is a documentation error affecting Pages 273, 276, and 279 of the
 "Microsoft Operating System/2 Device Drivers Guide." The command field
 of the DevIOCtl call should be as follows:

    Bit    Value

    0      0   Track layout contains nonconsecutive sectors or
               does not start with sector 1.

           1   Track layout starts with sector 1 and contains only
               consecutive sectors.

 All other bits are reserved and must be zero.


 252. Process GP Faults when Signaling a Signal Handler

 Question:
    I wrote a simple program to trap a CTRL-C and display a message
 when the signal handler received a CTRL-C. When I press CTRL-C the
 program generates a GP fault. What is wrong?

 Response:
    The signal handler must declare the arguments that it receives even
 if it does not do anything with them. See the following example.

    However, note that the following is a very simple example of a
 signal handler. This handler does not acknowledge the signal.
 Therefore the screen group will be hung after the first signal is
 received. This is because only one signal is allowed to be waiting for
 acknowledgment and so other incoming signals are lost. Since all
 future CTRL-Cs are lost, there is not an easy way to kill this
 program. For a better example of signals, see the example on the OS/2
 SDK disks named SIGNAL.C.

 #include <doscalls.h>

 unsigned old_action;
 unsigned far * old_action_p = &old_action;
 unsigned flag;
 unsigned far * flag_p = &flag;
 unsigned long old_handler;

 void far pascal handler(sig_arg, sig_num) /* you must declare these */
 unsigned sig_arg, sig_num;            /*  two arguments even though */
                                       /* nothing is done with them. */

 {
     *flag_p = 1;

 }

 main(argc,argv)
 int argc;
 char * argv[];
 {
     printf("dossetsighandler value %x\n",
      DOSSETSIGHANDLER(handler, 0L,
        0L,2,1));

     while (1)
  if (flag) {
      flag = 0;
      printf("event_happened\n");
  }
 }


 253. Saving Registers Across a Call to PhysToVirt

 Question:
    Does the PhysToVirt Device Help call preserve the caller's BP
 register?

 Response:
    The PhysToVirt call is only guaranteed to preserve the segment registers
 CS, SS, and either DS or ES, depending on the value of DH at the time the
 call is made, and the SP register. Any other registers that you need to
 preserve need to be stored and reloaded across the call.


 254. DEL Command Quits Too Soon on Multiple Deletions

 Question:
    Take three directories called A, B, and C. Directory A is empty; B
 and C have files in them. The command "DEL A B C" quits after the "are
 you sure" prompt on the first directory (A), leaving the B and C
 directories intact. Directory A being empty shouldn't have any effect
 on B and C. The same sort of thing happens if A, B, and C are files
 and A is read-only.

 Response:
    Not finding any files is considered an error from delete. It is
 used to set the error level and can be checked for by programs. All
 internal commands that accept multiple arguments like DEL, MKDIR, and
 RMDIR will all quit if there is an error in one of the arguments. This
 is because they work from left to right and what is on the right often
 depends on what was on the left being successful.


 255. Global Seg Current Foreground PID Is Not Always Current

 Problem:
    Global Seg Current Foreground PID is not always current. The only
 time the current foreground PID in the global information segment is
 updated is when the process occupying the current foreground screen
 executes a KBDCHARIN. Therefore, if a process (especially a detached
 process) does a DOSGETINFOSEG it will not always be able to correctly
 discern if there is a process other than the command line prompt
 active. Basically, the Global Seg Current Foreground PID seems to
 often not be current.

 Response:
    This problem will be fixed in the 1.1 release of OS/2 with the
 Presentation Manager.


 256. "COPY *.* *.BAK" Does Not Always Give Desired Results

 Question:
    "COPY *.* *.BAK", when there is an opening in the second position
 of the FAT, returns an error after the first copy and quits. Copy
 should be smart enough not to try to recopy a file that it has already
 copied. This is also a problem in PC-DOS.

 Response:
    Use XCOPY /p. There is nothing that can be done with a GLOBAL type
 copy that essentially stumbles upon itself to copy. It should not
 usually be necessary to use that type of syntax during a copy
 operation.


 257. VioGetConfig Values Missing from Documentation

 Question:

 I am running OS/2 with a VGA adapter/monitor. When I do a VioGetConfig
 I get AdapterType 3 and DisplayType 4, neither of which is listed in
 the documentation.

 Could you please give me the complete list of values?

 Response:

 The adapter type values should be as follows:

 Value       Adapter

   0         Monochrome / printer adapter
   1         Color graphics adapter
   2         Enhanced graphics adapter
   3         VGA
   4-6       Reserved

 The values for display type should be as follows:

 Value       Display

   0         Monochrome display
   1         Color display
   2         Enhanced color display
   3         PS/2 Monochrome display
   4         PS/2 Color display
   5-8       Reserved


 258. When Processes Receive Priority Boosts by the System

 Question:
    From experimentation I have determined that the foreground screen
 group is given higher priority than either processes in background
 screen groups or detached processes. Is there a rule for how the
 priorities of various processes are adjusted based on their screen
 group's state?
    Given a process that creates children within the same screen group,
 detached children, and children in new screen group, how does that
 process ensure that all its children compete on an equal basis for the
 system resources?

 Response:
    Processes are given temporary priority boosts under the following
 circumstances:

    1. They are in the current screen group.
    2. More than MAXWAIT number of seconds has elapsed since the
 process was last executed. The priority of the process will be boosted
 for one timeslice. MAXWAIT is a parameter in the config.sys file.

    You can disable the dynamic variation of priority by using the
 PRIORITY= parameter in config.sys. This can be set to either absolute
 or dynamic, with dynamic the default. Generally we presume that
 processes in the foreground have your attention and therefore should
 be given a slight boost over processes in the background.
    You could use the DosSetPrty call to increase the priority of
 background processes/threads so that all your threads ran at
 essentially the same level even though some of them were originally
 lower and received a boost by the system because they were in the
 foreground.


 259. COMP Doesn't Handle Environment Parameters Correctly

 Question:

 Assume there is a directory D:\TEST and two identical files TEST1.DAT
 and TEST2.DAT. After you set the following environment variable in
 protect mode, as follows

 SET Z:=D:\TEST\

 you will be able to use variable %Z:% in COMP from the protect mode
 command line, as follows:

 COMP %Z:%TEST1.DAT %Z%TEST2.DAT

 The utility compares these two files correctly no matter what the
 current directory and/or drive is.

 However, after the comparison, the utility asks if you want to compare
 more files. If you answer "Y," it asks the first filename and then the
 second. If the first filename is entered as %Z:%TEST1.DAT and the
 second as %Z:%TEST2.DAT, the error message "SYS1171: The system cannot
 find the d:%Z:%TEST1.DAT path" appears and no comparison occurs
 although the same syntax is valid when typing from the protect mode
 command line. This means that COMP is inconsistent with itself.

 Response:

 COMP is consistent. COMP does not handle the conversion of "SET"
 variables at all. This is done by the command interpreter in protect
 mode and by the batch file processor. We agree that this sounds like a
 good enhancement for the COMP utility and will be considered for
 inclusion in a future release. It is now, however, working as
 designed.


 260. SYS Command Option /S Documentation Error in User's Reference

 Question:

 The SYS command has documented an option /S that is not recognized by
 the command. The /S is supposed to copy all the files in the
 FORMATS.TBL file. Is there a problem in the SYS command or is it no
 longer supported?

 Response:

 The SYS command copies only the system files (OS2BIO.COM and
 OS2DOS.COM) onto the disk you are SYS'ing. The /S command is no longer
 valid. This is a documentation error on Page 193 of the "Microsoft
 Operating System/2 Software Development Kit User's Reference."


 261. DOSWRITE Error Conditions Not Well Documented

    The OS/2 documentation section on DOSWRITE needs a better
 description of the out-of-disk-space condition. Add the following to
 the Remarks section on Page 333 of the "Microsoft Operating System/2
 Programmer's Reference":

       "Note that in order to determine if the entire buffer requested
    was successfully written it is necessary to check the return code
    from DOSWRITE for error and also to check that the 'BytesWritten'
    value returned is the same as the 'BufferLength' parameter.
    Insufficient disk space is not indicated with an error return."


 262. Swapper Run from Command Line Crashes System

 Problem:
    In the SDK release, if the swapper is run from the command line,
 the system halts with an internal error.

 Response:
    In the SDK release if the swapper is run from the command line, the
 system does halt with an internal error. The solution is to not invoke
 the swapper from the command line. The swapper will be correctly
 invoked by setting MEMMAN=swap in the config.sys file.


 263. What Happens when DosReAllocSeg Fails

 Question:
    What condition is the allocated memory in after attempting a
 DosReAllocSeg if the DosReAllocSeg failed? Is it left alone or freed?

 Response:
    If the DosReAllocSeg call fails, the memory will be left alone. It will
 not be freed or have its size changed.


 264. Device Driver Stack Size

 Question:
    How much stack space is available on entry to an OS/2 device
 driver?

 Response:
    When the device driver's strategy routine is entered, it is running
 on the kernel stack of the calling thread. Therefore, the amount of
 stack space that is available depends on the state of the thread that
 called it. When the device driver is entered at interrupt time it is
 running on the interrupt stack, which is not very big.
    We recommend that you keep your use of the stack to a minimum
 within device drivers. At strategy time you should keep your stack use
 to under 500 bytes and at interrupt time you should use less than 100
 bytes of stack space.


 265. Additional Semaphore Information

 The description of RAM semaphores and how they compare/contrast to
 system semaphores was not well described in the "Microsoft OS/2
 Programmer's Guide" (Pages 103+). The following is a more complete
 description of the two types of semaphores.

 The semaphore functions provided by OS/2 allow multiple processes (or
 threads) to control access to serially reusable resources in an
 efficient, well-controlled fashion. Two types of semaphores are
 supported: RAM semaphores and system semaphores. This requires the
 using processes to have shared access to the same area of memory in
 which the RAM semaphore is defined. The affected processes define the
 semaphore by convention (mutual agreement) as a particular double-word
 in some shared storage area.

 The system semaphore is a full-function mechanism providing control
 between any processes and threads with OS/2 managing the storage for
 the semaphore data structure. System semaphores are defined within the
 file-system name space as a "pseudo-file" instead of a RAM location.
 The semaphore is a "pseudo-file" in that its name takes the form of a
 file in the subdirectory "SEM" although this subdirectory does not
 actually exist; system semaphores and their names are kept in memory.

 The following is a comparison of RAM and system semaphores:

 1. System semaphores are more flexible and easier to use than RAM
    semaphores because of the following qualities:

    a. They can be used by processes that share no memory.

    b. Their ownership is relinquished when the owner terminates.

    c. In future versions of OS/2, when protection mechanisms are added
       to the OS/2 file system, access to system semaphores will be
       protected by the same mechanism that protects access to files.

    d. Future versions that manage file names across a network could
       also support system semaphores across the network between
       processes on different machines.

 2. From a performance standpoint, RAM semaphores offer a performance
    advantage over system semaphores because the handle used to refer
    to them is actually the address of the semaphore, while the handles
    of system semaphores must be translated to the memory address of
    the semaphore data structure.

 3. RAM semaphores should not be used between processes to control
    access to a serially reusable resource because it will not be
    possible to relinquish the semaphore, should the owner end
    abnormally. In the case of system semaphores, should the owner end,
    OS/2 will release the semaphore and notify the next thread that
    gets the semaphore that the owner ended while holding the
    semaphore.

 When discussing semaphores, the terms "owned," "unowned," "set," and
 "clear" are used to describe the state of a semaphore at a particular
 time. The concept of ownership applies only to system semaphores that
 are created with exclusive ownership indicated. When a semaphore is
 owned, it is an error for a thread other than the owner to try to
 modify that semaphore.

 The handle for a RAM semaphore is the address of the double-word of
 storage allocated. If this address of the RAM semaphore is invalid,
 the system will terminate the process with a general protection fault.
 The semaphore system calls will not return an error code when passed
 an invalid semaphore handle.

 The functions provided to support semaphores in their classical
 serialization mode of usage are DosSemRequest and DosSemClear. In
 addition to these functions, there is a set of functions for using
 semaphores as an efficient means of signaling between threads. These
 functions are DosSemSet, DosSemSetWait, and DosSemWait.

 To wait for the occurrences of multiple events, there is a multiple
 semaphore wait function, DosMuxSemWait, described on Page 179 of the
 "Microsoft Operating System/2 Programmer's Reference."


 266. Detecting Extra Keys on Enhanced Keyboards

 Question:
    We are trying to make our keyboard routine act the same under OS/2
 as it does under DOS. For this reason we want the ARROW keys to first
 return a 00 and then the code (such as 80).  The numeric ARROW keys
 appear to work this way (with NUM LOCK off).  However, the gray ARROW
 keys on the PS/2 Model 80 behave differently under OS/2 and DOS.
 Under DOS they are the same as the numeric arrow keys.  Under OS/2 it
 appears that they return a 224 as the char_code and the code is in
 scan_code.

 Response:
    Under OS/2 you are able to tell the difference between the numeric
 ARROW keys and the gray ARROW keys. You should write your program to
 be sensitive to either value in the char_code field (0 or 224) if you
 wish to be able to run the same program in DOS and OS/2.  It will work
 in OS/2 if you don't, but you would then have to always use the
 numeric ARROW keys and special function keys rather than the gray keys
 on enhanced keyboards.


 267. Using DOSFREESEG

 Question:
    Is the DOSFREESEG call used to free up memory allocated with
 DOSALLOCSEG or DOSALLOCHUGE? Or, can we use DOSFREESEG for either
 allocation scheme?

 Response:
    You may use DOSFREESEG for either allocation scheme.


 268. VGA Mouse Cursor

 Problem:
    I am having problems using my mouse in applications in real mode
 (such as Word Version 4.0) in VGA mode.

 Response:
    The problem is that POINTDD.SYS currently only supports graphics
 cursors for display modes 0-7, which does not include the VGA modes.


 269. When to Call UnPhysToVirt in the Device Driver

 Question:
    The documentation for the DevHelp UnPhysToVirt states:
 "UnPhysToVirt must be called by the same procedure that issued
 PhysToVirt when use of the converted address is completed and before
 the procedure returns to its caller."

 Response:
    It is correct that you must be in the same procedure when you do
 the UnPhysToVirt as when you did the PhysToVirt. This is because if a
 mode switch occurred on the PhysToVirt call, then the return address on
 the stack might not be valid for the current mode when you tried to
 return from the procedure.


 270. Device Driver Memory Access

 Question:
    We need to pass information between the PC and some card that has
 512K of memory accessible to the PC through a 64K window at address
 D000:0000. We are writing a device driver to interface with this card.
 What does the device driver have to do to access shared memory at
 D000:0000?

 Response:
  Since the memory is either between 640K and 1 megabyte or above the
 range of contiguous memory you can use the Selector : offset pair
 returned from either PhysToVirt or PhysToUvirt without needing to
 verify or lock down the memory, since memory in these ranges is
 ignored by the OS/2 memory manager.


 271. EGA.SYS Error when Booting OS/2

 Question:
    Do I need EGA.SYS at all? If so, how do I get one that works?

 Response:
    This is only for the real mode box. Programs such as Word need it
 to draw the mouse cursor on the screen.
    If your system is set up to run only in protected mode then you
 will get this error. Remove the line in the STARTUP.CMD file that
 says "Protectonly=yes". This line is needed only if you want a 3x box.


 272. Inherited Attributes of Files

 Question:
    What attributes of a file handle are inherited by child processes
 that inherit the handle?

 Response:
    The inheritance flag and the write through bits are not inherited
 by child processes. The other attributes of a file handle are
 inherited by child processes.


 273. File System ID

 Question:
    Page 234 of the OS/2 programmer's reference mentioned the parameter
 File System ID for DOSQFSINFO. Could you please tell us what it means
 and what it is used for?

 Response:
    The File System ID parameter returns the file system ID/number for
 the file system; there is currently only one file system for OS/2.


 274. Running Character Applications with PM Applications

 Question:
    Can the other 11 sessions run while the Presentation Manager is
 running in session 1?

 Response:
    Yes. But you can only have one Presentation Manager screen group.


 275. RM and Losing Disk Space

 Question:
    OS/2 seems to be loosing disk space quite rapidly. Two days ago I
 had 15 megabytes free on my D partition. Today I have none. I have
 carefully checked all files; CHKDSK /f does not help.
    I have found that RM places deleted files into a "deleted"
 subdirectory. This continues to consume disk space. To recover the
 disk space, I must "del deleted" in each directory. Is there a better
 way to do this?

 Response:
    RM comes with the SDKED editor; it is documented on Page 36 of the
 user's guide to the SDKED editor.
    Two other commands, UNDEL and EXP, may be used on files that were
 "deleted" with RM. UNDEL restores a specified file from the deleted
 subdirectory. EXP expunges the contents of a deleted subdirectory--for
 example, "EXP /r c:\" will recursively expunge all the deleted
 subdirectories starting from the root of C.


 276. Calling C Routines from a Device Driver

 Question:

 How can I call a routine written in C from an OS/2 device driver
 written in assembly language?

 Response:

 Below is a simple device driver that calls a C routine. The following
 is a list of the problems we encountered:

 1. Segment names in the assembly code must match those generated by
    the C compiler (_DATA and _TEXT).

 2. The order of the segments must be defined in the assembly so that
    all the data and code are each in one segment. Refer to the top of
    the STRAT.ASM file.

 3. C code must be compiled with Gs to disable stack checking.

 4. C code should not use any C run-time routines because the C
    routines are nonreentrant; assume SS==DS, and have stack checking
    enabled.

 The C routine (C_ROUTINE) is called from init time and when a read of
 the device is done. It does not perform any function other than that
 it adds the numbers from 0 to whatever number you call it with;
 however, it demonstrates calling C in a device driver and passing
 parameters to the C routine.

 You do not need all the declarations in MYDEVICE.INC, which was copied
 from another device driver and was not cut down to the bare minimum.

 mydevice.def ===========================================================
 LIBRARY
 PROTMODE

 mydevice.inc ===========================================================

 ;     Include file for mydevice device driver
 ;
 ;     contains macro definitions for the driver routines
 ;
 ;    By John Bartlow
 ;

 WO      EQU     WORD PTR
 BY      EQU     BYTE PTR

 ALLOC_MEM_LOW   EQU 1
 ALLOC_MEM_HIGH  EQU 0
 STDOUT          EQU 1

 MemBufSz        EQU 256

 ToDS_SI         EQU 0
 ToES_DI         EQU 1

 ;=====================================================================
 ;
 ; Local Data Area
 ;   LocalData structure is allocated on the stack and initialized by the
 ;   Strategy routine for each device driver instance.
 ;
 LOCALDATA STRUC
     LD_PTRSAVE  DD   (?)                ; Far pointer to the request header
 LOCALDATA ENDS

 ;****   DevHelp - a macro to call DevHlp
 ;

 DEVHELP MACRO   func
         mov     dl,DEVHLP_&func
         call    [DevHlp]
 ENDM

 FX_LAST_CLOSE   EQU     00000010b       ;  last close in progress

 PhysAddr struc
         _lo     dw      (?)     ; low word of a 32-bit pointer
         _hi     dw      (?)     ; high word of a 32-bit pointer
 PhysAddr ends

 DataPacket Struc                ;  data packet for IOctl to register
             Placement   dw  ?        ;  a monitor
             Index       dw  ?
             Inbuff      dd  ?
             Outbuff     dw  ?
 DataPacket ends

 GetLocInfoSeg    equ   2      ; parameters for dh_GetDosVar
 GetYeildFlag     equ   7

 BUFFSIZE         equ   256
 MIN_BUFFSIZE    equ     10
 TimerInterval   equ    100    ; Call timer routine every 100 tics

 mydevice. ===========================================================
 #
 #**     makefile for OS/2 simple sample device driver
 #

 ASM=masm

 #       Definitions for assembler

 #       To make debug version use --
 #       AFLAGS= -Mx -t -P -DSAMPDEBUG -L

 #       To make non-debug version use --
 #       AFLAGS= -Mx -t -P

 #       -Mx -- preserve case sensitivity in external names
 #       -t  -- "terse" mode, don't print out unneeded messages
 #       -P  -- check for IMPURE code
 #       -L  -- Create a listing file
 #       -n  -- Suppress tables in listing
 #       -Dsymbol  -- Define assembler symbol

 AFLAGS= -Mx -t -P -DMYDEBUG -L -n

 #       Definitions for new style linker

 LINK=link
 LFLAGS=/nod /map
 LIBS=c:\lib\doscalls.lib

 #       List of object files required
 #       ORDER IS IMPORTANT!
 #       "sample" must come first, "sampinit" must be last
 OBJS=   strat.obj init.obj csub.obj

 #       Production rules

 strat.obj: strat.asm mydevice.inc
         $(ASM) $(AFLAGS) strat.asm,strat.obj;

 mysubs.obj: mysubs.asm mydevice.inc
         $(ASM) $(AFLAGS) mysubs.asm,mysubs.obj;

 csub.obj: csub.c
         cl -Lp -c -Asnw -G2s -Zp -Od -c csub.c

 init.obj: init.asm mydevice.inc
         $(ASM) $(AFLAGS) init.asm,init.obj;

 mydevice.sys: $(OBJS) $(LIBS) mydevice.def
         $(LINK) $(LFLAGS) @mydevice.lrf
         mapsym  mydevice

 strat.asm =============================================================
 .286p

 _DATA   SEGMENT  WORD PUBLIC 'DATA'
 _DATA   ENDS
 CONST   SEGMENT  WORD PUBLIC 'CONST'
 CONST   ENDS
 _BSS    SEGMENT  WORD PUBLIC 'BSS'
 _BSS    ENDS

 _TEXT   SEGMENT  WORD PUBLIC 'CODE'
 _TEXT   ENDS

 DGROUP  GROUP   CONST, _BSS, _DATA
         ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP

 include devhlp.inc
 include devsym.inc
 include dosmac.inc
 include error.inc
 include ioctl.inc
 ;  include infoseg.inc

 include mydevice.inc

 EXTRN CmxInit : NEAR
 EXTRN C_ROUTINE : NEAR

 ATTRIB EQU  DEV_CHAR_DEV OR DEV_30 OR DEVLEV_1 OR DEV_GIOCTL

 _DATA SEGMENT WORD PUBLIC 'DATA'

 ;  The header must be at the head of the data segment

 MyDevice SysDev < -1,ATTRIB, OFFSET _TEXT:Strategy,0,'MYDEVICE'>

 .ERRNZ  OFFSET _DATA:MyDevice            ; enforce the above warning

 EVEN
 CommandTab  LABEL   WORD
     DW      OFFSET _TEXT:CmxInit      ;0 :  Initialization routine
     DW      OFFSET _TEXT:CmxUnknown   ;1 :
     DW      OFFSET _TEXT:CmxUnknown   ;2 :
     DW      OFFSET _TEXT:CmxUnknown   ;3 :
     DW      OFFSET _TEXT:CmxRead      ;4 :  Read from device
     DW      OFFSET _TEXT:CmxUnknown   ;5 :
     DW      OFFSET _TEXT:CmxUnknown   ;6 :
     DW      OFFSET _TEXT:CmxUnknown   ;7 :
     DW      OFFSET _TEXT:CmxWrite     ;8 :  Write to device
     DW      OFFSET _TEXT:CmxUnknown   ;9 :
     DW      OFFSET _TEXT:CmxUnknown   ;10:
     DW      OFFSET _TEXT:CmxUnknown   ;11:
     DW      OFFSET _TEXT:CmxUnknown   ;12:
     DW      OFFSET _TEXT:CmxOpen      ;13:  Open
     DW      OFFSET _TEXT:CmxClose     ;14:  Close
     DW      OFFSET _TEXT:CmxUnknown   ;15:
     DW      OFFSET _TEXT:CmxUnknown   ;16:

 MAXCMD = (($ - CommandTab)/2) -1

             PUBLIC  TimeCount,DevHlp,Buff,YeildAddr

 Buff        dd      ?               ; pointer to allocated buffer to xfer
                                     ;  through
 DevHlp      dd      ?               ; Pointer to device help routine
 TimeCount   dw      0
 ReqPacket   dd      0               ; address of request packet
 YeildAddr   dd      ?               ; address of yield flag
 WritMsgLen  dw      ?               ; Length of message in buff
 OpenCount   db      0            ; count of number of opens on this device
 PID         dw      ?               ; PID of task making open request

 _DATA ENDS

 _TEXT SEGMENT WORD PUBLIC 'CODE'
         ASSUME cs:_TEXT

 ;  The strategy routine is called by DOS to handle I/O requests to the
 ;  device
 ;
 ;  Entry
 ;        es:bx -> request packet
 ;        ds  data segment for mydevice.sys

 ;  Exit
 ;        result of operation set in request packet status field
 ;
 ;  Uses
 ;        ax, di, ds, es, bx

 Procedure Strategy,FAR
        ASSUME cs:_TEXT, ds:_DATA, es:NOTHING, ss:NOTHING

 IFDEF MYDEBUG
        int 3
 ENDIF
        mov         di,bx           ; (es:di) -> Request packet

        SUB         SP,SIZE LOCALDATA
                          ; reserve space for LocalData (Defined in .INC file)
        MOV         BP,SP
                          ; ...referenced with positive offsets

        MOV         [BP].LD_PTRSAVE._lo,BX  ; Save the virtual address  (ES:BX
        MOV         [BP].LD_PTRSAVE._hi,ES  ; ...of the Request Packet.

        xor         bx,bx
        mov         bl,es:[di].pktcmd   ; get command from request packet

        cmp         bl,MAXCMD           ; is it out of range ?
        ja          CmxUnknown

        shl         bx,1

 ; Entry to command handlers
 ; (es:di) -> request packet

        jmp         CommandTab[bx]

 Entry CmxDone
        mov     ax,STDON
        jmp     SHORT cmx

 Entry CmxUnknown           ;  error unknown command
        mov     ax,STDON OR STERR OR ERROR_I24_BAD_COMMAND
        JMP     SHORT cmx
 Entry CmxNotReady
        mov     ax,STDON OR STERR OR ERROR_I24_BAD_COMMAND
        jmp     short cmx

 Entry CmxBusy
        mov     ax,STDON OR STBUI
        JMP     SHORT cmx

 Entry CmxGenFail
        mov     ax,STDON OR STERR OR ERROR_I24_GEN_FAILURE

 cmx:   sti
        LDS     BX,[BP].LD_PTRSAVE         ;Load packet address back into DS:B
        MOV     [BX].PKTSTATUS,AX          ;Mark operation complete

        MOV     SP,BP                      ;Re-Load SP form BP (clean up stack
        ADD     SP,SIZE LOCALDATA          ;And de-allocate local data space

        ret

 EndProc Strategy

 ;************************************************
 ;  The Open routine gets the PID of the process opening the device
 ;  and then checks to see if the device is already open.
 ;  If it is open by the same process we increment the counter.
 ;  If it is open by another process we fail then open request.
 ;  If it is not open we save the PID of the opening process and
 ;    return DONE.
 ;
 ;************************************************

 Procedure CmxOpen,NEAR
     ASSUME cs:_TEXT,ds:_DATA,es:NOTHING,ss:NOTHING

        jmp  CmxDone
 EndProc CmxOpen

 ; **********************************************
 ;   We get the PID of the closing process and check it against the opening
 ;   processes PID.
 ;   If they are the same we decrement the open counter and if it reaches 0.
 ;   We set the PID to 0 so subsequent closes will fail due to a bad PID.
 ;
 ; **********************************************

 Procedure CmxClose,NEAR
     ASSUME cs:_TEXT,ds:_DATA,es:NOTHING,ss:NOTHING

        jmp     CmxDone

 EndProc CmxClose

 ; ***********************************

 ;========================================================================
 ;
 ;           READ
 ; Get the transfer address, which is PHYSICAL
 ; Convert it to VIRTUAL
 ; Load it into registers to do transfer from "readmsg" area
 ;   Set up es:di for destination
 ;   Set up ds:si for source
 ;   Set up cx for number of characters
 ;   Do movsb to move data
 ;
 ;========================================================================

 Procedure CmxRead,NEAR
         ASSUME  DS:_DATA

         push    25                              ;  A parameter to pass
         call    C_routine
         pop     ax                              ;  a return value

         mov     cx,es:[di].IOcount              ; count of chars to move in c
         cmp     cx,WritMsgLen                ; make sure we have enough chars
         jl      rd01
         mov     cx,WritMsgLen                   ; Only do max of WritMsgLen
 rd01:
         mov     es:[di].IOcount,cx              ; Assume transfer works
         mov     ax,es:[di].IOpData._hi
         mov     bx,es:[di].IOpData._lo          ; ax:bx = physycal xfer addr
         mov     dh,ToES_DI                      ; want result in es:di
         DEVHELP PHYSTOVIRT
         jnc     rd00
         jmp     CmxGenFail                      ; error on conversion
 rd00:
         mov     ax,BUFF._hi
         mov     bx,BUFF._lo                     ; ax:bx = physical addr of sr
         mov     dh,ToDS_SI                      ; want result in ds:si
                                                 ; cx already set up
         push    ds                              ; save data segment ptr
         DEVHELP PHYSTOVIRT
         jnc     rd02
         pop     ds
         jmp     CmxGenFail                       ; error on conversion
 rd02:
         rep     movsb                           ; move the data
         pop     ds
         ASSUME  DS:_DATA
         DEVHELP UNPHYSTOVIRT                    ; Release the virtual address

         jmp     CmxDone                       ; done, no error

 EndProc CmxRead

 ;**************************************
 ;  Write routine takes a buffer of _DATA pointed to by the request Packet
 ;  and copies it to the buffer previously allocated by the init routine to
 ;  store the data.
 ;**************************************

 Procedure CmxWrite,NEAR
         ASSUME  DS:_DATA

         mov     ax,BUFF._hi
         mov     bx,BUFF._lo                    ; ax:bx = physical addr of des
         mov     dh,ToES_DI                      ; want result in es:di
         mov     cx,MemBufSz                     ; cx = size of segment we wan
         DEVHELP PHYSTOVIRT
         jnc     wr00
         jmp     CmxGenFail                      ; error on conversion
 wr00:
         push    ds                              ; save data seg pointer
         ASSUME  DS:NOTHING
         lds     si,[bp].LD_PTRSAVE              ; ds:si now point to packet
         mov     cx,ds:[si].IOcount              ; count of chars to move in c
         cmp     cx,MemBufSz                   ; make sure request isn't bigge
                                                 ; than buffer size
         jl      wr01
         mov     cx,MemBufSz                     ; Only do max of MemBufSz
                                               ; Also sets up cx for phystovir
 wr01:
         mov     ax,ds:[si].IOpData._hi
         mov     bx,ds:[si].IOpData._lo          ; ax:bx = physical xfer addr
         mov     dh,ToDS_SI                      ; want result in ds:si
         mov     ds:[si].IOcount,cx              ; assume transfer works
         pop     ds                              ; we're back
         ASSUME  DS:_DATA
         mov     WritMsgLen,cx                   ; save length transferred
                                                 ; for read
         push    ds                              ; going to need it again
         DEVHELP PHYSTOVIRT
         jnc     wr02
         pop     ds
         jmp     CmxGenFail                       ; error on conversion
 wr02:
         rep     movsb                           ; move the data
         pop     ds                              ; get data seg back
         DEVHELP UNPHYSTOVIRT                   ; Release the virtual addresse

         Jmp     CmxDone                      ; done, no error

 EndProc CmxWrite

 _Text ends

 END

 init.asm ==================================================================

 .286p

 include devhlp.inc
 include devsym.inc
 include dosmac.inc

 include mydevice.inc

     EXTRN DOSPUTMESSAGE:FAR

     EXTRN   CmxDone : Near
     EXTRN   CmxGenFail : Near
     EXTRN   DOSPUTMESSAGE:FAR

     EXTRN   TimeCount : WORD
     EXTRN   DevHlp : DWord
     EXTRN   Buff : DWORD               ; Physical addr of allocated buffer
     EXTRN   YeildAddr : DWORD
     EXTRN   C_ROUTINE : NEAR

 _DATA Segment Word Public 'DATA'

 EVEN

 END_DATA             dw  ?      ; pointer to use when freeing _DATA after ini

 SignOnMsg           db      'Hello world this is my device driver'
 SignOnLen = $ - SignOnMsg

 _DATA    Ends

 _TEXT Segment Word Public 'CODE'
     ASSUME cs:_TEXT,ds:_DATA,es:NOTHING,ss:NOTHING

 ENDCODE     EQU     $

 ; CmxInit - initialize the device driver
 ;
 ;  - Saves pointer to DevHlp
 ;  - Stores pointers to end of code and _DATA in the request packet
 ;
 ;   Entry
 ;       (es:di) -> request packet
 ;
 ;   Exit
 ;       (es:di).InitEcode = end of code
 ;       (es:di).InitEdata = end of _DATA
 ;   Uses
 ;       ax,bx,es,ds,si,di

 Procedure CmxInit,NEAR
     ASSUME cs:_TEXT, ds:_DATA, es:NOTHING, ss:NOTHING

 ; Save pointer to DevHlp
 IFDEF MYDEBUG
      int 3
 ENDIF
         push    25
         call    C_ROUTINE

         mov     bx,es:[di].IOpDATA._hi        ; save the pointer to the DevHl
         mov     [DevHlp]._hi,bx               ; routine
         mov     bx,es:[di].IOpDATA._lo
         mov     [DevHlp]._lo,bx

 ;  Get Address of Yeild flag and store in YeildAddr

         mov     al,GetYeildFlag
         DEVHELP GetDosVar
         mov     [YeildAddr._hi],ax
         mov     [YeildAddr._lo],bx

 ;  Allocate a buffer to do transfers through

         mov     bx,MemBufSz                     ; size low
         mov     ax,0                            ; size high
         mov     dh,ALLOC_MEM_LOW
         DEVHELP ALLOCPHYS
         jnc     OKALLOC

         mov     dh,ALLOC_MEM_HIGH               ; Failed low lets try to allo
         DEVHELP ALLOCPHYS                       ; in high memory
         jnc     OKALLOC
         jmp     CmxGenFail

 OKALLOC:
         mov     BUFF._HI,AX              ; Save physical address of buffer
         mov     BUFF._LO,BX

 ;
 ; Output Sign-on Message
 ;
         push    WORD PTR    STDOUT              ;File handle - standard outpu
         push    WORD PTR    SignonLen           ;Length of message
         push    ds                              ;Selector of message
         push    OFFSET  SignonMsg               ;Address of message
         call    DOSPUTMESSAGE                   ;AX destroyed

         mov     bx,OFFSET ENDCODE
         mov     es:[di].InitEcode,bx

         mov     bx,END_DATA                  ; End of _DATA
         mov     es:[di].InitEDATA,bx

         jmp     CmxDone

 EndProc CmxInit

 _TEXT    Ends
         End

 mydevice.lrf ==============================================================

 strat.obj csub.obj init.obj
 mydevice.sys
 mydevice.map /map /nod /noi
 c:\lib\doscalls.lib
 mydevice.def;

 csub.c ===================================================================
 int _acrtused;	/* to keep out the C runtime stuff */

 near pascal C_ROUTINE(param)
 unsigned int param;

 {

 int x;
 int sum=0;

 	for (x=0; x<param; x++)
 	sum+=x;
 return(sum);

 }
 ==========================  THE END =======================================


 277. CodeView Will Not Run under OS/2

 Question:

 When trying to invoke CodeView (CVP.EXE) under OS/2, I receive the
 error message "SYS0197 OS/2 not configured to run this application."
 Why is this error occurring?

 Response:

 To run the protected-mode version of CodeView, you need to have your
 system set up with IOPL segments enabled. You can enable IOPL segments
 by adding the following line to your CONFIG.SYS file:

    IOPL=YES


 278. Freeing Memory when a Process Dies

 Question:
    Is it true that memory allocated using DOSALLOCHUGE or DOSALLOCSEG
 is not freed when a process is terminated (the process may have
 neglected to free the memory using DOSFREESEG)? If so, does this
 "dead" memory accumulate until the system is rebooted?

 Response:
    All memory owned by a process is deallocated when the process dies.
 If there are other processes that have access to shared memory created
 by the dying process, those selectors will remain valid until no
 processes are alive that had access to them.


 279. DosSemWait Incorrectly Documented in Programmer's Reference

 In the "Microsoft Operating System/2 Programmer's Reference" on Page
 271 it incorrectly states, "DosSemWait cannot be issued against a
 system semaphore which is owned by another process unless the
 NoExclusive option was selected on the DosCreateSem request that
 created the semaphore."

 The correct documentation is as follows (note that nothing has been
 added, but that there are two deletions):

 2.2.4.10.2  DOSSEMWAIT - WAIT FOR A SEMAPHORE TO BE CLEARED

 Purpose   DosSemWait blocks the current thread until the indicated
           semaphore is cleared but does not establish ownership of
           the semaphore.

 Format    Calling Sequence:

           EXTRN DosSemWait:FAR

           PUSH  DWORD SemHandle ; Semaphore handle
           PUSH  DWORD Timeout   ; Timeout
           CALL  DosSemWait

           where     SemHandle is the double-word handle of the
                     semaphore. For a system semaphore, this handle
                     is the result of the DosCreateSem or DosOpenSem
                     request which granted this thread access to the
                     semaphore. For a RAM semaphore, this handle is
                     the address of the double-word of storage
                     allocated for the semaphore.

                     Timeout is the count, in milliseconds, until the
                     requesting task is to resume execution if the
                     requested semaphore does not become available.
                     The meaning of the values specified is as follows:

                     o  If value = -1, when the semaphore is set,
                        there will be no timeout - the requester will
                        wait indefinitely.

                     o  If value = 0, there will be an immediate
                        return if the semaphore is set.

                     o  If value > 0, value is the number of
                        milliseconds to wait if the semaphore is set.

           Returns:  IF AX = 0

                        NO error

                     ELSE

                        AX = Error Code:

                        o   Invalid semaphore handle

                        o   Timeout

 Remarks:  DosSemWait is similar to DosSemRequest with the difference
           being that the semaphore is unowned on return.

           The unblocking of a DosSemWait is "level triggered" in
           that it will not return unless the indicated semaphore
           remains clear until the affected thread has been
           redispatched and has been able to ascertain that the
           indicated semaphore is clear.

 o  DosSemWait

        ERROR_SEM_TIMEOUT

        ERROR_INTERRUPT

        ERROR_INVALID_HANDLE


 280. Information about Dual Boot

 Question:
    I do not understand how to remove dual boot. Can you provide
 details about how it works?

 Response:
    Dual boot modifies the boot sector of the hard disk, and a section
 of OS2BIO.COM. It replaces the traditional boot sector with a special
 boot sector to support dual boot. Commonly asked questions are as
 follows:

    1. How do I remove dual boot?
       Boot from a DOS Version 3.2x or Version 3.30 floppy and SYS C:
       to replace the boot sector. You may also wish to copy the hidden
       DOS files.
    2. What happens if I install dual boot twice?
       The MSDOS option will hang. To restore it, SYS your hard disk
       and reinstall dual boot.
       This is fixed in MS OS/2 SDK 1.05.  The new install program
       allows for re-installing dual boot with the OS/2 upgrade.
    3. What version of DOS have you tested dual boot with?
       All DOS Versions 3.21 or later. Dual boot does not support
       earlier versions.


 281. DLLs and File Handle Requirements

 Question:
    How may file handles are required for each DLL? May the DLL be run
 time or load time?
    Assuming each DLL will require a file handle, if the process
 default of file handles is 20, will the system automatically allocate
 a greater number of file handles if more are needed for DLLS (e.g.
 when using 100D LLs concurrently)?

 Response:
    An open DLL does not use a file handle from the process. A file
 handle is an index number into a table (one per process) that contains
 its true system-file number. DLLs are opened and loaded by using a
 system-file number, i.e., you can load (DosLoadModule) as many DLLs as
 the system can handle.
    However, there is one requirement: the process must have at least
 one file handle available, although it is not used. (A file handle is
 created out of the system file number to perform a removable media
 test, and then it is freed. A context switch does not look possible at
 this point.)
    Please note that if the file is on removable media or over a
 network, the code segments are not marked as discardable; they are
 marked as swappable, which allows the disk to be removed with none of
 the segments demand loaded out of the EXE file. (They would have been
 written to the swap file and loaded from there.)


 282. Application Requests to KBDXLAT Are Not Performed Correctly

 Question:
    I am writing an application that takes input from a terminal in the
 form of make and break codes as per the IBM AT technical reference
 manual. I would like to use KBDXLAT to convert these to ASCII
 characters. Are these make/break codes the same as the scan codes
 KBDXLAT expects to receive? Is the application responsible for keeping
 track of the make/break on the SHIFT key and setting the SHIFT key
 status, or will KBDXLAT handle the SHIFT key status itself? This
 question also applies to the ALT, CTRL, etc. keys.

 Response:
    The make/break codes in the IBM technical reference manual are
 indeed what KBDXLAT expects for input. KBDXLAT will also keep track of
 SHIFT-state keys for you. However, in researching this question, we
 have discovered a problem in KBDXLAT that is present in both Version
 1.00 and Version 1.10 of the Microsoft OS/2SDK. Application requests
 to KBDXLAT are not being performed independent of the hardware state
 as they should be; in particular, the XHotKeyShift field in the KBD
 driver can affect the outcome of application translations, returning
 inconsistent results to the KBDXLAT caller. This is why KBDXLAT did
 not appear to be working properly for you.
    Microsoft has confirmed this to be a problem in Versions 1.00 and
 1.10. We are researching this problem and will post new information
 as it becomes available.


 283. COM1: Device Driver Fix for PS/2 Model 80

 Question:
    How do I find the COM01.SYS file that corrects the COM1: problem on
 my PS/2 Model 80?

 Response:
    This file can be found in the Software Library by searching for
 COM01.ARC, the Q number of this article, or S10023.


 284. OS/2 SDK: Memory Swap to Disk Information

 Question:

 How long does it take to do a memory swap to disk? I would like to
 know some kind of average time to allocate a segment (and get it ready
 for a MOV mem,AX operation) that causes a swap to disk to occur.

 Also, is memory swapped when it is allocated or when it is used, and
 what will be the limits on the number of segments (shared, unshared,
 etc.) for Version 1.1 with the Presentation Manager?

 Response:

 We do not have any figures on the time to swap to disk for OS/2. When
 a process requests memory using DosAllocSeg(), DosAllocHuge(), or
 DosAllocShrSeg(), the compactor may be invoked if a large enough block
 cannot be found. If moving memory around does not create a large
 enough block to satisfy the memory request, the swapper will then be
 invoked, which will swap least recently used segments to disk, growing
 the swap file if necessary. Data within the swap file itself is not
 rearranged. Note that whole segments are swapped or moved in the
 current implementation of OS/2.

 As far as the system limits are concerned, the following are some
 figures for OS/2 Version 1.1:

 1. Approximately 28K swappable segments are allowed system wide.
 2. Approximately 57K total segments are allowed system wide.
 3. The limit is still 8K segments total for each process; 6K of these
    are swappable, 2K are private.


 285. OS/2 SDK: Support for MS-DOS and Windows

 Question:

 My question concerns the Software Development Kit (SDK) for OS/2. Will
 Microsoft Windows for MS-DOS, and Microsoft language products for
 MS-DOS continue to be supported?

 Response:

 Yes, Microsoft Windows for MS-DOS, and Microsoft Language products for
 MS-DOS will continue to be supported products from Microsoft. Updates,
 at Microsoft update prices, will be provided to holders of those
 products who have complied with the registration requirements. Holders
 of the Windows Version 1.03 SDK will be updated to Version 2.00.

 Microsoft OS/2 is a new product. It is a major addition and
 enhancement to the operating software for personal computers. There is
 no current Microsoft product that properly qualifies the holder for an
 update to OS/2. Microsoft has announced that the OS/2 SDK will be
 available August 1, 1987. The price is $3000, and we are currently
 taking orders. An OS/2 information kit (including an order form) is
 available by calling Microsoft's ad response number: (800) 227-4679.


 286. List of OS/2 Developers and Applications

 There is a list of OS/2 developers and OS/2 applications that are
 currently available or have been announced in the Software Library.
 The file is called OS2APPS.ARC, and can be found in the Software
 Library by searching for the filename, the Q number of this article,
 or S12020.


 287. Placement of MOUSEA02.SYS in CONFIG.SYS in OS/2 SDK

 Question:

 The bottom of Page 70 in the "Microsoft Operating System/2 Software
 Development Kit Setup Guide" states that MOUSEA02.SYS should be
 installed before the COM.SYS driver. This seems to imply that both
 drivers are needed to use a serial mouse. Is this true?

 Response:

 No, the COM.SYS driver is not required for the serial mouse. However,
 if you have a serial mouse and also want to use the COM.SYS driver,
 you should install the mouse driver first; otherwise, the COM.SYS
 driver will take the interrupts and the mouse driver will not be able
 to get loaded and initialized.


 288. Shell Command Problem in CONFIG.SYS File

 Problem:

 If the /C switch is specified for the command processor, COMMAND.COM,
 the 3.x box cannot be entered. The batch file specified by the /C
 switch is executed, but after it is finished, the following error
 appears:

 SYS2064: There is not enough storage to create DOS mode.
 DOS mode cannot be started.

 If the /C switch is removed, the 3.x box loads correctly.

 Response:

 The COMMAND.COM /C switch allows you to run a secondary command
 processor long enough to execute a program and then exit back to the
 primary command processor. In the case of the SHELL statement in your
 CONFIG.SYS file, it is not appropriate to use the /C switch because
 the SHELL statement is describing what must be the primary command
 processor. The system should not give such a vague error when this is
 done; however, it is being confused by the COMMAND.COM that it started
 executing for the 3.x box when the system exited suddenly.



 289. Printing out Size of Free Memory with DosMemAvail

 Problem:

 My sample program below fails with the following error when I execute
 it:

 The system detected a general protection fault (trap D) in a system
 call.

 My sample program is as follows:

  */

 #include <stdio.h>
 #define   INCL_DOS
 #include <os2.h>

 main()
      {
      PULONG mem_avail;
      DosMemAvail((PULONG)mem_avail);
      printf("\nLargest memory block available is %li bytes.",mem_avail);
      }

 Response:

 When using this API, you must provide an area to return the value in.
 In this case, you were only providing an uninitialized pointer to an
 area that was outside your memory address space. Since the value
 returned is an unsigned long integer, it is also important to print it
 out using the %lu format string of printf. See the following code
 example for more information:

  */

 #include <stdio.h>
 #define   INCL_DOS
 #include <os2.h>

 main()
    {
       ULONG mem_avail;
       DosMemAvail((PULONG) &mem_avail);
       printf("\nLargest memory block available is %lu bytes.",mem_avail);
    }



 290. Using an Interrupt Service Routine to Flag Ring 2 or 3

 Question:

 I want to be able to have an Interrupt Service Routine (ISR) in a
 device driver that will flag a ring 2 or ring 3 thread to get it
 scheduled again. I have two questions about doing this, as follows:

 1. It looks to me like the only way to do this is to have the device
    driver write a value into RAM or a system semaphore, since there
    doesn't seem to be an equivalent to DosSemSet in the DevHlps. If
    this is true, what is the semaphore data structure?

 2. Assuming that my thread is set at the critical highest priority
    time level and it's blocked on a semaphore that the ISR sets, I
    think I still have a problem. Won't OS/2 first finish the time
    slice for the thread that was interrupted (even if it was of lower
    priority than my thread) before running my thread? If so, can I
    override this and preempt the current thread?

 Response:

 There is a DevHlp to clear a semaphore at interrupt time. It would
 also be possible to have an application's thread do a generic ioctl
 call with DosDevIOCtl and have the device driver block that calling
 thread with a ProcBlock DevHlp. Then when an interrupt comes in,
 either DevDone or ProcRun could be used to allow the application's
 thread to be scheduled again. To use a semaphore, it must be a system
 semaphore.

 When the thread will be scheduled cannot be guaranteed. In most cases
 when the ISR completes, the scheduler will be invoked and can schedule
 the higher priority threads in the system to run. A case where this
 would not happen is when the interrupted thread is already in the
 kernel when the interrupt occurs.



 291. SetIRQ Interrupt Number Information

 Problem:

 I have found some inconsistencies in the SetIRQ:Set Hardware Interrupt
 Handler documentation. The "IBM Operating System/2 Version 1.1
 Technical Reference: Programming Reference" manual indicates that the
 interrupt number can range from 0 to 0FH, except for number 2, which
 is used for cascading the slave 8259 interrupts. It also says that
 only hardware interrupts can be set.

 The documentation on Page 358 of the "Microsoft Operating System/2
 Device Drivers Guide" also indicates that the interrupt number can
 range from 00H to 0FH, but then says that software interrupt vectors
 can also be set. It also states that invalid ranges are 08H-0FH,
 50H-57H, and 70H-77H.

 Response:

 Our documentation is incorrect and IBM's documentation is correct. In
 a future release of our documentation this error will be corrected.
 Please note that you can't get 0DH, which is the NPX, because the
 kernel takes that.



 292. DosFreeModule() Returns Error Code 12

 Question:

 When I use the DosFreeModule() function in my program, it returns an
 error code of 12 (ERROR_INVALID_ACCESS). The error occurs in a C
 program that loads and calls a Dynamic Linked Library (DLL) created
 with MicroFocus COBOL. After the module is loaded and a function
 inside the DLL module is called, the module handle is passed to the
 DosFreeModule() function. This is when the error occurs. The error
 does not consistently happen every time this function is called. This
 error is not documented to my knowledge. What does it mean?

 Response:

 Error code 12 will be returned if a routine in the DLL has been added
 to your exit list. Since the routine is needed by exit list when the
 the program exits, and calling a routine in a module that has used the
 DosFreeModule function would cause a general-protection fault, freeing
 the module that contains the routine is not allowed. The code in the
 DLL would have to be checked to see if any routines are being added to
 your exit list. Error code 12 might also be caused by the COBOL run
 time adding routines to your exit list without your application
 necessarily knowing about it.



 293. Get Device Information IOCTL 44H Fails in Compatibility Box

 There is a problem with running programs compiled and linked using the
 Turbo C Version 1.50 Compiler in the OS/2 compatibility box. It is due
 to a difference in the way the MS-DOS Get Device Information IOCTL
 function call 44H works under OS/2.

 When run in the compatibility box, the IOCTL Get Device Information
 function call for the predefined file handles (0-4) does not return
 the same values as under MS-DOS.

 This function call returns device information in DX. According to the
 "Microsoft MS-DOS Version 3.3 Programmer's Reference" on Pages
 329-330, bit 15 indicates whether the device is a character or block
 device.

 When run under MS-DOS for file handles 0-4, bit 15 = 1, indicating
 that the devices are character devices. When run under OS/2 in the
 compatibility box, bit 15 = 0. The same is true for IBM OS/2 Standard
 Edition Version 1.00.

 This causes a problem for Turbo C because the run-time library
 function isatty() does an IOCTL Get Device Information function call
 and does not work correctly under OS/2 for character devices.
 Unfortunately, any program that calls printf() or scanf() has the
 potential for not working correctly in the compatibility box because
 these functions call isatty().

 The current workaround is not to use Turbo C if you want to run your
 programs in the compatibility box.

 Microsoft is researching this problem and will post new information
 as it becomes available.



 294. Converting Terminate and Stay Resident Programs to OS/2

 Question:

 We plan to convert several terminate-and-stay-resident (TSR) modules
 that we are currently using under MS-DOS so that they can be used
 under OS/2 and the 3.x box. Current applications make use of these TSR
 modules through user-software interrupts. The logical conversion for
 OS/2 would be in the form of DLL's; however, the 3.x box has no
 published way to allow the transfer of information to OS/2 for
 processing. I understand that OS2DOS.COM traps software interrupts,
 but the actual processing is done by software on the OS/2 side. Is
 there a way to collect information from a software interrupt in the
 3.x box and pass that information and function request to OS/2
 software for processing?

 Response:

 You need to do write a bimodal OS/2 device driver and use the
 SetROMVector DevHlp call to take over a software interrupt. When a 3.x
 box application issues that software interrupt, your device driver
 will get control. From that point, you could pass the information to a
 protected-mode routine through shared memory or some other interprocess
 communication method.



 295. Use of Profiler Calls Returns Many Errors

 Question:

 The C program below was created using the Microsoft example profile
 calls. These wrappers were inserted into our code (a large program,
 using Presentation Manager (PM)) and the error codes shown in the
 comments were returned. Could you please tell us what the error codes
 mean and how to stop them from occurring?

 #include <os2.h>
 #include <stdio.h>
 #include <conio.h>
 #include <profile.h>

 start_profiling ()

 {

   int ec;
   ec = PROFINIT(PT_USER|PT_USEKP, (char far *)NULL);
        /* error code == 8 */
   ec = PROFCLEAR(PT_USER);
       /* error code == 9 */
   ec = PROFON(PT_USER);
       /* error code == 9 */
 }

 end_profiling (dumpfile)
 char *dumpfile;

 {
     int ec;
     ec = PROFOFF(PT_USER);
          /* error code == 9 */
     ec = PROFDUMP(PT_USER, (char far *) dumpfile);
         /* error code == 0 */
     ec = PROFFREE(PT_USER);
         /* error code == 0 */
 }

 Response:

 Error code 8 is ERROR_NOT_ENOUGH_MEMORY. Error code 9 on the
 subsequent call probably occurred because the PROFINIT failed. The
 error codes returned by the profiling API's are the same as for the
 other DOSxxx calls, and are defined in the BSEERR.H include file. The
 particular type of memory being asked for turns out to be "fixed", so
 it is possible that the system cannot find enough memory available if
 your PM application is large and your machine does not have much
 memory on it. You may need more memory for your development machine.

 Also please verify that you have swapping and memory movement enabled.
 You need to have "MEMMAN=SWAP,MOVE" in your CONFIG.SYS file (or in
 CONFIG.OS2 if you have dual-boot) to enable swapping and memory
 movement.



 296. GetTextExtent Equivalent in Presentation Manager

 Question:

 What is the recommended Presentation Manager method to get the same
 kind of information that the Windows call GetTextExtent does?

 Response:

 The method for obtaining text metrics in Presentation Manager is
 through the GpiQueryFontMetrics() function.


 297. PM Dialog Box Editor Hangs in Group Move Mode

 Problem:

 After I get into group move mode and move a group of controls, I can't
 get back out of group move mode. The dialog box editor appears to get
 hung up in a modal window.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.03. This
 problem was corrected in the Version 1.05 SDK release.

 The Version 1.05 SDK dialog box editor now works as described in the
 documentation.


 298. Unrecognized PS/2 Disk Controller Card

 Question:

 When attempting to install Software Development Kit (SDK) Version 1.05
 on my PS/2 model 70, I receive the following message:

 Unrecognized PS/2 disk controller card

 Why am I getting this message?

 Response:

 Some PS/2s (including model 70s) have a new ESDI controller. These new
 controllers have a different ROM ID than the older controllers. The
 SDK Version 1.05 device driver loader does not recognize this newer ID
 as valid for PS/2s.

 There is a patch available that corrects this problem in most PS/2s,
 except for those that have two ESDI drives. The patch is called
 PS2105A.ARC and is available in the Software Library. The patch can be
 found in the Software Library by searching on the filename
 PS2105A.ARC, the Q number of this article, or S12068.

 You will need to use the PKXARC utility to unarc the file PS2105A.ARC.


 299. Using High-Resolution Graphics Programs in the DOS 3.x Box

 This article describes how an OS/2 real-mode application (running
 inside the OS/2 DOS compatibility mode or 3.x box) can detect when
 OS/2 will switch into and out of the 3.x box screen group. It
 discusses the interface with which an application can obtain this
 information from OS/2, and what options are available to the
 application.

 Screen-Switch Notification

 OS/2 provides a screen-switch notification mechanism in the 3.x box
 to support high-performance DOS EGA graphics applications that cannot
 accept the overhead of the EGA register interface (EGARI).

 The notification is made by issuing the DOS multiplex interrupt
 (interrupt 2FH) with AH=40H and AL indicating what kind of screen
 switch is occurring. AL=01H indicates that the 3.x box is moving into
 the background; AL=02H indicates that the 3.x box is moving into the
 foreground.

 A DOS application that wishes to receive this signal must "hook" the
 multiplex interrupt vector; i.e., when the application is started, it
 must save the current interrupt 2FH vector and set the interrupt 2FH
 vector to point to the application's own multiplex interrupt handler.

 When an application receives an interrupt 2FH with an unexpected value
 in AX (in this case, a value other than 4001H or 4002H), the
 application must do a JMP FAR to the previous interrupt 2FH vector.

 Since only one DOS application may have control of the screen at a
 particular instant in time, the proper behavior for an application's
 interrupt 2FH handler, when it recognizes a screen-switch
 notification, is to perform its screen switch work and IRET. This
 approach ensures that only one application is responsible for
 preserving the screen state.

 3.x Box Moving Background Notification

 When OS/2 is making the 3.x box the background screen group, the
 following sequence of operations is performed:

 1. Make the 3.x box ineligible for hardware interrupts.

 2. Perform a "3.x Box Background" notification.

 3. Interrogate EGARI to save the EGA state (if present).

 4. Save the video RAM.

 5. Freeze the 3.x box.

 To perform "3.x Box Background" notification, OS/2 issues a software
 interrupt 2FH, with AX=4001H. The application must perform whatever
 "save" processing it requires and IRET back to OS/2; it need not
 preserve any registers.

 This notification may occur at ANY time, including during code where
 the application is directly programming the EGA. At the point where
 the notification occurs, the application (other than its interrupt 2FH
 handler) will not continue execution until the 3.x box is brought into
 the foreground. If the application has any sections of code that are
 sensitive to being interrupted in this fashion, the application must
 either protect the code by doing a CLI/STI, or have the interrupt 2FH
 handler do appropriate work so that when the "3.x box foreground"
 notification occurs, the state of the EGA and application can be
 properly restored.

 When the notification occurs, the application might do one or more of
 the following operations:

 1. Use EGARI calls to set the EGA state for OS/2 to save.

 2. Save the EGA/application state in private memory.

 Once notification is complete, the application should be written, if
 possible, to avoid accessing all video I/O ports and memory until
 after a foreground notification has been processed, since it may
 eventually be possible for applications using this interface to
 continue to run in the background.

 3.x Box Moving Foreground Notification

 When OS/2 is making the 3.x box the foreground screen group, the
 following sequence of operations is performed:

 1. Thaw (reinstate) the 3.x box.

 2. Restore video RAM.

 3. Restore the EGA state (using EGARI information if present).

 4. Perform a "3.x Box Foreground" notification.

 5. Make the 3.x box eligible for hardware interrupts.

 To perform "3.x Box Foreground" notification, OS/2 issues a software
 interrupt 2FH, with AX=4002H. The application must perform whatever
 "restore" processing it requires and IRET back to OS/2; it need not
 preserve any registers.

 When the notification occurs, the application might do one or more of
 the following operations:

 1. Restore the EGA/application state from private memory.

 2. Do nothing (if EGARI calls were made at "3.x Box Background"
    notification, EGARI will do the restore).

 If the application used EGARI calls to set the EGA state at the time
 of the "3.x Box Background" notification, the application need do
 nothing when it receives the "3.x Box Foreground" notification.


 300. #define INCL_DOS Does Not Define INCL_DOSDEVICES in SDK 1.05

 Question:

 The documentation states that "#define INCL_DOS" preceding "#include
 <os2.h>" will get all of the include files in BSEDOS.H. However, upon
 closer examination, "#define INCL_DOS" is found to define all of the
 subsequent "INCL_..." statements EXCEPT "INCL_DOSDEVICES", wherein
 DosDevIOCtl and a few other calls are defined. Is this an error or
 should "INCL_DOS" define "INCL_DOSDEVICES"?

 Response:

 Microsoft has confirmed to be a problem in the BSEDOS.H file of the
 Version 1.05 OS/2 Software Development Kit. We are researching this
 problem and will post new information as it becomes available.


 301. Asych Device Driver and DosDevIOCtl

 Question:

 The "Microsoft Operating System/2 Device Drivers Guide" Section 2.4.2,
 Page 48, paragraph two, reads as follows:

    Since data is lost when the input queue has no space, programs
    should use DosDevIOCtl to specify an appropriate input size.
    Similarly, output queue size should be adjusted for an
    application's needs. The input queue's default length is 150 bytes;
    the output queue's default length is 64."

 I've looked through all of the IOCTL functions and found nothing to
 adjust the queue size. Could you please tell me where to find this
 information?

 Response:

 An application program cannot change the size of the transmit and
 receive queues. These queues are owned by the communications device
 driver. A documentation errata sent with the Version 1.02 SDK
 discusses the transmit and receive queues on Page 3. However, an
 application program can query the size of these queues through
 category 1 function 68h and 69h IOCTLs.


 302. DosExecPgm() Flag Paramenters: EXEC_LOAD Not Documented

 Both Page 45 of the "Microsoft Operating System/2 Programmer's
 Reference Volume 3" for Version 1.10 and QuickHelp incorrectly
 show only five possible values for the fExecFlags parameter to
 DosExecPgm(). However, the BSEDOS.H header file correctly shows
 six possible values, as follows:

    #define EXEC_SYNC           0
    #define EXEC_ASYNC          1
    #define EXEC_ASYNCRESULT    2
    #define EXEC_TRACE          3
    #define EXEC_BACKGROUND     4
    #define EXEC_LOAD           5

 EXEC_LOAD is not documented anywhere. EXEC_LOAD allows you to load a
 program into storage and make it ready to execute. This program is not
 executed until the session manager thaws the process.


 303. Problem with Using VioPopUp and VioEndPopUp with DosExitList

 Question:

 In my test program, once an application has terminated, it is executed
 using a DosExitList. The test program calls a DosStartSession that
 begins another session; it operates correctly. The test program then
 displays a message on the screen using a VioPopUp; this also works
 correctly. Then to terminate that message, a VioEndPopUp is issued.
 At this point, the DosExitList is terminated even though there is code
 following the VioEndPopUp.

 I also put together another test program that only tests the VioPopUp
 and VioEndPopUp. The results are still the same; the code after the
 VioEndPopUp is not executed. Is this a problem in OS/2?

 Response:

 Exit-list routines are documented on Page 94 of the "Microsoft
 Operating System/2 Programmer's Reference" for Version 1.00 as not
 supporting the functions DosExecPgm and DosCreateThread. This list
 should also include DosStartSession because it does an implicit
 DosExecPgm. This is what is happening here.

 In general, exit-list routines are intended to be as short and as
 fail-safe as possible. You are not running into a problem with it
 here, but it would be best if you did not do anything like a VioPopUp.
 There is a possibility of an exit-list routine not being run if an
 exit list that you have designed fails or causes an error and has been
 added by a routine transparently to your application. An example of
 this is the exit-list routine that is added by the queue's dynamic
 link library. If this exit list is not run because your application's
 exit list fails, the system will be left with an orphan queue until
 the next reboot.

 VioPopUp is internally executing DosExitList(EXLST_ADD, VioEndPopUp).
 This is done to allow for the case when VioPopUp is used in a
 "nonexit" routine. Should the process exit (normally or not) with the
 pop-up opened, its resources can be freed. In the event that VioPopUp
 is used in an exit routine, the exit-routine list is modified so that
 when VioEndPopUp is executed, the system returns to CMD.EXE. Though it
 is not documented on Page 94 of the programmer's reference as an
 invalid routine for exit-list routines, it should not be used for this
 type of routine.

 In Version 1.05 of the Software Development Kit there is a problem
 with VioPopUp. After doing a VioPopUp, and ending with a VioEndPopUp,
 the problem occurs when you attempt to exit back to OS/2. At this
 point the system appears to hang. What is happening is that the
 current screen group is hung in such a way that you cannot return to
 the command prompt and you cannot change screen groups. You must
 reboot the system to recover from this problem. Microsoft has
 confirmed this to be a problem in Version 1.05. We are researching
 this problem and will post new information as it becomes available.

 If you wish to continue using DosStartSession within an exit routine
 and have a pop-up to announce the event, you may want to try the
 following:

 1. Move the VioPopUp and keyboard I/O into the main routine just prior
    to the exit.

 2. Do not insert a VioEndPopUp into your code; let the system take
    care of it.


 304. Monochrome VGA Monitor Color Incompatibility: IBM and MS OS/2

 Question:

 There is an incompatibility between Microsoft's version of OS/2 and
 IBM's version of OS/2 when using a monochrome VGA monitor in color
 mode. The "summed" values that are programmed into the VGA's
 Digital-To-Analog Controller are not identical.

 When a VGA monochrome monitor is used in a color mode, the VGA's DAC
 is programmed with "summed" values, which are calculated with the
 following formula:

          30% of the Red Value
        + 59% of the Green Value
        + 11% of the Blue Value
        ------------------------
             Gray Shade

 The resulting sum represents one of the 64 gray shades the monochrome
 monitor can display. The sum is programmed into all three DAC color
 registers: red, green, and blue, even though the hardware uses only
 the green value to drive the display.

 In protected mode under Microsoft OS/2, BVSCALLS.DLL programs the DAC
 with "summed" values. These values are found in the table "sumregs",
 located in the source file BVSMODES.INC. In protected mode under IBM
 OS/2, the DAC is programmed with different values for 12 of the
 colors. These match IBM's VGA ROM, leading me to believe that ABIOS,
 instead of the BVS table, is being used by IBM to program the DAC.

 Why aren't these "summed" values identical?

 Response:

 If you test this with IBM OS/2 on an AT and compare it to what is
 happening on a PS/2, we think you might find that the results will be
 similar to what you found with our OS/2 and IBM's. We cannot guarantee
 that what we do on a PS/2 and what IBM does will be identical; what is
 done on the PS/2 with IBM OS/2 and on an AT with our OS/2 will be
 different in certain areas.

 You are correct in assuming that IBM OS/2 on a PS/2 uses the tables in
 the ABIOS, which causes the differences you are discovering.


 305. Setting Up a Selector to Access Shared Memory

 Question:

 I am trying to use the AllocateGDTSelector and PhysToGDTSelector to
 set up a selector to access shared memory on an I/O card. I then want
 to pass this selector to a process, allowing the process to access the
 shared memory.

 My device driver fails on one of the above calls, displaying the
 "internal error processing DevHlp at 1F90.." message. Are these
 DevHlps supported in Version 1.10 of OS/2? If so, then why does OS/2
 crash?

 Response:

 The DevHlps AllocGDTSelector and PhysToGDTSelector work as documented.
 These DevHlps are supported in Version 1.10 of OS/2. There is a
 description of these DevHlps in an archived file named DEVHLP.ARC in
 the Software library. This file can be found in the Software Library
 by searching for the filename, the Q number of this article, or
 S12066. You will need to unarchive the file using the PKXARC utility.

 If you want to give an access to a portion of shared memory from a
 device driver, use DevHlp "PhysToUVirt". This DevHlp creates a
 descriptor in the Local Descriptor Table (LDT) of the current process
 and returns a selector, which then can be passed to the process using
 an IOCTL.


 306. Memory Requirements in OS/2 Version 1.05

 Question:

 I am running the OS/2 Software Development Kit (SDK) Version 1.05 on a
 machine with 4 megabytes of memory. Does it require more memory to run
 the OS/2 (SDK) Version 1.05 than previous versions of the OS/2 SDK?

 Response:

 Yes, the OS/2 SDK Version 1.05 may require more memory than previous
 SDK's. Recently we have been able to trim things down so that the
 final version will perhaps be smaller. The following are a few
 workarounds to help you work within the memory requirements:

 1. Disable the DOS compatibility box. By doing so, this will save you
    a considerable amount of memory. Even if you have 4 megabtyes of
    memory, when you try to run LAN Manager and the Presentation
    Manager (PM) Shell, and build applications, you can still run out
    of memory.

 2. Make sure that swapping is enabled. The system in general will be
    less responsive if you rely on virtual memory. However, swapping
    will help other processes that are not used very often.

 3. Do not install LAN Manager as a server. This takes up more memory
    and requires a minimum 4 megabytes of memory.

 4. Remove the PM spooler. To remove the PM spooler do the following:

    a. Enter the Program Starter from the Presentation Manager.

    b. Click on "Group".

    c. Click on "Utility Programs".

    d. Double click on "Control Panel".

    e. Click on "Setup".

    f. Click on "Spooler options".

    g. Activate the "Spooler is not Selected" box.

    h. Click on "Enter".

    i. Exit the Control Panel, answer "Yes" to save prompt.

    j. Reboot the system.



 307. Slow Video Input/Output on Compaq Portable IIIs

 Microsoft OS/2's VIO functions run slowly on Compaq Portable IIIs
 because the Compaq Portable III uses a gas plasma screen. Microsoft
 OS/2 screen drivers do not take this into consideration and the output
 method they use runs slowly on these types of displays.

 Compaq's release of Microsoft OS/2 includes modified screen drivers
 that improve video I/O performance on the Compaq Portable III gas
 plasma display.


 308. Determining Whether System Is Running Under HPFS or FAT

 Question:

 What call can be used in OS/2 to determine whether the system is
 running under FAT or HPFS?

 Response:

 If you use the DosQFSAttach() call, the file system type is returned
 in the SzFSDName field of the FSQBUFFER structure. The following is a
 sample program that demonstrates this method:

 /* be sure to compile with small model! /AS */

 #define INCL_DOSFILEMGR
 #define INCL_DOSMEMMGR
 #define INCL_VIO
 #include <os2.h>
 #include <stdio.h>

 main()
 {
   PSZ psz;
   PUSHORT pcb;
   USHORT cb;
   SEL sel;
   USHORT err;
   char drvLet[3];

   if (DosAllocSeg(0x1000, &sel, SEG_NONSHARED))
     {
     printf("DosAllocSeg failed!\n");
     exit(0);
     }
   printf("enter drive letter: ");
   scanf("%2s", &drvLet);
   drvLet[1] = ':';
   drvLet[2] = 0;
   err = DosQFSAttach(drvLet, 0, FSAIL_QUERYNAME, MAKEP(sel,0),
                       &cb, 0L);
   if (err)
     {
     printf("DosQFSAttach failed, err=%u\n", err);
     exit(0);
     }
   pcb = MAKEP(sel, 2);        /* points to length of device name */
   psz = MAKEP(sel, 4);        /* points to device name           */
   VioWrtTTY(psz, *pcb, 0);    /* displays device name            */
   VioWrtTTY("\r\n", 2, 0);
   psz += *pcb + 3;            /* adds null character and name-length
                                   variable                       */
   pcb = (PUSHORT) (psz - 2);  /* points to length of name        */
   VioWrtTTY(psz, *pcb, 0);    /* displays file-system name       */
   VioWrtTTY("\r\n", 2, 0);
 }


 309. OS/2 SDK 1.02 PRINT01.SYS Driver Replacement

 There is a replacement driver for PRINT01.SYS in the Software Library
 that adds support for the 20 Mhz PS/2 Model 80.

 This file can be found in the Software Library by searching for the
 filename PRINT01.ARC, the Q number of this article, or S10058.
 PRINT01.ARC has been archived with PKARC so you will need to unarchive
 it with PKXARC. The PKXARC utility is located on your OnLine Utilities
 Disk 2.


 310. QuickHelp Documentation Problems

 There are numerous errors and missing information in QuickHelp. Some
 of these problems are as follows:

 1. DosStartSession is incorrectly documented.

 2. There is no information on named pipes.

 3. DosMonRead still has the DCWW_xxxx values (and has them
    _backwards_).

 4. There is no information on monitor packet formats.

 Microsoft has confirmed these problems in Version 1.10. We are
 researching these problems and will post new information as as it
 becomes available.



 311. OS/2 SDK QuickHelp Documentation Suggestion

 Question:

 Is there any way of getting either a different version of QuickHelp or
 an update to the documentation that has things written from an
 assembler programmer's point of view?

 The C format of the OS/2 function description is very difficult to
 read. All the data types and return codes are in symbolic notation,
 and there is no reference as to what the symbols stand for.

 The first set of documentation had everything in terms of there actual
 integer value; this documentation was much more readable.

 Response:

 At this time, there is only one version of QuickHelp available and
 there is no update to the documentation available that references
 Assembly language as opposed to the C language.

 This feature is under review and will be considered for inclusion in a
 future release.



 312. Compilation Problems Due to Use of Wrong Include File

 The "#include <pm.h>" statement used to be the last line in the OS2.H
 file but is now commented out in the Version 1.05 Software Development
 Kit (SDK). If you use the OS2.H file without the "#include <pm.h>"
 statement commented out, it resolves the original problem (i.e.,
 compile error C2054) but still does not allow compilation. When using
 the OS2.H file with the "#include <pm.h>" statement commented out, the
 following error appears when you try to run MAKE on the sample HELLO.C
 program:

 MAKE HELLO > ERR

 This error produces the following:

 Microsoft (R) Program Maintenance Utility Version 4.07
 Copyright (C) Microsoft Corp 1984-1988. All rights reserved.

   cl -c -W3 -AS -G2sw -Os -Zpei hello.c

 hello.c
 C:/pmsdk/include/pmwin.h(215) : warning C4074: non standard extension
   used -'trailing ',' used for variable argument list'
 C:/pmsdk/include/pmwin.h(215) : error C2061: syntax error : identifier
   'PRECTL'
 C:/pmsdk/include/pmwin.h(215) : fatal error C1022: expected '#endif'

 The symptoms described indicate that old versions of the include files
 are still being found. You have to make sure that you do not use the
 OS2.H file that comes with the C compiler. It is this copy of the
 include file that has the line "#include <pm.h>" commented out in it.
 The copy of OS2.H that came with the Version 1.05 Software Development
 Kit (SDK) should not have this line commented out in it.

 We suggest that you use the WHERE utility and find all copies of the
 following files:

    OS2.H
    OS2DEF.H

 You should then replace the older versions of these files with the
 versions that came with the SDK.



 313. HELLO.C Returns C2054: Expected '(' to Follow 'MRESULT' Error

 Problem:

 Using the OS/2 Software Development Kit (SDK) Version 1.05 I cannot
 compile most of the sample programs, or the Petzold sample code. On
 the sample program HELLO.C I receive an error "C2054: expected '(' to
 follow 'MRESULT'". On the Petzold sample programs I receive the error
 "C4071: 'WinInitialize': no function prototype given".

 Response:

 The errors you are receiving indicate that you have not included the
 correct include file. MRESULT is typedef'ed in PMWIN.H to be a far
 pointer. If the typedef for MRESULT is not found, the compiler assumes
 that you are making a function declaration, and you get the error
 about the missing '('. You will need to make sure that you have
 everything configured correctly so that the most current versions of
 the include files are being found along your include environment
 variable.

 Also, make sure that you are using the correct version of the include
 file OS2.H. The one that comes with the OS/2 SDK Version 1.05 includes
 the following extra statement which was not present in the OS2.H file
 that came with the C compiler, or with the SDK Version 1.03:

    #include <pm.h>


 314. QuickHelp Returns Invalid Error of "qh.hlp Already Open"

 After trying to access QuickHelp, a "qh.hlp already open" message
 appears when the QH environment variable is set using OS2INIT.CMD with
 the following statement in a new screen group:

   set QH=c:\pmsdk\pbin +50

 When a key is pressed to continue, a protection violation (trap 13)
 occurs. Starting QuickHelp with the command: qh +50 seems to work
 correctly.

 Microsoft has confirmed this to be a problem with the QuickHelp
 shipped with the OS/2 Software Development Kit (SDK) Version 1.05. We
 are researching this problem and will post new information as it
 becomes available.


 315. VGA Support under OS/2 and C Compiler Version 5.10

 The following are questions and answers regarding VGA support under
 OS/2 and C Compiler Version 5.10.

 1. Does OS/2 include a driver for VGA support, or is it up to the VGA
    manufacturer to supply one?

    Yes, OS/2 does provide support for the VGA card.

 2. Will the C Compiler Version 5.10 graphic functions work with VGA or
    any graphic display device in OS/2 protected mode?

    The C Compiler Version 5.10 graphics functions (i.e.,
    _setvideomode, _rectangle, etc.) are not supported in protected
    mode. They do work in the DOS compatibility box.

 3. Can a VGA and a monochrome display be present at the same time, and
    will the new OS/2 Presentation Manager use the VGA and allow the
    monochrome to be used for dual booting of MS-DOS?

    Whatever video configuration you have set up as the primary one is
    the one that will be used for both real mode and protected mode. In
    other words, if you have the VGA set up as the primary display, the
    dual-boot feature will use this as the default adapter when you go
    into either the OS/2 protected mode or the MS-DOS real mode. It
    will not use the VGA as the primary for OS/2 and monochrome as the
    primary for MS-DOS.


 316. Multi-Thread Programming Hints

 The THREADS.C example states that a thread should terminate with a
 DosExit() call or unpredictable results can occur. The documentation
 and QuickHelp program indicate that a thread terminates when the
 function returns or calls the DosExit function.

 The following are questions regarding this information:

 1. Is it possible for a thread to "know" that it is running as a
    thread and not as a function?

 2. There appears to be a conflict between the THREADS.C example and
    the documentation. Is the DosExit function required in a thread?

 The example that you are referring to is not completely correct. The
 original version of this example was created some time ago and is
 somewhat misleading.

 Several things have changed. It is no longer a problem to use the C
 run time for multi-threaded programs. You can create multi-threaded
 programs using one of a couple of libraries available with the
 C Compiler Version 5.10. For complete details on creating multi-threaded
 programs using the new C run time, refer to the MTDYNA.DOC file that
 comes with the C Compiler package.

 In the MTDYNA.DOC file, note that it is recommended that you use the new
 run-time functions _beginthread and _endthread to start and end your
 threads instead of the OS/2 calls DosCreateThread and DosExit, because
 there is some initialization that is done for each thread.

 If you choose to use the method described in the example THREADS.C, it
 is not necessary to explicitly exit the thread with DosExit, although
 it is recommended.

 As for identifying whether you are a thread or a function, a call to
 the function DosGetPid will return the thread id (TID). If you are in
 the main program, your thread identification will always be one under
 the current release of OS/2.

 If you are running a thread that is not the main thread, it will have
 a different thread identification. We do not recommend that you depend
 on the TID of the main program being one. If it is necessary for you
 to see if you are in the main thread or in a separate thread, call
 DosGetPid from the main thread and store the thread identification in
 a global variable. If you are in a function and the value returned by
 DosGetPid is not the same as that returned when in the main function,
 then you are executing as a thread.


 317. 32 Thread Limitation when Using C 5.00 Run-Time Library

 Question:

 What happens if I need more than the 32 threads that are supported by
 Version 5.00 of the C run-time library to be used with multithreaded
 programs?

 Response:

 The limitation of 32 threads is considerably over the recommended
 maximum per process (of 12) and is a fairly reasonable limit. There
 are no plans at this time to change this limit.

 If you don't use the C run-time library, you can create more than 32
 threads per process with the DosCreateThread() function call. The
 current process limit is about 52. This limit is version dependent and
 is subject to change.


 318. Moving the Mouse Cursor Causes Exception Error

 If the "device=c:\os2\dev\pointdd.sys" line in the OS/2 CONFIG.SYS
 file is not present or is remarked out (REM appears at the beginning
 of the line), the following error may occur when you attempt to move
 the mouse after the system has finished booting:

                     TRAP 000
                     AX=0010 ...
                        .
                        .
                        .
    Exception Error in device driver MOUSE$
    The system detected an internal processing error
    at location #00B0:084E
    Exception while in kernel mode

 To correct this problem, remove the REM statement from the line
 "device=c:\os2\dev\pointdd.sys" or insert the line if it is not
 present.


 319. Writing a Signal Handler to Capture Keyboard Input

 Question:

 I have written a signal handler to capture CTRL+BREAK. KbdCharIn
 correctly indicates that an error occurs by returning a positive
 value. However, if I issue a KbdCharIn immediately after the
 CTRL+BREAK has been handled by my handler routine, the return value
 indicates that the read was successful (zero is returned) but the
 character that is returned has a scan code of zero (0). Is this
 expected behavior, and how should I handle this?

 Response:

 It is expected behavior; you need to flush the keyboard buffer after
 receiving a CTRL+BREAK. One way to accomplish this is to use the
 function KbdFlush either in your handler function or whenever
 KbdCharIn returns an error value.

 Below is a sample program that takes input from the keyboard and
 echoes it back. If you press CTRL+BREAK, the handler is called and
 prints out a message. If you do not put the KbdFlushBuffer(hkbd)
 call in the "do...while" loop, KbdCharIn will pick up a character
 from the buffer that has a scan code of zero. The KbdFlushBuffer
 call could also be put into the handler if you chose to do it
 that way instead.

 The sample program is as follows:

 #include <stdio.h>
 #define INCL_BASE
 #include <os2.h>

 void pascal far ctrlBreakHandler(USHORT usSigArg, USHORT usSigNum);

 int main(int argc, char **argv)
 {
      KBDINFO kbstInfo;
      KBDKEYINFO kbciKey;
      HKBD hkbd;
      USHORT rc;
      PFNSIGHANDLER FAR *prevCtrlBreakHandler;
      USHORT prevAction;

      printf("Hello, World!\n");

      rc = KbdOpen(&hkbd);
      printf("KbdOpen rc %d   hkbd %d\n", rc, hkbd);

      rc = KbdGetFocus(IO_WAIT, hkbd);
      printf("KbdGetFocus rc %d\n", rc);

      kbstInfo.cb = sizeof(kbstInfo);
      rc = KbdGetStatus(&kbstInfo, hkbd);
      printf("KbdGetStatus rc %d\n", rc);
      /* mask cooked bit, set raw bit */
      kbstInfo.fsMask = (kbstInfo.fsMask & 0x00F7) | 0x004;
      rc = KbdSetStatus(&kbstInfo, hkbd);
      printf("KbdSetStatus rc %d\n", rc);

      rc = DosSetSigHandler(0L, 0L, 0L, SIGA_ERROR, SIG_PFLG_A);
      printf("DosSetSigHandler disallow PFLG_A rc %d\n", rc);
      rc = DosSetSigHandler(ctrlBreakHandler, prevCtrlBreakHandler,
           &prevAction, SIGA_ACCEPT, SIG_CTRLBREAK);
      printf("DosSetSigHandler rc %d   prevAction %d   prevCtrlBreakHandler
           %p\n", rc, prevAction, prevCtrlBreakHandler);

      kbciKey.chChar = ' ';
      while('A' != kbciKey.chChar)
      {
           do {
                if (rc)
                 KbdFlushBuffer(hkbd);
                rc = KbdCharIn(&kbciKey, IO_WAIT, hkbd);

           } while(ERROR_INTERRUPT == rc);
           printf("rc %d   char:%d   scan:%d\n",
                rc, kbciKey.chChar, kbciKey.chScan);
           if(0 != rc)
                break;
      }
      rc = KbdClose(hkbd);
      printf("KbdClose rc %d\n", rc);
 }

 void pascal far ctrlBreakHandler(USHORT usSigArg, USHORT usSigNum)
 {
      PFNSIGHANDLER FAR *prevCtrlBreakHandler;
      USHORT prevAction, rc;

      printf("ctrlBreakHandler usSigArg %u   usSigNum %u\n",
           usSigArg, usSigNum);
      rc = DosSetSigHandler(ctrlBreakHandler, prevCtrlBreakHandler,
           &prevAction, SIGA_ACCEPT, SIG_CTRLBREAK);
      printf("reset DosSetSigHandler rc %d   prevAction %d
             prevCtrlBreakHandler %p\n", rc, prevAction,
             prevCtrlBreakHandler);
 }


 320. INSTALL.TXT Is an ASCII Version of Word Document INSTALL.DOC

 In the Microsoft OS/2 Software Development Kit (SDK) Version 1.05, the
 file INSTALL.DOC is a Microsoft Word document, not an ASCII text
 document. An ASCII version of this document is located in the file
 INSTALL.TXT. Both of these files are located on the INSTALL disk.


 321. Program Doesn't Run in 1.05 Because Include Files Not Updated

 Question:

 Some of my programs that were working correctly under Version 1.03 of
 the OS/2 SDK Presentation Manager no longer run under Version 1.05.
 When I checked the \include subdirectory in Version 1.05, I saw that
 it contains revised files; however, I didn't see any revised files in
 the \include\mt subdirectory for Version 1.05. Could this be part of
 the problem?

 Response:

 Microsoft has confirmed this to be a problem in Version 1.05. We are
 researching this problem and will post new information as it becomes
 available.

 As you discovered, there is a problem in the OS/2 Software Development
 Kit (SDK) Version 1.05 Install program. It did not update the OS/2
 include files in the \include\mt subdirectory.

 To correct this problem, copy the OS/2-specific files that were
 updated from the \include subdirectory into the \include\mt
 subdirectory. Please note that you should not copy the regular C
 include files.


 322. OS/2 SDK 1.03 Spool Files Cause 1.05 to Hang after 10 Seconds

 Problem:

 After booting from the floppy disk, everything appears to be correct
 and the screen ends up with a CMD.EXE window in the upper-left, which
 is overlaid in the center with a Program Starter window with icons for
 MS-DOS and the print spooler at the lower left, and a black sunburst
 at the lower right. After the above screen is displayed and a period
 of about 10 seconds passes, a beep sounds and a pop-up box appears.
 The pop-up looks like an example template, and across the top it says
 "Problem Caption" and below that it says "Problem Text", with buttons
 for "retry" and "cancel" at the bottom. I am unable to either retry or
 cancel because the system is hung at this point. I can press ALT+ESC
 to the get to the 3.x compatibility box, where everything seems
 correct, and then return to Presentation Manager (PM), where the
 system is still hung. In the 10-second period before the beep and
 pop-up box, the PM seems functional; if I press the F1 key, help is
 displayed, the cursor up/down arrow keys move the selected line in the
 Program Starter window, and so on.

 Response:

 The spool files created from the OS/2 SDK Version 1.03 are causing the
 system to display this error and hang up. To correct this problem,
 reboot the system and delete all the old spool files in the c:\spool
 subdirectory while running MS-DOS.

 Microsoft has confirmed this to be a problem in Version 1.03. We are
 researching this problem and will post new information as it becomes
 available.


 323. DosR2StackRealloc Defined in Different Library in 1.05 SDK

 Problem:

 In the OS/2 Software Development Kit (SDK) Version 1.05, what library
 is DosR2StackRealloc defined in? It used to be defined in the
 DOSCALLS.LIB library, but it no longer is.

 Response:

 This function, along with other new Version 1.10 functions, is now
 defined in a file named OS2.LIB. The OS2.LIB file is the OS/2 Version
 1.10 replacement library for the DOSCALLS.LIB library.


 324. Passing Addresses with DosWriteQueue Function in OS/2

 Question:

 On Page 257 in the "Microsoft Operating System/2 Software Development
 Kit Programmer's Reference" Version 1.00 manual is the following
 example that demonstrates the usage of the DosWriteQueue function
 call:

    DosWriteQueue(handle, 0, 11, "Hello World",0);

 Does the address of the string get passed, or the string itself? Also,
 if another process tries to use that address, will it generate a
 general protection (GP) fault?

 Response:

 In the sample piece of code, it is the address of the string that gets
 passed. If another process uses this address, which is actually a
 selector, it will not necessarily cause a GP fault, nor will it point
 to the string. This is because each process has its own set of
 descriptors (located in the LDT). For example, consider the following:

    Process A has its own LDT. In Process A's LDT, descriptor number 1
    points to the physical address 100.

    Process B has its own LDT. In Process B's LDT, descriptor number 1
    points to the physical address 200.

    Each process can legally have the selector value of 1 (remember, a
    selector points to the descriptor contained in the current
    process's LDT). However, while each may have the selector value of
    1, this selector points to a different descriptor. Since each
    descriptor points to a different physical address, the values
    obtained will be different.

 DosWriteQueue has access to the process's LDT that called it. When you
 pass in your selector, DosWriteQueue uses the selector to point to the
 descriptor in your LDT. This way DosWriteQueue is sure to obtain the
 correct data. As mentioned above, this may or may not cause a GP
 fault. Consider the following example:

    If Process A's LDT has 30 descriptors in it, its selectors can be
    in the range of 1-30.

    If Process B's LDT has 20 descriptors in it, its selectors can be
    in the range of 1-20.

    If Process B gets any of Process A's selectors that are above 20
    and tries to use them, this will generate a GP fault because the
    CPU "knows" Process B has only 20 descriptors.

 If Process B must access data in Process A, Process A must set up
 some sort of shared memory. The selector for this shared memory will
 then be valid for both Process A and Process B. This situation is
 discussed starting at the middle of Page 165 in the book "Inside OS/2"
 by Gordon Letwin. This section reads as follows:

    "Thus, the data body of the queue message must be addressable to
    both the client and the serving process. This is straightforward if
    both the client and serving threads belong to the same process
    (because they both automatically use the same LDT). If the client
    and serving threads are from different processes, however, the data
    body of the queue message must be in a shared memory segment that
    is addressable to both the client and the server."

 The book then describes how to use memory suballocation to work around
 this situation.


 325. Allocating Huge Blocks of Shared Memory with DosAllocSeg

 Question:

 The documentation on Pages 48 and 52 of the "Microsoft Operating
 System/2 Software Development Kit Programmer's Reference" for Version
 1.00 states that the function calls DosAllocHuge and DosAllocSeg can
 allocate shared memory using either the DosGiveSeg or the DosGetSeg
 function calls. For DosAllocSeg, this translates to one segment at a
 time. I have the following questions about sharing memory:

 1. What happens (or should happen) if a huge block of memory is
    shared?

 2. Does it have to be shared one segment at a time?

 3. If the base selector is passed, can the receiving process use the
    entire huge block?

 4. Is there an advantage to suballocating a huge block of memory in
    this way?

 Response:

 The following are answers to your questions:

 1. If a huge block is shared, all segments of it are shared.

 2. It does not have to be shared one segment at a time.

 3. Yes, if the base selector is passed, the other process can use
    the whole block.

 4. One advantage of suballocating a huge block of memory this way
    is that the process can reference the segment the same way it
    would reference a huge block that it had allocated for itself,
    after it has, of course, been given addressability to the block
    by the sending process.


 326. OS/2 SDK 1.05 Linker Doesn't Accept /NOE Switch

 Problem:

 The new linker (Version 1.10) shipped with the Version 1.05 OS/2
 Software Development Kit (SDK) no longer supports the /NOE switch.

 Response:

 The linker shipped with the OS/2 SDK Version 1.05 is a stripped-down
 version of the one we provide with our languages. We recommend that
 you use the linker from the OS/2 SDK Version 1.03 release if you need
 to use the /NOE switch.


 327. Control Panel Doesn't Work from Command Line in OS/2 SDK

 Question:

 How do I get the Control Panel (PMCPL.EXE) to run from the command
 line? When I run it, nothing happens. It seems to go through some
 motions and then the window title reads "Completed."

 Response:

 In the OS/2 Software Development Kit (SDK) Version 1.05, the Control
 Panel does not function when run from the command line.

 Microsoft has confirmed this to be a problem in Version 1.05. We are
 researching this problem and will post new information as it becomes
 available.

 In the meantime, you should just run the Control Panel from the
 Utility Programs group in the Program Starter by doing the following:

 1. Go to the Program Starter window.

 2. Click Group.

 3. Select Utility Programs.

 The Control Panel should be the first entry in the list.


 328. Support for COM Port 3 in OS/2 SDK

 The Microsoft OS/2 Software Development Kit (SDK) does not have a
 driver for the third communications port that is unique to IBM's PS/2;
 however, the retail version of IBM's OS/2 will have support for this
 port.


 329. Taking Advantage of Enhanced EGA or VGA Support

 The version of Presentation Manager (PM) shipped with the Version 1.03
 OS/2 Software Development Kit (SDK) supports the EGA in a 640 x 350
 16-color mode and the VGA in a 640 x 480 16-color mode. The
 instructions for setting up PM for the VGA are included in the
 INSTALL.DOC file. Version 1.05 of the OS/2 SDK prompts for display
 type during installation. These two display modes are still the only
 ones supported. Device driver kits (beta versions) are now being
 released to hardware manufactures to bring wider device support to PM.


 330. Capturing Mouse Events in Graphics Mode

 Problem:

 We are trying to use MouReadEventQue() to capture mouse events.
 Everything works properly in text mode, but when we set the mode to
 graphics, we no longer receive mouse events. The following is an
 outline of the program:

       .
       .
       .

  VioSetMode(&viom,0))
  MouOpen(0L,&hmou);
  mevent = 0x0100;
  MouSetDevStatus(&mevent,hmou);
  mevent = MOU_BUTTON1_MASK;
  MouSetEventMask(&mevent,hmou);

  while(count < 10)
  {
  MouReadEventQue(&mouevent,&fWait,hmou);

   if (mouevent.fs)
       {
           DosBeep(600,150L);
       }
   }

   VioSetMode(&oldmode,0);
       .
       .
       .

 Response:

 You can get events from the mouse in graphics mode, but you need to be
 sure that you open the mouse and set the device status before you set
 the video mode. Changing the above code so that the MOU calls are
 before the VIO calls will correct the problem.


 331. Trouble Setting Border Color (Overscan) with EGA

 Problem:

 I am using OS/2 with an EGA and I am trying to set the border color
 using VioSetState(). When I do this, the error status 421 (invalid
 parm) is returned. The following is a copy of my program:

 main ()
   {
     struct _VIOINTENSITY request1;
     struct _VIOOVERSCAN request;
     int status;

     request.cb = sizeof request;
     request.type=1;
     request.color=0x10;
     status = VioSetState(&request, 0);
     if (status)
      printf ("Set border failed. Status=%i", status);

    }

 Response:

 Setting the border (overscan) color is only legal for CGA, VGA, or IBM
 PS/2 display adapters.


 332. OS/2 SDK: MARKEXE Returns Fatal Error U1013

 Question:

 When I use MARKEXE.EXE in a MAKE file, it returns fatal error U1013
 even though it successfully marked the .EXE file. Why does MARKEXE.EXE
 return this error?

 Response:

 MARKEXE.EXE does not initialize a return value upon completion. This
 causes other programs that expect a return value (such as MAKE) to
 incorrectly state that an error has occurred. If you invoke MAKE with
 the /I option (see Page 312, Section 14.5 of the "Microsoft CodeView
 and Utilities Software Development Tools for the MS-DOS Operating
 System" manual for Version 5.10), MAKE will ignore all exit codes
 returned by programs called from within the MAKE descriptions.


 333. Unable to Get Shifted Characters from within PM Shell

 Problem:

 In Version 1.05 of the OS/2 Software Development Kit (SDK), if you
 start up the DOS compatibility box from the Presentation Manager (PM)
 Shell and then attempt to run a PM program from within PM, such as
 Petzold's Typer program, you can no longer get shifted characters when
 you type.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.05. This
 problem was corrected in Version 1.06 of the OS/2 SDK.


 334. Memory and Display Requirements for OS/2 1.10 Final Release

 Question:

 What will the memory and display adapter requirements be in the final
 release of OS/2 Version 1.10? Also, will the Program Selector Shell
 from the OS/2 Software Development Kit (SDK) Version 1.03 be supported
 in the final release of Version 1.10?

 Response:

 The final release of OS/2 Version 1.10 will require from 3 to 3.5
 megabytes of memory. It will only support EGA and VGA graphics cards.

 The Program Selector Shell from Version 1.03 will not be supported in
 the final release of OS/2 Version 1.10. The only shell that will be
 supported is the Presentation Manager graphics-based shell.


 335. Sending C and Pascal Output to Printer in OS/2 SDK 1.05

 Question:

 I had trouble printing bound programs in Pascal and C with previous
 versions of the OS/2 Software Development Kit (SDK). In C, it was
 necessary to do an open and then an fdopen to print, and in Pascal, it
 was impossible to print altogether. Have these problems been resolved
 in Version 1.05 of the OS/2 SDK?

 Response:

 Yes. In OS/2 SDK Version 1.05, you do not have to print to a file
 handle obtained using the open command by associating it with an I/O
 stream with the fdopen command. As the following program demonstrates,
 you can open the printer with the open command and then write to it
 using the write command:

 #include <fcntl.h>
 #include <sys\types.h>
 #include <sys\stat.h>
 #include <io.h>
 #include <stdio.h>

 int fh;

 main()
 {
      if ((fh = open("prn",O_WRONLY)) == -1)
           printf("Unable to obtain File Handle.\n");
      else
           write(fh,"Hello",11);
 }

 You can then compile this program for dual mode by using the /Fb
 compile option.


 336. OS/2 Utility to Modify/Create QuickHelp Files

 Question:

 Is there a tool or sample code so that we can modify and/or create our
 own QuickHelp files?

 Response:

 In the OS/2 Software Development Kit (SDK) Version 1.06 we have
 included a compiler called HELPMAKE.EXE that allows you to create
 databases readable by the QuickHelp utility.


 337. Handling an NMI Issued from a Graphics Card under OS/2

 Question:

 If OS/2 can't handle a nonmaskable interrupt (NMI) that a graphics
 card has issued, is it possible to do a simple IRET to alleviate the
 condition?

 Response:

 Issuing an IRET will not work in cases where OS/2 is in protected mode
 because the routine on the graphics card is written for the real-mode
 environment. The NMI would probably only cause a protection-violation
 error to occur.


 338. No Way to Change Program Title on Program Selector in OS/2 SDK

 Question:

 Is there a way to change the program title on the Program Selector for
 the current session?

 Response:

 A Presentation Manager (PM) application can use the API function call
 WinChangeSwitchEntry() to change its title in the OS/2 Version 1.10
 Task Manager. There is currently no official way for an application
 other than a PM application to programmatically change the title in
 the Task Manager or the Version 1.00 Program Selector. This feature is
 under review and will be considered for inclusion in a future release.


 339. How to Enable CVP Support for IBM's OS/2

 Problem:

 When I run CVP on IBM's OS/2, I get the following error message:

    SYS0197: IBM Operating System/2 is not presently configured
             to run this application.

 Response:

 CodeView uses IOPL segments. By default, IBM's OS/2 does not come with
 support for IOPL programs enabled. To enable this support, add the
 following line to your CONFIG.SYS file and reboot:

    IOPL=YES


 340. Determining Screen Mode when Using VioSaveRedrawWait()

 Question:

 How can a background process, such as a keyboard monitor, find the
 current foreground screen mode, assuming the foreground process has
 done a VioSaveRedrawWait() [which means the background process can't
 do a transparent VioPopUp()]?

 Response:

 Using VioSaveRedrawWait() [and VioModeWait()] in your application
 prevents you from finding out what the screen mode of the foreground
 application is. Because these modes indicate direct hardware
 manipulation, there is no way for a separate process (or the system)
 to know what mode you are using, particularly with graphics cards that
 have write-only registers, such as the EGA.


 341. Incorrect Documentation on OS/2 Multitasking Functions

 The comments on Pages 14-15 in Section 2.2, "Multitasking Functions,"
 in the "Microsoft Operating System/2 Programmer's Reference" manual
 regarding the inheritance of queues by child processes are incorrect.

 The queues are actually just an abstraction that is implemented with a
 DLL, QUECALLS.DLL, that runs at ring 3 (application level). An
 application can write its own queue routines that would accomplish the
 same thing. Because this code is at the application level, the kernel
 is not managing it; therefore, queue handles are not inherited by a
 child process created with the kernel call DosExecPgm().


 342. Inheritance of System & RAM Semaphores between Parent & Child

 Question:

 Does inheritance between parent and child also apply to system and RAM
 semaphores? We are using generalized DLL-based routines to perform
 queue creation, sending, and receiving, as well as semaphore creation,
 setting, requesting, and clearing for different applications. Are
 there any problems with using DLLs in this way (especially between the
 parent and child processes using the same DLL)?

 Response:

 System semaphore handles are not inherited. It is the responsibility of
 each process to open the system semaphore.

 A RAM semaphore "handle" is actually the address of the location in
 memory where there is a LONG. Because of this, it is possible for the
 RAM semaphore to be placed in shared memory and have more than one
 process access it. However, there is one important problem with this.
 If process A sets this semaphore and then dies, there is no automatic
 cleanup done for it like there is for system semaphores, which the
 kernel knows about. This means that if process B now blocks on the RAM
 semaphore that was set by process A, process B will block forever. A
 good alternative to RAM semaphores is FS (Fast Safe) RAM semaphores,
 which is a new feature of OS/2 Version 1.10. FS RAM semaphores have
 ownership and use counts, so they are cleaned up by the kernel if the
 owning process dies while owning them. They are also good for
 recursive applications.

 Another alternative to using the queue calls is to use named pipes in
 message mode. Support for named pipes is available in Version 1.00
 with a device driver. They provide a very efficient means of
 transferring data between client/server processes and their handles
 can be inherited. Another advantage to named pipes is that they will
 work transparently over a network, as well as between processes on the
 same computer. Please refer to the LAN Manager reference manuals that
 come with Version 1.04 of the OS/2 SDK.


 343. OS/2 SDK: Setting Up Automatic Reboot when GP Error Occurs

 Question:

 Is there an easy way to make OS/2 automatically reboot after a general
 protection error that occurs at the application level?

 Response:

 There are a variety of techniques to accomplish this task; two of
 them are as follows:

 1. You could write a device driver that attaches itself to the
    32-millisecond timer interrupt and then periodically checks a
    dedicated semaphore in its data segment for each application you
    wish to monitor. This semaphore would be set up with a
    PhysToUVirt() DevHelp() command. Each application would then
    periodically write a 1 (for example) to its semaphore from a
    separate thread. The device driver would check for this 1 before
    writing a 0. If it ever detected a 0, the device driver would know
    the application had crashed and been aborted by OS/2, and it could
    then take appropriate action.

 2. A similar and probably simpler technique is to have a background
    job communicating and checking on your application in a way
    similar to the one described above using OS/2 interprocess
    semaphore commands.


 344. Considerations for Applications That Read Key and Mouse Events

 When using two threads, one blocking on MouReadEventQueue() (mouse
 events) and the other blocking on KbdCharIn() (keystrokes), you must
 observe certain cautions.

 For instance, if the customer presses a key that would cause part of
 the screen that might have the mouse pointer over it to be drawn, it
 is necessary to remove the mouse pointer with a call to
 MouRemovePtr(), then use MouDrawPtr() after the screen has been
 updated. Normally this is not a problem, but if the thread reading the
 mouse is blocked on the MouReadEventQueue() call, there is a semaphore
 internal to the MOU subsystem that will block the MouRemovePtr() call
 until a mouse event occurs and the mouse reading the thread returns
 from its MouReadEventQueue() call. A workaround for this problem is to
 draw your own pointer and not call the MouRemovePtr()/MouDrawPtr()
 calls.

 Another problem occurs if the customer presses a key that would cause
 the application to exit; in this case, MouClose() is typically called
 to close the mouse. Again, this call will block on the internal MOU
 semaphore until an event occurs. The workaround is to not call
 MouClose(), but instead to let the system close the mouse for you
 implicitly when your application exits. This is not the best
 programming style, but it works.

 The following are four other workarounds to these general problems:

 1. Send IOCTLs directly to the mouse device driver when it is
    necessary to do something from the keyboard while reading a thread.
    Most of the MOU calls have equivalent IOCTLs that can be used and
    will bypass the "per screen group" semaphore in the MOU subsystem.

 2. Use a mouse monitor that reads mouse events directly; therefore, it
    will not be necessary to block on MouReadEventQueue().

 3. Use a polling loop. This is obviously not as desirable in a
    multitasking operating system like OS/2; if it is necessary to use
    this approach, the loop must have a DosSleep() call within it so
    that other threads in the system still get time. The value to use
    for DosSleep() can be experimentally determined; the value of 25
    has been reported to work acceptably.

 4. Presentation Manager (PM) applications do not have these
    limitations. The mouse and keyboard events are converted into
    "messages" and are combined into one message queue. This queue
    contains both types of events in time sequence order.


 345. Turning NUM LOCK Off or CAPS LOCK On with KbdSetStatus()

 Question:

 I used the following code to attempt to turn NUM LOCK off:

 struct  KbdStatus  OurKbdStatus;
 /* KbdStatus is defined in subcalls.h */
 OurKbdStatus.length = sizeof(OurKbdStatus);
 KBDGETSTATUS((struct KbdStatus *)&OurKbdStatus,0);
 OurKbdStatus.shift_state &= 0xFFDF;              /* turn off bit 5 */
 KBDSETSTATUS((struct KbdStatus *)&OurKbdStatus,0);

 Both KbdGetStatus() and KbdSetStatus() returned 0, no error, but
 NUM LOCK was not turned off. I also tried to turn CAPS LOCK on by doing
 the following:

 OurKbdStatus.shift_state |= 0x0040;              /* turn on bit 6 */
 KBDSETSTATUS((struct KbdStatus *)&OurKbdStatus,0);

 This didn't work either. How do you turn NUM LOCK, CAPS LOCK, etc. on
 and off?

 Response:

 When setting the status of the shift state, you must turn on a bit in
 the bit_mask field of the keyboard status structure to tell
 KbdSetStatus() that you want to change the shift_state field. By
 default, it will not change that field. The following code
 demonstrates how to turn on a bit in the bit_mask field:

 #include <subcalls.h>
 #include <stdio.h>

 struct KbdStatus kbds;
 unsigned short rc;

 main()
 {
     kbds.length = sizeof(kbds);
     rc = KBDGETSTATUS(&kbds, 0);

     kbds.shift_state &= 0xFFDF; /*mask out numlock              */
     kbds.bit_mask |= 0x0010;    /*enable setting the shift state*/
     rc = KBDSETSTATUS(&kbds, 0);
 }

 The setting of the bit_mask field, now called fsMask, is described in
 QuickHelp and in the "Microsoft Operating System/2 Programmer's
 Toolkit Reference" manual under KbdSetStatus().


 346. Determining if Computer Has a MicroChannel Backplane (PS/2)

 Question:

 How does an OS/2 device driver determine at initialization time if the
 machine it's running on has a MicroChannel backplane (PS/2)? Under
 MS-DOS this was done by doing an INT 15H. Under OS/2 you can only do
 BIOS calls from real mode, but the initialization strategy routine
 calls the driver in protected mode and a RealToProt() can't be done at
 initialization time.

 Response:

 An OS/2 device driver can issue some of the APIs at initialization
 time. One of them is DosDevConfig(), which gets the information about
 the machine and the attached devices. Your device driver needs to
 issue DOS API DosDevConfig() from the initialization routine for items
 4 and 5 (please refer to Pages 74 and 75 of the "Microsoft Operating
 System/2 Programmer's Toolkit Programmer's Reference" manual for
 Version 1.00). When this API returns, it will have the information
 about the PC submodel and the model type.


 347. Writing to Screen After Device Driver Has Been Initialized

 Question:

 We want to print debug information to the screen from within a device
 driver at KERNEL time. Of course, this is trivial in MS-DOS, because
 we can simply use the INT 10H services without too much concern about
 reentrancy. However, this can't be done in OS/2 since the driver is in
 protected mode at that time. The DevHlp ProtToReal() call cannot be
 made at that time either, and the DosPutMessage() and VIO calls are
 useless as well.

 Use of the KERNEL debugger is not a viable option for what we want to
 do at this time, nor can we write directly to video RAM since it may
 be in graphics mode. How can we write to the screen at this time?

 Response:

 There is no direct way of writing to the screen from the device
 driver after the initialization is completed. However, you may want
 to consider the following suggestion: have a ring 3 process write
 the message for you.

 To accomplish this, you will first need to write a daemon process to
 accompany your device driver. Then, have your daemon process call down
 into your driver via a general IOCtl that you have defined. When your
 device driver receives this IOCtl, it can trap that ring 3 thread and
 hold it until it wants to write a message. When your driver is ready
 to write, it just needs to release the thread, which should then go on
 to write the message onto the screen (either directly or by using the
 VioPopup mechanism). The device driver can save the message string
 somewhere in memory, which is shared by both the ring 3 process and
 the device driver.


 348. Real Mode Device Driver in .EXE Format Can't Be Loaded

 Problem:

 If a real mode device driver in OS/2 1.00 is in .EXE format, an
 error occurs when the device driver is loaded.

 Response:

 You need to convert the .EXE format of the MS-DOS device driver into .SYS
 format using the EXE2BIN utility. This should allow the MS-DOS driver to
 be loaded under OS/2. There are some restrictions on the MS-DOS drivers
 that are used under OS/2. The restrictions are as follows:

 1. Block device drivers are not permitted in MS-DOS mode.

 2. Only a limited set of character device drivers can be supported by
    OS/2. To run in the MS-DOS mode, a character device driver cannot have
    a hardware-interrupt handler. Its device must be polled rather than
    interrupt driven.

 3. The device driver should support the request packet for all the
    commands, which is a character device driver that OS/2 supports.

 For more information, please refer to Section 1.13, on Page 28 of the
 "Microsoft Operating System/2 Device Drivers Guide."


 349. OS/2 SDK: Limit of 254 Segments Per Process

 Question:

 I have a FORTRAN application that has exceeded the limit of 254
 segments per process. Will this limitation be changed in future
 versions of OS/2?

 Response:

 The limitation of 254 segments is actually a limit in the executable
 header in an .EXE file. This means that an application that uses DLLs
 can have 254 segments in its main .EXE and 254 in each DLL that it
 accesses. Since 254 segments times 64K for each segment produces an
 .EXE that is over 16 megabytes, the problem is not really in the limit
 in the .EXE header, but rather in the way the segments are built into
 the FORTRAN executables. Currently, there are no plans to change
 either the limit on the .EXE header or the default behavior of the
 FORTRAN compiler. Therefore, the only workaround is to combine the
 common blocks in the program so that fewer physical segments are
 required.


 350. Clarification of Process Status and Profile Support in OS/2

 Profiling and the Process Status (PS) utility use APIs in the KERNEL
 that will not be in any final release of the product. They are only
 included in special builds of the KERNEL provided to Microsoft OS/2
 SDK customers. In the Microsoft OS/2 SDK Version 1.05 release, the
 KERNEL contains these APIs, and the utilities and header files are in
 the subdirectory \PMSDK\PROFILER.


 351. OS/2 SDK: Description of DLL Load Architecture

 Below is a description of the dynamic link library (DLL) loading
 mechanisms concerning segment-selector allocation and actual segment
 loading.

 When the loader loads a program and resolves references to a dynamic
 link library, which can in turn load more DLLs, all of the selectors
 are reserved in each process's local descriptor table (LDT). It is
 necessary to reserve the selectors in all LDTs because the code and
 usually the data in a DLL can be shared by all processes. The
 descriptors are initially marked as not present.

 In building the DLL, it is possible to specify two options for the
 code and data segments: PRELOAD and LOADONCALL. The default is
 LOADONCALL, which means that the segments that are necessary for a
 routine are only loaded into memory the first time the routine is
 called. The PRELOAD option means that at load time all segments will
 come into memory. If the DLL is located on removable media like a
 floppy drive, the default is PRELOAD because the system cannot assume
 that the media with the DLL will not be removed.


 352. OS/2 SDK: Information on DosGetResource()

 Problem:

 If I call the same TypeID and NameID within the same process with the
 DosGetResource() call, the system assumes that the segment is already
 loaded. The following is a portion of my code:

    DosGetResource(NULL, Topic, SubTopic, &selHelpText);
    DosSizeSeg(selHelpText, &ulSegSize);
    lpHelpText = MAKEP(selHelpText, 0);
    _fstrncpy(szText, lpHelpText, ulSegSize);
    DosFreeSeg(selHelpText);

 Response:

 DosGetResource() acts a little differently than you might expect. It
 does not get you a fresh copy of the resource each time, but instead
 gives you a selector to an already loaded resource segment. It would be
 more efficient if you kept the selector around as long as you need it,
 but you should also be able to call DosGetResource() again and get the
 same selector. In your case, problems occur because you are calling
 DosFreeSeg() on memory that has not been allocated with DosAllocSeg().
 Your code should work properly, provided that you remove the call to
 DosFreeSeg().


 353. OS/2 SDK: File and Pipe Mode Information

 OS/2 function calls such as DosWrite() and DosMkPipe() default to
 binary mode. OS/2 does not provide support for text mode. The C
 run-time function calls such as write() are what contain the options
 for text or binary mode. In the C run-time, you can specify text or
 binary mode with the open() function. There is no such feature with
 OS/2.

 The handles stdin and stdout also default to binary mode. However, C
 run-time function calls, such as printf(), usually "massage" the data
 before sending it to stdout, so in this environment it could be
 considered "text" mode. OS/2 itself will not do this, however.

 If a process starts a child process, the child process will inherit
 the file handle, but not the mode specified by the parent. This is
 because the text/binary mode is maintained by the C run-time and the
 kernel has no knowledge of it; therefore, the text/binary mode cannot
 be inherited.


 354. Returning Virtual Address in Shared Memory to Application

 Question:

 I have the following two questions about returning virtual addresses
 in shared memory to an application:

 1. Assuming I use DevHlp_PhyToUVirt(), how do I make the virtual
    address obtained available to an application? Do I need to create
    my own IOCtl call, and then do a DosDevIOCtl() and return the
    value?

 2. Is it possible to return a value like this from DosOpen()? If so,
    how?

 Response:

 The answers to your questions are as follows:

 1. Yes, you do have to make your own IOCtl call, and also do a
    DosDevIOCtl() in the application program. This will start the
    strategy routine of your driver. In the strategy routine, you
    should do a DevHlp_PhyToUVirt() and return the selector to the
    application program as one of the parameters.

 2. No, it is not possible to return this kind of value from DosOpen().


 355. OS/2 SDK: VioGetBuf() and VioShowBuf() Removed from API.LIB

 VioGetBuf() and VioShowBuf() were removed from API.LIB when it was
 discovered that there were potential problems under certain
 circumstances when using these functions in MS-DOS. These functions
 will not be included in the FAPI; therefore, you will need to create
 your own functions with the same names and link them in to resolve the
 external references.

 The references to VioGetBuf() on Pages 326-327 and to VioShowBuf() on
 Pages 379-380 of the "Microsoft Operating System/2 Programmer's
 Toolkit Programmer's Reference" manual for Version 1.00 will be
 removed in a future release of the documentation.


 356. OS/2 SDK: DosDevIoctl() Category 03H Documentation Error

 There is a documentation error on Page 162 of the "Microsoft Operating
 System/2 Device Drivers Guide" labeled "Pre-release". The only IOCtl
 available to an application program under Category 03H is function 72H
 (Get Pointer-Draw Address); the other IOCtl commands listed on Page
 162 are not available.


 357. OS/2 SDK: Allocating Memory on 64K Boundary for DMA Transfer

 Question:

 Could you give me some information on how to allocate memory on a 64K
 boundary from an application to allow for correct DMA transfer?

 Response:

 A device driver will allow you to do this, but it cannot be done from
 an application. From the application level, the OS/2 memory-management
 scheme is a virtual scheme, and it does not allow such physical
 segment alignment. A device driver should be used in this case, where
 such physical demands are required.


 358. Specifying a Device Rather Than a Filename in DosOpen()

 To specify a device rather than a filename in DosOpen(), do the
 following:

    DosOpen ( (char far *) "TEST$",
              (unsigned far *) &Shandle,
              (int far *) &Result,
              0l,
              (int) 0,
              (int) 1,        /* open if there, fail if not  */
              (int) 0x42,
              0l,
            ) ;


 359. Presentation Manager: File Manager Selection Problem

 When using the File Manager in OS/2 Presentation Manager (PM), a
 problem exists associated with file selection. After selecting a
 single file and deleting it, the next time a file is selected, two
 items are shown as selected. Deselecting the second item results in
 both being shown as not selected.

 Microsoft has confirmed this to be a problem in the OS/2 Software
 Development Kit (SDK) Version 1.05. This problem was corrected in
 Version 1.06 of the OS/2 SDK.


 360. OS/2 SDK: Inquiring about a Module Name

 Question:

 How can you access the name of a module?

 Response:

 This information is contained in the .EXE header. Look in the file
 NEWEXE.H for information on the .EXE header. This file should be in
 your include directory after you have installed the OS/2 Software
 Development Kit (SDK). There is no API that will directly give you the
 module name instead of the filename, but NEWEXE.H should give you the
 location in the .EXE header where the module name is found, so you can
 open the .EXE file and look for the module name there.


 361. OS/2 SDK: Queued Semaphore Requests Not Allowed

 Question:

 How would you use semaphores to serialize access to a resource in a
 queued fashion? The order in which requesting processes are granted
 semaphores depends on scheduling rather than the order in which the
 semaphores are requested. Does the semaphore interface provide the
 ability to have semaphore requests queued so that they are granted in
 the order in which they were requested? The requirement for queued
 access to a resource would seem to be fairly common.

 Response:

 Unfortunately, there are no semaphore mechanisms built into OS/2 that
 allow queued access. When threads are being scheduled, the next thread
 to run is chosen based on its priority. The semaphore APIs are
 primitives, and any higher-level behavior that you want to accomplish
 will have to be built off of them. To accomplish what you want to do,
 you need to explicitly implement the queuing in your application.


 362. OS/2 SDK: How to Run .CMD Files in Program Starter

 The steps below describe how to run a .CMD file from the Program
 Starter.

 To run a .CMD file from the Program Starter, do the following:

  1. Create the .CMD file.

  2. Select Program from the Program Starter menu.

  3. Select Add from the Program Starter menu.

  4. Type in the program title.

  5. Enter the complete path and filename. The following is an example:

        c:\os2\test.cmd

  6. Select Add from the Program Starter menu.

  7. A warning message should appear that asks you if the .CMD file is
     a Presentation Manager application. Click the No button.

  8. Another pop-up menu will appear asking for the mode this character
     application should run under. Select the Run on Full Screen option.

  9. Click the Enter button.

 10. The .CMD file should then be added to the Program Starter's menu.
     Select the .CMD file from this menu.

 11. The .CMD file should run and immediately return to the Task Manager
     when it completes.

 If you make a mistake while entering the .CMD file into the Program
 Starter menu (e.g. you selected Take System Default instead of Run on
 Full Screen) and then try to use the Change command to reset it, a
 SYS1041 error message is still returned. To correct the mistake you
 have made, you must select Delete and start over again.


 363. OS/2 SDK: Displaying Mouse Pointer in EGA/VGA Graphics Mode

 Question:

 How do we get the mouse pointer to appear when using OS/2 with an EGA
 or VGA graphics card?

 Response:

 OS/2 supports the mouse under EGA and VGA graphics modes, but does not
 provide pointer drawing for the graphics modes. This means that you
 can go into loop reading events with MouReadEventQueue() and will be
 informed of button presses and mouse motion, but OS/2 will not draw
 the cursor on the screen. If you are going to be using a graphics
 mode, you must use MouSetDevStatus() to specify that you will be doing
 your own pointer drawing, and it is the responsibility of your
 application to draw the shape of the pointer on the graphics screen
 when you get a mouse event saying that the mouse has moved. This is
 only a high-level overview. There is a specific example of drawing
 your own mouse pointer and using a graphic screen mode in the LIFE
 example included with the Microsoft OS/2 Version 1.00 Programmer's
 Toolkit.


 364. BLOCK.ARC: Drive Not Ready Detection Sample Program

 Question:

 I want to be able to detect the hard error returned when selecting a
 disk drive that is not ready (e.g. when a user selects a drive for my
 application to use). However, DosSelectDisk(1), which selects Drive A,
 does not return the error INVALID DRIVE, even if I've previously
 disabled handling hard errors with the call DosErrors(0). INVALID
 DRIVE seems to mean the drive number is out of range. How can I detect
 if the drive is not ready?

 Response:

 The most common way to detect if a drive is not ready is to use the
 DosOpen() function with the DASD option. To avoid the "Drive not
 Ready" message from OS/2, you should call DosError(0) to disable
 critical-error handling. When you do this, DosOpen() will return an
 error of ERROR_NOT_READY.

 A sample program in the Software Library named BLOCK.ARC detects if a
 drive is not ready. This file can be found in the Software Library by
 searching for the filename BLOCK.ARC, the Q number of this article, or
 S12147. BLOCK.ARC has been archived with the PKARC utility. You will
 need to unarchive it with PKXARC. A copy of PKXARC can be found on
 your Microsoft OnLine Utilities Disk 2.


 365. Additional Segment after Init, and Load High Device Drivers

 Question:

 Is there any way that an OS/2 Version 1.10 device driver can keep
 extra segments after the initialization process has completed?

 Response:

 Yes, starting with OS/2 Version 1.10, a device driver can keep
 additional segments even after initialization. These segments must be
 specified as IOPL segments in the definition file. All segments in a
 device driver must be specified in the correct order. These segments
 also have to be locked down from the initialization routine.

 The additional segments are located in the High Memory Area at boot-up
 time. These segments can only be accessed in protected mode. The
 primary segments (original segments) are located in low memory as
 usual. The kernel only calls the primary segment of the device driver.
 If a device driver wants to execute the code in the additional
 segment, it should transfer the execution through a FAR call. These
 FAR addresses should be stored in the primary segment.

 A device driver can change the CPU mode by using the DevHlps
 RealToProt() and ProtToReal(). After the processing is complete, the
 device driver must return the processor to the mode it was in when the
 device driver was entered.

 The following is a list of rules and steps to get segments in your
 device driver to load into the High Memory Area:

 1. The first two segments that appear in the .SYS file must be the
    default low-data segment and the default low-code segment.

 2. All dispatching from the OS/2 kernel will be made to the default
    low-code segment (i.e., strategy routine, interrupt handlers, timer
    ticks, etc.). These routines must still be bimodal.

 3. To get other segments to load into High Memory, the IOPL bit must
    be set by the device driver's .DEF file.

    Note: When listing segments in a .DEF file, be sure to list all the
    segments in the order you wish them to be linked (i.e., low data,
    low code, init code/data, high code/data). By setting the IOPL bit
    on a segment, it will be loaded into High Memory, and it will not
    be discarded after initialization time.

 4. The high-code segments are not locked down after the device driver
    is loaded. To lock them down, call DevHlp_Lock, sub function 1.
    This step is required. If the device driver attempts to access
    memory that is not present, the system will crash.

    Note: This now works at INIT time. Older documentation will claim
    it doesn't. Also, newer documentation may suggest using DevHlp_Lock
    type 3. This may cause a protection fault during the boot; we
    recommend using type 1 to avoid this problem.

 5. The high segments can only be accessed in protected mode.
    DevHlp_RealToProt can be used to get into protected mode when
    necessary (even at strategy time). If the device driver switches
    the processing mode, it must restore the mode before returning to
    the kernel (i.e., DevHlp_ProtToReal).

    Note: For performance reasons, your device driver should attempt to
    keep the mode switching as low as possible.

 6. Base device drivers cannot have any load-high segments.


 366. Reason for General Protection (Trap D) Error Message

 Question:

 Sometimes my OS/2 application crashes with the following error
 message:

    The system detected a general protection fault (trap D) in a
    system call.

 What causes this error to occur?

 Response:

 The "trap D" error message can occur in the following two situations:

 1. When an application tries to use a segment that has not been
    allocated to the application.

 2. When a reference is made that is out of the range of a segment's
    size. Generally, this occurs when a buffer is passed to a system
    routine and the size of the buffer is less than the size parameter
    passed to the system routine.

 The system detects this overflow within the kernel, which is why the
 error says that it was detected in a system call. Even though the
 system says that it detected the error in the system call, this does
 not imply that the system had an error. Rather, it means that the
 application passed an incorrect buffer and/or size parameter to the
 system call.


 367. OS/2 SDK: HELPMSG Documentation Error

 The text displayed when HELPMSG is invoked with SYS 2092 in Version
 1.05 of the OS/2 SDK is incorrect. For example, it contains
 "1Microsoft", and the first line contains asterisks instead of a
 parameter. This problem was corrected in Version 1.06 of the OS/2 SDK.


 368. OS/2 SDK: VDISK.SYS Sector Size Documentation Error

 The "Microsoft Operating System/2 Setup Guide" (document number
 510830003-200-001-1087) incorrectly states on Page 72 that the sector
 size can be set to 1024. If you set the sector size to 1024, VDISK.SYS
 resets it to 512, which is the maximum value allowed for this
 parameter.


 369. OS/2 SDK: System File Number Information

 Question:

 What is the meaning of what IBM calls the System File Number? What is
 its intended use in a device driver?

 Response:

 The System File Number is a unique number that is assigned with an
 open request [i.e., DosOpen()]. It is usually not used by the device
 drivers except the printer device driver. The printer device driver
 uses the System File Number for spooling the files, which is how it
 associates a DosClose() with a temporary file in the spooler.


 370. OS/2 SDK: Killing Thread 1 Causes Process to Die

 Question:

 In the OS/2 Software Development Kit (SDK) Version 1.05, when you kill
 Thread 1 the whole process dies. Why is this happening?

 Response:

 You should kill off only subsidiary threads with DosExit(EXIT_PROCESS,
 return_code). Thread 1 has special properties. You should kill Thread
 1 with DosExit(EXIT_PROCESS, return_code) only when the entire process
 is done. Thread 1 is the thread that is interrupted by the system when
 the process receives a signal. (See Chapter 5 of Gordon Letwin's
 "Inside OS/2" book for more details on threads).

 This is a permanent change for OS/2 Version 1.10 from OS/2 Version
 1.00.


 371. OS/2 SDK: United Kingdom (UK) Keyboard Mapping Problems

 Problem

 I am changing the VIOTBL.DCP and KEYBOARD.DCP code-page files from the
 US configuration to the United Kingdom (UK) configuration. I have
 "un-remarked" the following line in my CONFIG.SYS file and changed the
 "US" to "UK" as follows:

    devinfo=kbd,UK, c:\os2\dev\keyboard.dcp

 The keyboard translation gives a number of incorrect mappings as
 follows:

 Key           Key Mapping     Shifted Key   Shifted Key Mapping

  6                6               ^                 &
  7                7               &                 '
  8                8               *                 (
  #                ]               ~                 }

 Response:

 Microsoft has confirmed this to be a problem in Version 1.05. This
 problem was corrected in Version 1.06.


 372. OS/2 SDK: DevHlp_Block Rescheduling Priority

 What is the rescheduling priority after a device driver's kernel
 routine issues a DevHlp_Block?

 Response:

 When a device driver uses DevHlp_Block, the scheduler removes this
 thread from the current run queue and starts a thread whose priority
 is highest at that time.


 373. OS/2 SDK: Unresolved External Error Occurs with VioWrtTTy()

 VioWrtTTy() was changed to VioWrtTTY() (the "y" was changed to "Y") to
 maintain compatibility with IBM's OS/2, which has the uppercase "Y" in
 it. If you do not use VioWrtTTY() with Version 1.05, you will receive
 an "unresolved external" error when compiling your program.


 374. MOU.ARC: Sample Mouse Program That Interprets Up/Down Events

 MOU.ARC is a sample program in the Software Library that detects a
 mouse-down or a mouse-up event. This program has been tested with the
 OS/2 SDK Version 1.05 and the Microsoft Mouse. The program does not
 attempt to interpret anything but up and down events and does not
 "weed out" other possibilities, such as down movement.

 MOU.ARC can be found in the Software Library by searching for the
 filename, the Q number of this article, or S12160. MOU.ARC has been
 archived with the PKARC utility. You will need to use PKXARC to
 unarchive it. A copy of PKXARC can be found on the Microsoft OnLine
 Utilities Disk 2.


 375. Determining Which Process Has Sent a Request to Device Driver

 Question:

 I am in the process of designing an OS/2 (probably bimodal) character
 device driver. Because I need to create and maintain a "minor" device
 for each process that makes a request of the device driver, I need a
 way to find out which process has made the OS/2 API call which in turn
 has caused OS/2 to generate and send the request packet to my device
 driver. Thus, I want to create a "minor" device when a process opens
 the driver by recording the identity of the requesting process (PID #)
 and then mapping all subsequent I/O requests to the proper minor
 device.

 Is there a DevHlp routine or some other mechanism that would provide
 me with this information?

 Response:

 The DevHlp GetDosVar() routine returns the address of important kernel
 variables. There are 11 such variables that the kernel maintains for
 device drivers. If a device driver needs a pointer to any of these
 variables, it loads the variable number in register AL and issues
 the DevHlp GetDosVar(). On return, the register AX:BX points to a
 memory location that contains the Segment/Selector Offset pair of some
 structure.

 One of these variables, LocalInfoSeg(), gives the process-specific
 information (PID, priority, session, etc.). You may want to use this
 variable to find out the PID of the process whose thread of execution
 is in the device driver.

 The address in the register AX:BX is a bimodal address.


 376. OS/2 SDK: Methods of Reading Boot Sector

 The following are two different methods for reading the boot sector:

 1. Open the device as a DASD and do DosReads on it.

 2. Use the IOCtls to do the reads. In this case, you would first open
    the device and use category 8 function 64H (read track) to read
    sector 0 (the first sector, which is called the Master Boot
    Sector). This sector contains information about the number of
    hidden sectors (please refer to the IBM AT technical reference
    manual for more information on the Master Boot Record format); skip
    these sectors and read the next sector. That next sector will be
    the boot sector of Drive C.

    If you want to read the boot sector of an extended volume, sector 0
    will get you the extended boot record (not the boot sector of the
    D: partition). Again, you need to figure out the position of the
    boot sector, as described above.


 377. PM: Changing Text Limit in Edit Control in Dialog Box

 Question:

 When I put an edit control in a dialog box, no matter what the size
 of the box is on the screen, or whether I set ES_AUTOSCROLL, the
 dialog box won't accept more than 30 characters. If I try to enter
 more than 30 characters, it beeps at me. How can I get the dialog box
 to accept more than 30 characters?

 Response:

 The default text limit in an edit control in a dialog box is 30
 characters. To change it for a particular edit control, send the
 control an EM_SETTEXTLIMIT, where the low-order word of mp1 specifies
 the maximum number of characters. You must also set mp2 to zero.


 378. PM: Meaning of DosStartSession() 0x110F Return Code

 Question:

 When I try to start a session with DosStartSession(), I get a return
 code of 0x110F. What does this mean? The session is started as a debug
 session. This message appears whenever I set the Length field of the
 StartData record to 50 (for maximum control), but not when I set it to
 30.

 Response:

 To avoid this problem, pass the size of the STARTDATA structure in the
 Length field. We also recommend that you use the sizeof() operator.
 The following is an example:

    StartData.Length = sizeof(STARTDATA);


 379. OS/2 SDK: Identifying .EXE File's Session Type

 Question:

 How can you identify an .EXE file's session type, as per
 DosStartSession()?

 Response:

 The session type can be obtained with the DosQAppType() function call.
 You pass DosQAppType() the .EXE filename, and DosQAppType() returns
 the executable type (i.e., windowable, nonwindowable, window API) in a
 pointer to a short.


 380. OS/2 SDK: DosStartSession() pgmTitle Parameter Information

 Question:

 There is an entry called pgmTitle in the start-area structure for the
 DosStartSession() call. What is pgmTitle used for?

 Response:

 The entry pgmTitle is the name that will be displayed in the program
 shell's task-manager switch list. You do not have to use this field,
 but it gives you the opportunity to select whatever name you want
 people to see when they are selecting a session to switch to from the
 task manager.


 381. OS/2 SDK: Definition of SessionID and/or Screen Group

 The terms "SessionID" and "Screen Group" are synonymous. They are
 defined to be one or more processes running together that share the
 keyboard, video display, and mouse.


 382. OS/2 SDK: General RAM Semaphore Information

 Question:

 I have the following questions regarding the creation of transient RAM
 semaphores in malloc()'ed space or on the stack:

 1. When I'm done using the semaphores and I want to return the
    space to the heap, is it necessary to clean up the contents, e.g.
    should I use DosSemClear() to clear the space before freeing it?

 2. When I'm creating a semaphore that I want to be initially clear,
    all I need to do is set it to 0:0. However, if I want it initially
    set, can I just set it to 0:255 [as it appears DosSemSet() does],
    or must I use the DosSemSet() call to do this?

 Response:

 The answers to your questions are as follows:

 1. Yes, you should do some sort of cleanup. This would prevent the
    possibility of a process blocking indefinitely on an abandoned
    semaphore.

 2. You should use the DosSemSet() call. This will prevent race
    conditions from occurring if two processes should ever attempt to
    modify the semaphore at the same time. If you are trying to make
    sure that the semaphore is set before anyone tries to read it, you
    should DosEnterCritSec() just before you create the semaphore, set
    it using DosSemSet(), and then use DosExitCritSec().


 383. OS/2 Returns "Not Enough Memory to Run Application" Error

 Question:

 Occasionally, OS/2 returns "not enough memory to run application"
 errors. The CMD processor then will refuse to run programs. How is
 this possible? I have SWAPPING and MOVING enabled, 2 megabytes of
 RAM, and the disk on which the swap file is placed has plenty of free
 space (approximately 5 megabytes)?

 Response:

 OS/2 will return the "not enough memory to run application" message if
 it determines that there is not enough RAM and/or disk space to allow
 the program to be loaded and run. Although 2 megabytes of RAM and 5
 megabytes of disk space are sufficient to run OS/2 and several
 applications simultaneously, it is not surprising that you would
 receive this message if you attempt to run many applications at the
 same time. Check the size of the file SWAPPER.DAT, and the amount of
 disk space at the time that you receive the error. As SWAPPER.DAT
 grows (by increasing the number of items that are swapped), the
 amount of available disk space diminishes until the operating system
 calculates that it could potentially be prevented from loading a
 segment into RAM because it does not have room on the disk to swap out
 another segment to make room.

 You can do the following two things to address this problem:

 1. Increase the amount of RAM you have [3 to 4 megabytes is a good
    amount, especially if you are doing Presentation Manager (PM)
    work].

 2. Make room on your swap disk to allow more files to be swapped.

 Getting more RAM is the best solution if you are concerned about
 speed, but making more disk space available will work just as well.


 384. OS/2 SDK: KbdCharIn() hkbd Parameters Information

 Question:

 On Page 258 of the "Microsoft Operating System/2 Programmer's Toolkit
 Programmer's Reference" for Version 1.00, under the KbdCharIn() call,
 it states that the hkbd parameter "must have been previously opened by
 using the KbdOpen function." However, the example on Page 261 passes a
 keyboard handle (third parameter) of zero. The hkbd parameter is
 ignored in real mode, but what is the meaning of a zero for that
 parameter under OS/2?

 Also, will KbdCharIn() behave this way in the future with a zero value
 for the hkbd parameter?

 Response:

 The zero (0) parameter is the default keyboard and identifies the
 physical keyboard. To access the physical keyboard, it is not
 necessary to explicitly open it. This will remain true for future
 versions of OS/2.


 385. OS/2 SDK: Protection Violation ERLIM & ERACC Field Information

 Question:

 What do the ERLIM & ERACC fields mean in the message displayed when a
 protection violation fault occurs?

 Response:

 When a fault is caused by violating the limit or access rights of a
 selector, ERRCD will contain that selector, and ERLIM and ERACC will
 contain the limit and access codes for that selector. If ERRCD does
 not contain a selector, ERLIM and ERACC will contain "**" instead.


 386. OS/2 SDK: DLL Call Gate Information

 Question:

 Does a call to a dynamic link library (DLL) go through a call gate
 mechanism? In other words, do the parameters passed to the DLL on the
 stack get transferred to a new stack?

 Response:

 A call to a DLL does not have to go through a call gate. This only
 happens when a ring transition occurs, such as when calling a ring 2
 IOPL segment function from a ring 3 code segment.


 387. INSTALL.TXT File for OS/2 SDK Version 1.06 Is Available

 The file 106READ.ARC contains the complete contents of the INSTALL.TXT
 file distributed with the Microsoft OS/2 Software Development Kit
 Version 1.06. This file can be found in the Software Library by
 searching for the filename 106READ.ARC, the Q number of this article,
 or S12165.

 The INSTALL.TXT file contains information about Version 1.06 of the
 Microsoft OS/2 Software Development Kit. The INSTALL.TXT file
 consists of the following six parts:

    Part     Title

     1       Introduction
     2       MS OS/2 SDK Components
     3       Installation Notes
     4       Miscellaneous
     5       Hardware Compatibility Caveats
     6       New SDK Owners Only


 388. Installation and General Information for OS/2 SDK 1.06

 The file INSTALL.TXT, "Microsoft Operating System/2 Software
 Development Kit Installation Notes Version 1.06," is included with the
 OS/2 Software Development Kit (SDK) Version 1.06. This file contains
 answers to many commonly asked questions about OS/2 SDK Version 1.06.
 This file is located on the Toolkit 1 disk. Please read this file
 before attempting to install OS/2 SDK Version 1.06 on your system.

 INSTALL.TXT can also be found in the Software Library by searching for
 the filename 106READ.ARC, the Q number of this article, or S12165.


 389. Dual-Boot Ability Not Supported in OS/2 SDK Version 1.06

 The dual-boot ability, included with previous releases of the OS/2
 Software Development Kit (SDK) is no longer included with the OS/2
 SDK Version 1.06. For more information on this and other changes to
 this release of the OS/2 SDK, refer to the file INSTALL.TXT,
 "Microsoft Operating System/2 Software Development Kit Installation
 Notes Version 1.06," located on the Toolkit 1 disk.

 INSTALL.TXT can also be found in the Software Library by searching for
 the filename 106READ.ARC, the Q number of this article, or S12165.


 390. OS/2 SDK Reentrancy of Multiple Copies of Program

 Question:

 Under OS/2, are multiple instances of a program running off the same
 executable file automatically reentrant? In other words, does each
 instance of an executable file get a separate data segment for static
 variables?

 Response:

 Yes. There is only one copy of the code segments in memory for each
 executable file at any one time. If the same executable file is loaded
 twice, another copy of the data segments will be made. However, if the
 application is not using any named objects, such as named pipes,
 queues, or system semaphores, and if it also does not use any of its
 own DLLs, you should not have to do anything special to run two or
 more copies.


 391. OS/2 SDK: Directly Switching to Task Manager from Application

 Question:

 Is there a way for my program to directly switch to the task manager?
 I have a text-based OS/2 application in which I would like to be able
 to switch from the text-based screen group to the Presentation Manager
 (PM) screen group by clipping the mouse on a pull-down menu item
 within the text-based OS/2 application.

 Response:

 Currently, there is no way for your program to directly switch to the
 task manager. This feature is under review and will be considered for
 inclusion in a future release.


 392. OS/2 SDK: Reason DosRead() Gets Zero Byte-Count of Bytes Read

 Question:

 We have a program that makes a named pipe, then does DosRead()s to the
 pipe and receives data from another program in another screen group.
 Sometimes the DosRead() gets a zero return value (i.e., successful
 read) but also gets zero for the byte-count of bytes read. What does
 this mean?

 Response:

 This can happen in the following cases:

 1. If the pipe is closed at the other end, reading 0 bytes means that
    the end of the file was reached.

 2. If the pipe is in message mode and the writer writes a message
    having zero bytes, the reader will get a message with zero bytes.


 393. OS/2 SDK: Using CodeView to Debug a PM Application

 Debugging a Presentation Manager (PM) application is most easily
 accomplished if you have a second monitor.

 You can also use sequential-mode debugging redirected through the COM
 port to a dumb terminal. This works well, although it is not windowed.
 It is also slower than using a second monitor.

 If neither of the options mentioned above are available to you, you
 will have to toggle back and forth between the PM screen group and the
 CVP screen group. This is the least desirable way of debugging an
 application because you can end up in situations where you can't
 switch screen groups because of a hang or a loss of keyboard focus.
 You will have to reboot your computer to recover from either of these
 situations.


 394. OS/2 SDK: Device-Driver-Defined Error Statuses

 Question:

 Can you provide me with information concerning device-driver-defined
 error statuses (return statuses with bit 14 set)? I would like to know
 how to use this feature and what limitations exist.

 Response:

 In case of an error, a device driver would set bit 15 and specify the
 error code in bits 0-7. The error code is processed by OS/2 in one of
 the following ways:

 1. If the IOCtl category is system defined, FF00H is ORed with the
    error code specified in bits 0-7.

 2. If the IOCtl category is user defined, FE00H is ORed with the error
    code specified in bits 0-7.

 3. The error code must be one that is system defined (as defined on
    Page 81 of the "Microsoft Operating System/2 Device Drivers Guide")
    and is mapped into one of the standard OS/2 API return codes.


 395. OS/2 SDK: Use of DevHelps Character Queue Management Functions

 Question:

 I need to use a pair of the Character Queue Management functions
 provided with the DevHelps in a way that raises the question whether
 they will work concurrently from the kernel and interrupt states.
 Specifically, I want to enqueue items in the kernel state, and dequeue
 them from the same queue in the interrupt state (and vice versa).

 Do I need to protect the kernel state DevHelps call by bracketing it
 with CLI/STI, or are these functions designed to be re-enterable in
 situations such as the one described above?

 Response:

 These calls can be used to do what is described above; however, you do
 need to bracket them by disabling interrupts if you are calling them
 at task time (kernel state).


 396. Accessing ROM Area During Initialization of Device Driver

 I am writing an OS/2 device driver for a hard disk. I need to access
 the ROM on my adapter board during initialization. I used the DevHelp
 functions AllocateGDTSelector() and PhysToGDTSelector() to obtain
 access to this ROM. However, when I try to access it using the
 selector given to me, I get a general protection (GP) fault. The GP
 fault occurs because the DPL = 0 for the selector. If I change the DPL
 to 3 or execute the same code during Strategy time, the code works
 properly. Is there a better way to change the IOPL of the selector (I
 modified memory to do it), or is there some other way to read the ROM
 space during Init time?

 Response:

 You would typically use PhysToVirt() during Init time to gain
 accessibility to the ROM area because it gives you temporary
 addressability to the data area that you need during Init time.

 You can still use PhysToGDTSelector() to allocate a GDT selector;
 however, this means that the GDT selector is permanently allocated,
 even after Init time. This may or may not be desired.


 397. OS/2 SDK: Using Floating Point Math Libraries in DLLs and EXEs

 Question:

 1. Is it possible to use the Emulator library in a DLL (Dynamic Link
    Library)? Single threaded? Multithreaded? If not, why?

 2. Can I use the emulator library in a regular OS/2 .EXE file?

 3. What options can I choose from when doing floating point operations
    in DLL and .EXE files?

 Response:

 1. The single-threaded DLL support library LLIBCDLL.LIB does not use
    emulator math; it uses only the alternate math library. The
    multithreaded DLL support library CRTLIB does use emulator math.
    Technically, it is not possible to use the emulator library in any
    DLL because you can link only to the appropriate library (LLIBCDLL
    or CRTLIB + DOSCALLS).

    This relates only to what the dynamically linked libraries will use
    themselves and is independent of what the calling program is doing.
    For example, you can have a program that uses an emulator math call
    into the single-threaded DLL. The same holds true for the
    multithreaded DLL support library; you can call into the library
    from an application using any floating point option.

 2. Yes, you can use the emulator library in a regular OS/2 .EXE file.

 3. There are no restrictions on which floating point option you can
    use when calling into the multithreaded dynamic link support
    library, CRTLIB or the single-threaded DLL support library. When
    creating dynamic link libraries, you can only link to the
    appropriate library that will provide either alternate (within
    LLIBCDLL) or emulator (within CRTLIB) math support within the
    dynamic link library.


 398. OS/2 SDK: How to Catch Protection Faults

 Question:

 Is there any way to catch protection faults using DosSetVec() and
 DosError()?

 Response:

 DosError() and DosSetVec() will not allow you to catch protection
 faults. To catch protection faults in an application, it is necessary
 to use the DosExecPgm() function to start up the application as a
 child with the fExecFlags parameter set to EXEC_TRACE. You then can
 use the DosPTrace() function to retrieve information about the child
 processes, including whether a general protection fault occurred.
 DosPTrace() is documented on Pages 171-175 of the "Microsoft Operating
 System/2 Programmer's Toolkit Programmer's Reference" manual for
 Version 1.00.


 399. OS/2 SDK: Return Line Control Register Documentation Error

 The section on Function 62H: Return Line Control Register on Page 140
 of the "Microsoft Operating System/2 Device Drivers Guide" is no
 longer up to date. The "Microsoft Operating System/2 Programmer's
 Toolkit Programmer's Reference" for Version 1.00 does contain the
 correct documentation for reading and writing to the Return Line
 Control Register; Pages 484 (SETLINCTRL) and 420 (GETLINECTRL)
 document the calls and the structures they use. These are the calls
 you should use.


 400. OS/2 SDK: General Environment Block Information

 Question:

 1. Is it possible for a child process to read the environment block of
    its parent? In other words, is the parent's environment block
    shareable?

 2. There is a DosGetEnv() OS/2 function, but no companion DosPutEnv()
    function. Is it correct to assume that the maintenance of the
    environment block is completely up to each program?

 Response:

 1. The parent's environment block is in memory private to the parent;
    the child process cannot access it directly.

 2. Yes, the maintenance of the environment block is completely up to
    each program. You can substitute the C run-time function putenv as
    a replacement for DosPutEnv().


 401. OS/2 SDK: Changing Current Drive & Directory in a Command File

 Problem:

 I have a program that parses the path and changes both the drive and
 directory. It works correctly under MS-DOS and in the compatibility
 box, but does not work in protected mode. In protected mode, the
 current drive and directory revert to the previous values at the
 completion of the program.

 Response:

 The reason your program does not work in protected mode is that the
 current drive and drive path assignments are on a per-process basis in
 protected mode. When you call the program to change the drive name and
 pathname, this creates a new process. When the process ends, the drive
 and path for the calling process have not changed.


 402. OS/2 SDK: #include Files Contain Bitwise Inclusive OR Operator

 Problem:

 The OS/2 Software Development Kit (SDK) Version 1.05 release contains
 #include files that use preprocessor directives of the following form:

 #if  ( defined( A ) | !defined( B ) )
 .
 .
 .
 #endif

 I think that the following was intended:

 #if  ( defined( A ) || !defined( B ) )
 .
 .
 .
 #endif

 It appears that the implementor intended to use the logical-OR (||)
 operator, but instead used the bitwise-inclusive-OR (|) operator.

 This is a nuisance when using syntax-checking utilities such as
 PC-lint for OS/2 by Gimpel Software. It correctly flags the suspicious
 usage of the bitwise operator, and the files need to be patched by
 hand each time they are updated by a new release of the OS/2 SDK.

 Response:

 Microsoft has confirmed this to be a problem in the OS/2 SDK Version
 1.05. We are researching this problem and will post new information as
 it becomes available.


 403. Characters-Per-Line Value for Set Frame Control Command

 Question:

 The parameters 80 and 132 are allowed in the characters-per-line value
 for the Set Frame Control command (function 42H) of the Printer
 Control IOCTL commands. If 132 is indicated, it outputs the control
 code for reduced characters, and it allows you to print more than 132
 characters in one line. Is this by design?

 Response:

 No, this is not by design. The only required characters-per-line
 values are 80 and 132. The printer may support many more values.
 The decision to use reduced characters is made by the device driver
 itself. It does not have to be this way, but the particular printer
 device driver you have installed does it that way. The IOCTL does not
 control the printer; it only calls the device driver.


 404. OS/2 SDK: Displaying Fonts at an Angle

 Question:

 Is it possible to use "simple" fonts on an angle? I would like to be
 able to display a sans-serif font on an angle, rather than displaying
 a serif font. The serif font looks somewhat "mushy" and is difficult
 to read when you reduce the size by 25 percent.

 I understand that only vector fonts can be displayed at angles.
 Ideally, I would like to use a font similar to type 6 in the OS/2
 Software Development Kit (SDK) sample program named FontTest. It looks
 like the system font with a height of 8 and width of 4.

 Response:

 You are correct; currently, only vector fonts can be displayed at
 angles. We are evaluating various ways to provide future support for
 angling bitmap fonts; however, there is no schedule yet for when or if
 this support will be implemented.

 The font you mentioned (#6 from FontTest) is "Helvetica proportional,"
 and it is a bitmap font; thus, it cannot be rotated. There are two
 sans-serif vector fonts in the Version 1.05 OS/2 SDK, and the Version
 1.06 OS/2 SDK also has some different fonts. There is a Helvetica
 Proportional font and a Sans Proportional font. However, neither of
 these fonts looks good at a size much smaller then 32, and rotating
 them doesn't help any. Also, the vector fonts will be noticeably
 slower to draw. Depending on your exact needs, you might want to just
 use the raster fonts, specify the rotation using mode 2, and let the
 character placement be rotated, without actually rotating each
 individual letter.


 405. OS/2 SDK: .EXE File Header Information

 Question:

 What are the meanings of the bytes at locations 0x88, 0x89, and 0x8D
 in an OS/2 program's executable file? I noticed that when I take the
 "WINDOWAPI" statement out of the module definition file, these values
 change upon relinking.

 Response:

 The bytes at those locations are the least significant portion of a
 long that is a CRC sum of the whole file. The word after the CRC sum
 is a flag that contains three bits that are set depending on the type
 of the executable. The MARKEXE program modifies this word, but does
 not bother to update the CRC. This is probably due to the fact that
 neither the DOS nor the OS/2 loader checks this CRC value.

 This information is included in the include file NEWEXE.H that comes
 with the OS/2 Software Development Kit (SDK).


 406. OS/2 SDK: DosOpen() Error Return Values Information

 Question:

 I have the following questions concerning DosOpen() error return
 values:

 1. Attempting to use DosOpen() to open a nonexistent file with
    fOpenFlags=1 returns the error of ERROR_OPEN_FAILED rather than
    ERROR_FILE_NOT_FOUND. Is this intentional?

 2. DosOpen() returns the error of ERROR_INVALID_DRIVE, which is not
    mentioned in the "Microsoft Operating System/2 Programmer's
    Toolkit Programmer's Reference" manual for Version 1.00.

 Response:

 1. Yes, this is expected behavior. ERROR_OPEN_FAILED will be generated
    if you attempt to do an explicit open on a file that does not
    exist. If you want to open a file and create it if it does not
    exist, you should use fOpenFlags of 0x0010.

    ERROR_FILE_NOT_FOUND will be generated if you pass an invalid
    filename to DosOpen(); for example, attempting to open ".xyz" will
    generate this error.

 2. You are correct; this error is not documented under DosOpen(). We
    plan to document this error in a future release of the
    documentation.


 407. Parent Is Blocked if Child Issues MouReadEventQueue() Call

 Question:

 I have a child process that has been started up with DosExecPgm()
 asynchronously. When the child process issues a MouReadEventQueue()
 function call, the parent process is stopped if it executes any MOU
 API function calls. Why is this happening?

 Response:

 The mouse subsystem has a per-screen group semaphore that controls
 access to the mouse from the different threads and processes in each
 screen group. When the child process executes a blocking
 MouReadEventQueue(), it takes possession of this semaphore and will not
 release it until the call completes. When the first process tries to
 do any MOU API calls that require this semaphore, it will block until
 the semaphore is freed. This is by design and is not a bug.

 If your application design requires you to have more than one thread
 doing MouXXX calls in the same screen group, you will need to use one
 of the following workarounds:

 1. Probably the best solution is to do your own drawing of the mouse
    pointer. This is not very difficult to do, and this way you can do
    your own removing and showing of the pointer.

 2. To bypass the mouse subsystem semaphore, do direct ioctls to the
    mouse device driver to hide and show the mouse pointer. Most of the
    high-level MOU API calls have similar DosDevIOCtl() function codes
    that can be used instead.

 3. You could set up a flag or a semaphore and have the child process
    not block during the mouse read. You have to be careful of this,
    however, because you don't want to consume a lot of CPU resources
    just doing polling of the mouse. You would want to be sure that you
    do a DosSleep() call within the loop so that you give other
    processes a chance to run.

 Note that this problem does not occur in the Presentation Manager,
 because the system handles the mouse and keyboard messages coming into
 the system.


 408. QuickHelp 1.06 IBM PS/2 Model 80-071 ENTER Key Problem

 Problem:

 While using QuickHelp, the ENTER key on the numeric keypad of my IBM
 PS/2 model 80-071 seems to be ignored. The ENTER key on the main
 keyboard works correctly.

 Response:

 Microsoft has confirmed this to be a problem with the QuickHelp
 included with the OS/2 Software Development Kit (SDK) Version 1.06. We
 are researching this problem and will post new information as it
 becomes available.


 409. OS/2 SDK QuickHelp 1.06 OVERVIEW.HLP Problems

 Problem:

 The QH.DATABASE entry states that OVERVIEW.HLP contains "descriptions
 of CMD.EXE commands." I cannot find these descriptions.

 Also, after paging through the OVERVIEW.HLP file, I noticed that the
 last screen displayed was not text, but instead included garbage
 characters.

 Response:

 Microsoft has confirmed both of these anomalies to be a problem with
 the QuickHelp shipped with the OS/2 SDK (Software Development Kit)
 Version 1.06. We are researching these problems and will post new
 information as it becomes available.


 410. WHERE and KBDP Are Not Listed in OS/2 SDK QuickHelp 1.06

 Question:

 When using QuickHelp, is there a way to list all the entries in a
 database or section? For example, is there a way to list all the C
 function calls or all the utilities (such as WHERE.EXE and KBDP.EXE)?

 Response:

 Other than paging through the database, there is no way to see every
 help entry.

 The entries for WHERE.EXE and KBDP.EXE used to be in the categories
 list for tools in previous versions of QuickHelp. Microsoft has
 confirmed that these utilities are not listed for tools in the
 QuickHelp shipped with the Version 1.06 OS/2 Software Development Kit
 (SDK). We are researching this problem and will post new information
 as it becomes available.


 411. When to Use Preserve Start-up Option in Installation Program

 Question:

 I specified the option to preserve the start-up information that
 previously existed during the installation procedure; however, when I
 rebooted OS/2, the Start Programs window was empty. Why wasn't the
 information preserved?

 Response:

 The preserve start-up option should only be used if you are going from
 IBM Version 1.00 to Version 1.10. If you have installed any of the
 intermediate releases of Version 1.10 (OS/2 SDK Version 1.03 or 1.05),
 your Start Programs window will be empty. You will need to reinstall
 the OS/2 SDK and choose not to save previous installation information.


 412. Wrong Topic Displayed in OS/2 SDK Version 1.06 QuickHelp

 Problem:

 Sometimes while using QuickHelp, the wrong topic is displayed. For
 example, I am unable to view the documentation for the Microsoft
 Editor "Window" topic, because it always brings up the information for
 the RC.EXE WINDOW command instead.

 Response:

 Microsoft has confirmed this to be a problem with the QuickHelp
 included with the OS/2 Software Development Kit (SDK) Version 1.06. We
 are researching this problem and will post new information as it
 becomes available.


 413. How to Stop QuickHelp from Exiting after Paste Is Executed

 Question:

 When the Paste option is executed, QuickHelp exits instead of
 remaining in the topic. This means that you have to keep going back
 into QuickHelp and selecting topics each time you do a Paste. Is there
 a way to prevent QuickHelp from exiting after the Paste option is
 executed?

 Response:

 Yes; there is both a command-line option and a menu option that will
 allow you to do this. If you start QuickHelp with "qh -pa [filename]",
 QuickHelp will not exit after executing the Paste option. You must
 press "X" to exit. The filename is optional, and specifies where to
 send the Paste data.

 If you use the Append Paste File option, all Paste operations will be
 copied to the end of the file instead of overwriting the file. When
 the Append option is chosen, QuickHelp does not automatically exit
 after a Paste command.


 414. OS/2 SDK: PRINT Commands /C and /B Option Documentation Errors

 Question:

 I have the following questions regarding the PRINT command:

 1. The "SYS 1526" error message states that you should use "PRINT /C";
    however, the "Microsoft Operating System/2 User's Reference" manual
    for Version 1.00 states on Pages 175-176 that you should use "PRINT
    filename /C". Which syntax is correct?

 2. The error message "SYS 1525" indicates that a /B option is
    available; however, this option is not documented in the "Microsoft
    Operating System/2 User's Reference" manual for Version 1.00. What
    is this option used for?

 Response:

 1. The documentation on Pages 175-176 of the "Microsoft Operating
    System/2 User's Reference" manual for Version 1.00 is incorrect.
    The correct syntax is "PRINT /C". This problem will be corrected in
    a future release of the documentation. We will post new information
    as it becomes available.

 2. The /B option tells the spooler to read the first CTRL+Z character
    in the file as an EOF character. The EOF character is not printed.

 The following are the proper syntaxes that can be used with the PRINT
 command:

    PRINT /C [/D:device]
    PRINT /T [/D:device]
    PRINT pathname... [/D:device] [/B]

 Options /B, /C, /T, and /D: are the only options the system accepts.


 415. OS/2 SDK: Various Ways to Detect Redirected Input

 Problem:

 I am trying to detect a single keystroke from the keyboard under OS/2
 in my C program; however, I need the code to be capable of being
 redirectable to the COM port. Attempting to use DOSREADASYNC on the
 STDIN handle 0 does not set "key read" until the ENTER key has been
 pressed on the main keyboard. However, redirecting it through the COM
 port works as I expect it to.

 Response:

 We have the following suggestions on various ways to accomplish this:

 1. This is what we consider to be the best suggestion: there is a
    DosQHandType() function that will tell you whether a handle is a
    file, a device, or a pipe. When using stdin, whether keyboard or
    COM, it returns as a device. Along with the device return is a
    device attribute word. This is unique (not necessarily, but for the
    purpose of comparing the keyboard or COM1:, it is). By using the
    device attribute word and DosQHandType(), you can then tell when
    your I/O is redirected and to what (approximately).

    The bits you would probably be interested in would be 0 and 1
    (stdin/stdout bits), bit 6 (generic IOCtl control), and bits 11 and
    12 (open/close bit and shared bit). You can get descriptions of all
    the fields from the "IBM Operating System/2 Version 1.10 Technical
    Reference" or the "Microsoft Operating System/2 Device Drivers
    Guide."

    This requires separate code, but it relieves you of the additional
    command switch(es).

 2. You could create a detached process that monitors the COM port and
    does one of the following two things:

    a. The detached process communicates with the parent through a pipe
       or queue. This would allow you to identify the source of the
       input, but it requires disjointed code.

    b. The detached process is a monitor that reads the COM port and
       stuffs the keyboard buffer. This will allow you to use the same
       code for reading from stdin, but it might not work as well as
       the above idea.

 3. Use a command-line switch that identifies that input/output has
    been redirected to another device/file. This isn't as eloquent, but
    at least you will know what is going on and which sequence of code
    to execute.


 416. OS/2 SDK: EMS Drivers for DOS Compatibility Mode

 The release of OS/2 provided with the Microsoft OS/2 Software
 Development Kit (SDK) does not provide a device driver for using
 LIM/EMS memory in the DOS compatibility mode. There normally are two
 kinds of EMMs (expanded memory managers): ones that use actual
 expanded memory and ones that use extended memory to emulate expanded
 memory.

 One form of EMM directly manipulates extended memory and simulates
 expanded memory. This form of EMM cannot be used in OS/2 because the
 driver must perform absolute memory manipulations, which OS/2 does not
 allow, for security reasons. Instead, an OS/2 device driver (an OS/2
 version of an EMM) must be written to control this EMS memory and to
 make it available to applications.

 The other form of EMM, which works with true expanded-memory hardware,
 is not using memory that is addressable by OS/2, because OS/2 only
 understands conventional and extended memory. Since OS/2 doesn't use
 this memory, it is theoretically possible for an EMM written as a DOS
 device driver to be loaded and to work in the OS/2 DOS compatibility
 mode. Contact your EMS board manufacturer for the availability of a
 driver that will meet this and the other requirements of being able to
 be run under OS/2.


 417. OS/2 SDK Disk/Documentation Updates/Replacements

 If you need any changes, replacements, or updates to disks, or if you
 have documentation requests for the OS/2 Software Development Kit
 (SDK) -- for example, if you receive disks in the wrong media size --
 please call the toll-free number provided for Microsoft OS/2 SDK
 owners. The phone number is (800) 227-4679. The people at this number
 can verify that you are properly set up to receive the latest OS/2 SDK
 disks in the proper media size, and that you have the latest OS/2 SDK
 release.


 418. Using SCSI Drives with OS/2

 Question:

 I would like to use OS/2 on a system with a SCSI disk controller. Is
 this possible? If so, how?

 Response:

 Yes, it is possible to use a SCSI drive with OS/2. However, it
 requires an OS/2 disk device driver that supports a SCSI drive. The
 Microsoft OS/2 SDK release of OS/2 does not come with such a driver.
 You must contact your system hardware OEM (or a third party SCSI drive
 hardware OEM) to obtain such a device driver to support your drive.


 419. OS/2 SDK: No Transparent Method to Take Back Giveable Memory

 Question:

 I would like to allocate a portion of giveable memory, give it to a
 process, let another process use it, and then take it back without the
 other process knowing that it was shared memory. I know that such an
 OS/2 memory API doesn't exist, but my question is the following: is
 there some function that will allow me to take back a segment I gave
 away and free it?

 Response:

 OS/2 does not have such an API, since an application that gives a
 segment of memory has no way of telling when the recipient of the
 memory is finished with it. Thus, an application cannot tell when it
 would be safe to take back this segment of memory.

 The normal situation in which shared segments are used between two
 applications (in this case "app1" and "app2") is as follows:

     app1: DosAllocSeg(giveable)     lock count = 1
     app1: DosGiveSeg(app2)          lock count = 2
     ... (apps use segment)
     app2: DosFreeSeg()              lock count = 1
     app1: DosFreeSeg()              lock count = 0

 The order in which app1 and app2 call DosFreeSeg() does not matter: in
 either case, both must call this API in order for the lock count to
 come down to 0. In this case, app1 is taking on more of the duties by
 calling DosGiveSeg(app2), which is in essence a DosAllocSeg() done in
 the guise of app2. Thus, app1 must allocate the segment for itself,
 allocate it for app2, and free it once. The other application, app2,
 must only free it once.

 The following is another situation in which shared memory services can
 be used:

     app1: DosAllocSeg(gettable)     lock count = 1
     app2: DosGetSeg()               lock count = 2
     ... (apps use segment)
     app2: DosFreeSeg()              lock count = 1
     app1: DosFreeSeg()              lock count = 0

 In this scenario, application app1 creates the segment, but this time
 with the gettable bits set. (This is in contrast with the previous
 method, in which the DosAllocSeg() call by app1 was with the giveable
 bits set.) Application app2 must call DosGetSeg() to obtain
 accessibility of the segment. (This is in contrast to the previous
 method, in which app2 didn't need to worry about GETting the segment,
 since it was GIVEn to him or her.) Then, after both apps are done,
 they can free their lock counts to the segment. In this case, just as
 in the first method, BOTH applications must call DosFreeSeg(), to
 decrement the lock counts to 0.

 The reason that there is no such DosTakeSeg() is that app1 generally
 would not have the information to tell it that app2 is done with a
 segment. Also, as stated earlier, this was part of the OS/2 design
 theory in the memory management area. For this reason, both
 applications must call DosFreeSeg(), and can't rely on anything else
 to do it.

 It is possible to implement an abstract API to take back memory using
 some method of interprocess communication and knowledge between the
 applications involved. However, this still requires that both
 applications fundamentally call DosFreeSeg().


 420. OS/2 SDK 1.06 Hangs with Error R6003, Divide By Zero

 On some systems, the OS/2 Software Development Kit (SDK) Version 1.06
 hangs with a run-time error R6003, divide by zero. This is caused by a
 video portion of OS/2 not recognizing the system's video adapter. OS/2
 does not understand how to work with this video card. To work around
 this problem, try using a more standard EGA or VGA card and/or
 adapter.

 Note that this boot error can sometimes be confused by the COM and
 MOUSE drivers. To eliminate this possibility, remove these drivers
 from the CONFIG.SYS file. This will help isolate the problem to the
 video system and will remove the possibility of mouse or serial
 hardware incompatibilities.

 Other possible temporary workarounds are described in the OS/2 SDK
 Version 1.05 installation notes document. See Section 4 of this
 document, which describes two alternative shells that are available
 with this release of OS/2 (i.e., two possible methods that you can try
 to get your system up and running). These shells are not available or
 supported in OS/2 SDK Version 1.06 or later, but are contained on
 older releases of the OS/2 SDK and may help you until another video
 card or adapter can be found.


 421. OS/2 SDK: Using Debugging Modules & Second Monochrome Monitor

 Problem:

 I am trying to use the debugging modules that come with the Version
 1.06 OS/2 Software Development Kit (SDK) with a VGA and a monochrome
 monitor. I have copied all three .DLL modules into \OS2\DLL and I have
 copied PMDD.SYS into \OS2. I also added the /2 switch to the
 DEVICE=C:\OS2\PMDD.SYS line in CONFIG.SYS.

 When Presentation Manager (PM) comes up, it displays a message at the
 bottom of the screen indicating that the debugging version has been
 installed; however, no output ever goes to the monochrome monitor.

 Response:

 The documentation in both the INSTALL.DOC and INSTALL.TXT files is in
 error regarding the switch to use for the second monochrome monitor.
 In Section 4.5.2, the documentation incorrectly states that you should
 use the /2 switch. The correct switch to use is /m.


 422. OS/2 SDK: DosPeekQueue() Documentation Errors

 Below is information on the documentation errors for the
 DosPeekQueue() function call in the "Microsoft Operating System/2
 Programmer's Toolkit Programmer's Reference" for Version 1.00.

 Page 165 of the "Microsoft Operating System/2 Programmer's Toolkit
 Programmer's Reference" for Version 1.00 incorrectly states the
 following:

    PULONG pulDataAddr;        address of element received

    It copies the element to the buffer pointed to by the pulDataAddr
    parameter

 Instead, it should state the following:

    PULONG pulDataAddr;        Address of pointer that points to
                               element read

    It sets the indicated buffer pointer to the address of the queue
    data.

 Page 166 of the "Microsoft Operating System/2 Programmer's Toolkit
 Programmer's Reference" for Version 1.00 incorrectly states the
 following:

    If the function waits, the function clears the semaphore identified
    by the hsem parameter as soon as the element is retrieved.

    pulDataAddr          Points to the buffer that receives the
                         element being retrieved from the queue

 Instead, it should state the following:

    If fNoWait is DCWW_WAIT and there is no element available,
    DosPeekQueue() will return immediately without retrieving an
    element from the queue, and the semaphore identified by the hsem
    parameter will be asynchronously cleared as soon as an element is
    written to the queue.

    pulDataAddr          Address of pointer to be set to point to the
                         queue element read


 423. Version 1.06 OS/2 SDK Case Changes in Certain API Calls

 The case of some characters in the following API calls in the BSEDOS.H
 header file included with the Version 1.06 OS/2 Software Development
 Kit (SDK) has changed. The following is a list of the old and new
 naming conventions:

 Old      New

 DosCWait DosCwait
 DosChdir DosChDir
 DosMkdir DosMkDir
 DosRmdir DosRmDir
 DosChdir DosChDir

 The version of QuickHelp included with the Version 1.06 OS/2 SDK still
 contains the old naming conventions for these API calls.

 The API names were changed for these API calls in the Version 1.06
 OS/2 SDK. QuickHelp has not yet been updated with this new information
 regarding these name changes. The other information still applies. We
 will post new information when a new release of QuickHelp is released
 that corrects this problem.

 You should also make sure you replace your old DOSCALLS.LIB or OS2.LIB
 files with the new ones from the Toolkit. If you use the old library
 with the new header files or the new library with the old header
 files, you will get unresolved externals when you try to link your
 program.


 424. OS/2 SDK: QuickHelp DosQFileInfo() Documentation Error

 Question:

 The documentation in QuickHelp included with the Version 1.06 OS/2
 Software Development Kit (SDK) regarding the DosQFileInfo() API call
 does not match the header files included with the Version 1.06 OS/2
 SDK. Listed below is the QuickHelp syntax from the QuickHelp files
 dated 1/6/89 and the function prototype from the BSEDOS.H header file
 with the same date.

 The QuickHelp syntax is as follows:

 USHORT DosQFileInfo(hf, usInfoLevel, pfstsInfo, cbInfoBuf)
 HFILE hf;                 /* file handle                 */
 USHORT usInfoLevel;       /* file data required          */
 PFILESTATUS pfstsInfo;    /* pointer to file-data buffer */
 USHORT cbInfoBuf;         /* length of file-data buffer  */

 The BSEDOS.H function prototype is as follows:

 USHORT APIENTRY DosQFileInfo(HFILE, USHORT, PBYTE, USHORT);

 In QuickHelp, the third parameter is declared to be a PFILESTATUS
 type; however, in the include file BSEDOS.H it is defined to be a
 PBYTE type. Which is correct?

 Response:

 This is an error in the include file. The correct syntax for this
 function is in QuickHelp.

 The third parameter of DosQFileInfo() will be changed to be a
 PFILESTATUS type for the include files that will be provided with the
 next version of the OS/2 SDK.


 425. OS/2 SDK: Piping stdout/stderr to Parent from Grandchild

 Problem:

 I'm trying to write an OS/2 utility similar to the ERROUT utility
 supplied with Microsoft C Version 5.10. I would like my utility to
 capture the stdout and stderr of all its children using a pipe and
 write that output to both the screen and a file. I'm creating an
 anonymous pipe and DUPing its write handle into both stdout and
 stderr.

 Response:

 A sample program that demonstrates a method of using anonymous pipes
 to get the stdout and stderr from both child and grandchild processes
 is located in the Software Library. This file can be found by
 searching on the filename INHERIT.ARC, the Q number of this article,
 or S12187.

 You will need to use the PKXARC utility to unarc the file INHERIT.ARC.
 INHERIT.ARC contains INHERIT.C. INHERIT.C demonstrates the use of
 DosMakePipe(), DosDupHandle(), and DosExecPgm() to accomplish the
 redirection of stderr and stdout handles.


 426. OS/2 SDK: EGA.SYS Doesn't Load When PROTECTONLY=YES

 Question:

 Why doesn't the device driver EGA.SYS load properly when PROTECTONLY
 is set to YES in CONFIG.SYS?

 Response:

 The device driver EGA.SYS is a MS-DOS-style device driver, and should
 only be loaded when the DOS compatibility mode of OS/2 is enabled.
 When this mode is enabled (PROTECTONLY=NO), this driver can be loaded
 properly. However, if the system is configured so that there is no
 real-mode emulation of MS-DOS (PROTECTONLY=YES), this driver (and any
 other MS-DOS-style device driver) will be rejected by the operating
 system.


 427. KbdXlate() Function in QuickHelp Gives Structure Information

 Problem:

 If I start QuickHelp, go into the Kbd category, and select KbdXlate(),
 QuickHelp transfers me into the structures category and the _KBDXLATE
 topic.

 Response:

 This is a circular reference problem in the QuickHelp database.
 Microsoft has confirmed this to be a problem in the QuickHelp included
 with the OS/2 SDK Version 1.06. We are researching this problem and
 will post new information as it becomes available.

 The following is the entry for KbdXlate() as it should have appeared
 in QuickHelp:

 #define INCL_KBD

 USHORT KbdXlate(pkbxlKeyStroke, hkbd)
 PKBDXLATE pkbxlKeyStroke;    /* pointer to structure for scan code */
 HKBD hkbd;                   /* keyboard handle                    */

 The KbdXlate() function translates a scan code and its shift states
 into a character value. The function uses the current translation
 table of the specified logical keyboard.

 In order to be translated, accent-key combinations, double-byte
 characters, and extended ASCII characters may require several calls to
 the KbdXlate() function.

 Parameters      Description
 -----------------------------------------------------------------------
 pkbxlKeyStroke  Points to the KBDTRANS structure that contains the scan
                 code to translate. It also receives the character value
                 when the function returns.

 hkbd            Identifies the logical keyboard. The handle must have
                 been created previously by using the KbdOpen() function.

 Return Value

 The return value is zero if the function is successful. Otherwise, it
 is an error value.

 See Also

 DosMonReg, KbdOpen, KbdSetCustXt, _KBDTRANS


 428. Redirecting Printer Output to COM2: under PM

 Problem:

 We are having problems redirecting printer output to COM2: under
 Presentation Manager (PM). We set up the printer PRINTER1 to print to
 COM2: using the Control Panel.

 Within a windowed command prompt, we successfully redirected output to
 COM2:. However, we cannot print using the print command. OS/2 always
 tries to print to LPT1: and then returns a "printer out of paper"
 error. Using SPOOL to redirect output to COM2: does not work either.

 Response:

 The PRINT command will always try to send output to the LPT1: device
 unless you use the /D:device parameter to specify another device, but
 even then, the only valid devices are LPT1:, LPT2:, or LPT3:. The
 SPOOL command has the options of /D:lpt1 and /O:com2, which should
 normally work; however, these features do not work in Version 1.06 of
 the OS/2 SDK. Microsoft has confirmed this to be a problem in Version
 1.06 of the OS/2 SDK. We are researching this problem and will post
 new information as it becomes available.

 For now, you must either use a parallel printer or print directly to
 COM2: with the "COPY file COM2" command.


 429. Sharing Interrupt with Multiple COM Ports in Device Driver

 Question:

 I am writing a COM driver that supports three COM ports and shares an
 interrupt for two of the COM ports. How does UnSetIRQ() know which of
 the ports sharing an interrupt to unset? Is the DS the deciding
 factor?

 Response:

 There is no way for UnSetIRQ() to know which COM port to unset if you
 are managing three COM ports under one interrupt. Also, UnSetIRQ() has
 no knowledge of ports; it only affects the IRQInfoTable and the 8259
 mask register. UnSetIRQ() will completely remove the interrupt
 handler, thereby affecting all devices under it. It's up to your code
 in the device driver to determine which COM port needs to be closed.
 In general, you must provide all the individual COM port control (such
 as open, close, read, write, buffering, etc.). There are no OS/2
 function calls available to help you manipulate the COM hardware.
 Using UnSetIRQ() to close one COM port will actually affect them all.


 430. OS/2 SDK: DosRead() Being Blocked on Read to Empty Pipe

 Question:

 I am trying to use a pipe to pass information between two threads. I
 am having problems with DosRead(). When the pipe is empty and I do a
 DosRead(), the process hangs. Because CodeView is hung at this point, I
 can't tell whether my DosRead() has been blocked or whether something
 else has happened.

 If the pipe is empty, will DosRead() return with 0 bytes read, or will
 DosRead() block the thread until the requested data is written into
 the pipe?

 Response:

 If the pipe is empty, DosRead() will block the thread until the
 requested data is written into the pipe. The DosRead() blocking
 behavior is to be expected with anonymous pipes. It is like any other
 stream I/O and therefore waits for the data rather than returning 0
 bytes read.

 There is a file in the Software Library named RDNMPIPE.ARC that
 includes documentation for the various named pipe function calls.
 RDNMPIPE.ARC can be found in the Software Library by searching for the
 filename, the Q number of this article, or S12189. RDNMPIPE.ARC has
 been archived with the PKARC utility. You will need to unarchive it
 with PKXARC. A copy of PKXARC can be found on the Microsoft OnLine
 Utilities Disk 2.


 431. OS/2 SDK: DosError() Critical Error Handler

 Question:

 Is there a FAPI equivalent to the DOS critical error handler INT 24 so
 that critical errors can be intercepted in OS/2?

 Response:

 Yes; the FAPI call DosError() can be used to suppress the hard error
 pop-up window message. This is just like saying to OS/2 that all hard
 errors are to be treated as if the user had selected "Fail" from the
 pop-up.

 If a process disables hard-error processing with DosError(), it does
 so for all forms of I/O errors. You can also disable hard-error
 processing for a specific file or device by setting special bits in
 the DosOpen() call for the device or file.

 DosError() allows the suppression of pop-up messages that result from
 CPU faults, such as GP faults; however, the application will still be
 terminated when a CPU fault occurs.

 If you use DosError() to suppress the pop-up message, your application
 will terminate unless you have set up a handler using the DosSetVec()
 call.

 For MS-DOS, passing a 0 to DosError() causes the system critical error
 handler to return a "Fail" code until DosError() is called again with
 an argument of 1.

 FAPI calls that are related to DosError() that you should look at to
 see how you want to handle your critical errors include DosErrClass(),
 DosOpen(), DosSetFHandState(), and DosSetVec().

 The "OS/2 Programmer's Guide" by Ed Iacobucci (Osborne McGraw-Hill)
 also contains some useful information on this topic.


 432. OS/2 SDK: DosStartSession() Error Return Code 457

 Question:

 I sometimes get an error return code of 457 when calling the
 DosStartSession() function call. What does this error mean?

 Response:

 This error is defined in the include file BSEERR.H to be
 ERROR_SMG_START_IN_BACKGROUND. This error occurs when
 DosStartSession() is called with the flag set to indicate that the
 started session should be started in the foreground, and the calling
 session is NOT in the foreground itself. This can happen when the user
 screen switches away from the session before the call to
 DosStartSession() or if the session has been switched away from
 because a VioPopUp() is in progress.

 Depending on what your application is trying to do, a possible
 workaround would be to change the flag to specify that the session
 should be started in the background and retry the call. Also note that
 foreground and background in the context of DosStartSession() does NOT
 mean that the process should be run detached or not detached. When you
 specify that a session should be started in the background mode, it
 simply means that it is started, but not immediately screen switched
 to.


 433. R2_to FM_ Constants (GpiSetMix) Translation Not Defined In QH

 In the QuickHelp section of Windows Equivalents, under SetROP2, it
 says to see the help on the R2_ constants to see how they map to the
 new FM_ constants to be used with GpiSetMix(). This translation of the
 R2_ values to the FM_values is not included in the Version 1.06 OS/2
 Software Development Kit (SDK) release of QuickHelp.

 The best way to make this conversion would be to look at the names
 given to the various ROP2 codes in WINDOWS.H and you should be able to
 convert the actions of those values to the appropriate FM_ values
 defined in PMGPI.H.

 Microsoft has confirmed this to be a problem in Version 1.06. We are
 researching this problem and will post new information as it becomes
 available.


 434. QuickHelp MENUITEM MIA_ENABLED Documentation Error

 There is a problem with the QuickHelp documentation on the MENUITEM
 statement under the Tools category regarding the RC.EXE program. The
 second MENUITEM statement in the Example section uses a #define that
 does not exist. The MIA_ENABLED definition should not be documented
 because it is not present in the OS2.H include file.

 Microsoft has confirmed this to be a problem in the QuickHelp
 included with the Version 1.06 OS/2 SDK (Software Development Kit).
 We are researching this problem and will post new information as it
 becomes available.



 435. QuickHelp CheckMenuItem Message Documentation Error

 Part of the QuickHelp documentation on the CheckMenuItem() function
 under the Windows Equivalent category is in error. The first paragraph
 after the syntax definition of the WinSendMesg() function references
 an incorrect message name. The function references the message
 MM_SETATTR, when it should actually be referencing the message
 MM_SETITEMATTR.

 Microsoft has confirmed this to be a problem with the QuickHelp
 included with the Version 1.06 OS/2 SDK (Software Development Kit).
 We are researching this problem and will post new information as it
 becomes available.



 436. Argv

 Problem:

 The environment generated for C programs in MS-DOS Version 3.30 and
 OS/2 bound programs is not the same. The contents of argv[0] are
 different depending on whether the application is a real-mode or
 protected-mode program.

 Under MS-DOS, the complete pathname of the EXECed program is placed in
 argv[0]. In an OS/2 bound program, only the primary part of the
 filename with no path and no extension is placed in argv[0].

 Response:

 The difference between a protected-mode and real-mode argv[0] occurs
 because the only thing that you are guaranteed to get in argv[0] is
 what the parent process (COMMAND.COM or CMD.EXE) passes to you. You
 could write a program that spawned child processes using the EXEC
 function and pass whatever you want to your children. It just so
 happens that COMMAND.COM and CMD.EXE do things differently.

 Microsoft has confirmed this to be a problem in Version 1.06. We are
 researching this problem and will post new information as it becomes
 available.


 437. Determining Block of Memory Allocated by DosSubAlloc()

 Question:

 Is there a way to determine the size of a block of memory allocated by
 DosSubAlloc()? It seems that the USHORT at sel:offset-8 could be used,
 but I don't want to hard code that into my program. I'm asking because
 DosSubFree() wants a block size, but I don't have that available.

 Also, why does DosSubFree want a size when it can read it from the
 block header? If I give it a value that is too big, it returns an
 overlap error. However, no error is returned if the value is too
 small.

 Response:

 The method of looking at sel:offset-8 is not valid. It does not work
 correctly and even if it did work, it could be changed in the future
 because the module involved is a DLL.

 The length of the block to free is required because you can free a
 size of memory that is less than what you allocated. If you allocated
 100 bytes, then found that you only needed 60, you could free up 40
 bytes. As a result, if your original DosSubSet() initialized a heap
 segment that was 200 bytes in size, and you did a DosSubAlloc() for
 100 bytes, then you could use the offset into the 100 bytes to do a
 DosSubFree() of less than 100 bytes. For example, this could be 40
 bytes.

 The bookkeeping is left up to you. The offset that you give to
 DosSubFree() does not have to be the same as the offset that you got
 back from DosSubAlloc(). You can decide how to free the memory as
 you desire. Most people want to be consistent about freeing the memory
 (from the top or bottom of the offset), though.

 One method for bookkeeping is similar to the 8-byte rule you mentioned
 above. You could write a couple of routines named Alloc and Free,
 which call DosSubAlloc() and DosSubFree(), respectively. Alloc could
 ask DosSubAlloc() for one or more bytes more than the application
 asked for and could store the length in byte(s). Alloc would then pass
 back the pointer to the length of the data, with the data being a
 standard offset from the pointer. Free could then look at the length
 you wanted to free and could free the memory and change the size
 accordingly.


 438. Obtaining Serial Printer Status Information

 Question:

 We are trying to use DosDevIOCtl category 5 function 66H to check the
 status of a serial printer (on-line, out of paper, etc..), but it
 seems to be returning inconsistent results. Is it supposed to work
 correctly with serial printers? If not, what can we use instead?

 Response:

 To print to the serial printer, your application must open one of the
 COM ports and use the handle returned from DosOpen (,COMx,..). When
 you use this handle in a subsequent DosDevIOCtl API for function 66H,
 it returns the "modem control output signals" instead of the "printer
 status" information. This behavior occurs because the handle
 corresponds to the COM driver. So, you cannot use any of the printer
 driver IOCtls when talking to a serial printer.

 To get the serial printer status information, you can write an
 application program, which sends the printer specific commands to
 the COM port and gets the response from the printer.


 439. OS/2 SDK: Using DosGetPPID() to Determine Root Process

 Question:

 I have the following questions regarding the function call,
 DosGetPPID():

 1. In what versions of OS/2 is DosGetPPID() supported?

 2. What is the "official" technique for determining whether I've
    reached the "first" process?

 Response:

 1. DosGetPPID() is only valid under OS/2 1.10.

 2. The supported method is to check for a parent PID of 0, which means
    you are at the root process in the chain. When the parent PID is
    returned as zero, the process has no parent. Also, if you pass zero
    as the child PID, it is assumed that you want the parent PID of the
    current calling process (i.e., your parent). This information can
    also be obtained from the structure PIDINFO in the pidParent field
    by using the DosGetPID() function call.


 440. Backward Compatibility with OS/2 Version 1.00

 Question:

 If you have a working Version 1.00 OS/2 application and you recompile
 and link it with the new OS2.LIB, API.LIB, and header files included
 with the OS/2 SDK (Software Development Kit) Version 1.06, will it
 still work on OS/2 Versions 1.00?

 Response:

 It will not work in all cases. Many APIs have changed from Versions
 1.00 to 1.10. One example is DosStartSession(), which now accepts
 almost twice as many arguments as it did originally. It has been
 updated in an upwardly compatible fashion, however.

 If you want your application to run on both Versions 1.00 and 1.10 of
 OS/2, you should use the includes and libraries (doscalls) from the
 latest version of OS/2 Version 1.00, NOT Version 1.10.

 This way you can ensure that you do not accidentally call unsupported
 or changed Version 1.10 functions. If you write for OS/2 Version 1.00,
 you can be safe in assuming that everything will be supported in
 future versions of 1.00 and 1.10. If you use the header files and
 libraries from the OS/2 Version 1.10 SDK, you run the risk of having
 things fail on a kernel that is later than Version 1.10.


 441. DosExecPgm First Argument String Parameter Information

 Question:

 When a C program is executed synchronously using the OS/2 function
 call DosExecPgm(), the "arguments" pointer must contain the program name
 so that the normal C convention of having your first argument pointer
 at argv[1] is upheld. Is this what it is supposed to do?

 Response:

 Yes; the convention used by CMD.EXE is that the first argument string
 is the program name either as it was entered on the command line or
 as it was found in a batch (.CMD) file. We suggest that you follow
 this convention to ensure the correct operation of programs (if not
 your own) that you spawn from your application with DosExecPgm().



 442. OS/2 SDK: Print Spooler Problem When No Printer Is Present

 There is a problem with the OS/2 Spool utility in the OS/2 Software
 Development Kit (SDK) Version 1.06. If you create a spool job and do
 not have a printer connected to your system, you will get a spooler
 error of PMV8006, followed by "n" number of PMV8005 errors, where "n"
 is determined by the number of times you press ENTER or Cancel for
 this error before you physically restart your system and delete the
 job file from the \SPOOL subdirectory.

 Microsoft has confirmed this to be a problem in Version 1.06. We are
 researching this problem and will post new information as it becomes
 available.


 443. OS/2 SDK: Problem with SETCOM40 Command

 Problem:

 There appears to be a problem with SETCOM40. In the DOS 3.x mode, I
 issue a SETCOM40 COM2=ON command, which produces normal behavior with
 my software communications package. After exiting from my software
 communications package, I issue a SETCOM40 COM2=OFF command, which
 produces a "SYS0049 The COM2 device is not functioning" error,
 followed by a "SYS2087 Port can not be opened" error when the error is
 returned to SETCOM40.

 The port is still available and functions correctly in the DOS 3.x
 mode, but it is not available in protected mode. I must reboot my
 system to make the port available again in protected mode.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.06 of the
 OS/2 Software Development Kit (SDK). We are researching this problem
 and will post new information as it becomes available.


 444. OS/2 SDK: No FAPI Equivalent for MS-DOS IOCtl 4406H or 4407H

 Question:

 Are there FAPI equivalents for the MS-DOS Interrupt 21H IOCtl services
 4406H (check input status) and 4407H (check output status)?

 Response:

 No, there is no FAPI that is the equivalent of either of these
 functions. These IOCtl functions are only generated by the DOS
 emulation mode. No OS/2 API can cause the file system to generate
 these functions. OS/2 block device drivers will never get these calls.
 OS/2 character device drivers may get these calls, if called from a
 DOS application.


 445. OS/2 DosDevIOCtl() GETDEVICEPARAMS "bMedia" Not Documented

 There is no documentation in either QuickHelp or the hard-copy
 documentation concerning the meaning of the field bMedia in the
 DosDevIOCtl() GETDEVICEPARAMS.

 Microsoft has confirmed that the bMedia field is not documented in
 either QuickHelp or the hard-copy documentation. We are researching
 this problem and will post new information as it becomes available.
 Below is some information regarding bMedia.

 The bMedia field of the BIOS Parameter Block structure returned in the
 GETDEVICEPARAMS function of the OS/2 DosDevIOCtl() API is the media
 descriptor byte. The following is information on the Media Descriptor
 Byte that is included in the "MS-DOS Version 4.00 Programmer's
 Reference" manual:

    2.8 The Media Descriptor Byte

    In MS-DOS, the media descriptor byte is used to inform the DOS
    that a different type of media is present. The media descriptor
    byte can be any value between 00h and FFh. It does not need to
    be the same as the FAT ID byte. The FAT ID byte, which is the
    first byte of the FAT, was used in MS-DOS 1.00 to distinguish
    between different types of disk media, and may be used as well
    under 2.x and 3.x [and 4.x] disk drivers. However, FAT ID bytes
    have significance only for block device drivers where non-FAT ID
    bit is not set (0). Values of the media descriptor byte or the
    FAT ID byte have no significance to MS-DOS. They are passed to
    the device driver so that programs can determine the media type.

 The following are some standard media descriptor bytes, taken from
 Section 3.7 of this same reference:

    Table 3.1: MS-DOS Standard Removable-Disk Formats

    -----------------------------------------------------------
    Disk Size in inches              5.25              8
    -----------------------------------------------------------
    WORD no. heads              1   1   2   2     1    2    1
    Tracks/side                 40  40  40  40    77   77   77
    WORD sectors/track          8   9   8   9     26   26   8
    WORD bytes/sector           512 512 512 512   128  128  024
    BYTE sectors/ cluster       1   1   2   2     4    4    1
    WORD reserved sectors       1   1   1   1     1    4    1
    Byte no. FATs               2   2   2   2     2    2    2
    WORD root directory entries 64  64  112 112   68   68   192
    WORD no. sectors            320 360 640 720   2002 2002 616
    BYTE media descriptor       FE  FC  FF  FD    *FE  FD   *FE
    WORD sectors/FAT            1   2   1   2     6    6    2
    WORD no. hidden sectors     0   0   0   0     0    0    0
    -----------------------------------------------------------
    *The two media descriptor bytes are the same for 8" disks
    (FEH). This is not a misprint. To establish whether a disk
    is single- or double-density, try a read of a single-density
    address mark. If an error occurs, the media is double-density.

    Table 3.2: MS-DOS Standard Removable-Disk Formats (High-Density)

    ----------------------------------------------------------
    Disk Size in inches       3.5 or 5.25       3.5     5.25
    ----------------------------------------------------------
    WORD no. heads          1   2   2    2       2       2
    Tracks/side             80  80  80   80      80      80
    WORD sectors/track      8   9   8    9       18      15
    WORD bytes/sector       512 512 512  512     512     512
    BYTE sectors/cluster    2   2   2    2       1       1
    WORD reserved sectors   1   1   1    1       1       1
    BYTE no. FATs           2   2   2    2       2       2
    WORD root dir entries   112 112 112  112     224     224
    WORD no. sectors        640 720 1280 1440    2880    2400
    BYTE media descriptor*  FA  FC  FB   F9      F0      F9
    WORD sectors/FAT        1   2   2    3       9       7
    WORD no. hidden sectors 0   0   0    0       0       0
    ----------------------------------------------------------
    *The value F0H in the media descriptor byte may be used to
    describe other media types.


 446. How OS/2 Handles "Badly-Behaved" Applications

 Question:

 We have noticed that there is a problem with poorly written
 Presentation Manager (PM) programs. For example, sometimes the
 terminal emulator that we are using will hang the system for quite
 some time if you ask it to dial a modem on a communications port
 without a modem hooked up. We understand that the terminal emulator
 should have multiple threads to avoid this problem, but it doesn't.

 To the beginning user who isn't very familiar with OS/2, OS/2 appears
 to be very slow or it appears to be a system with performance
 problems, when in fact this isn't true. What is the best way to handle
 this problem?

 Response:

 Synchronization problems go beyond mouse and keyboard messages. When a
 PM program handles any message and decides to undertake an
 indefinitely long activity without calling WinGetMsg() or
 WinPeekMsg(), it creates a bottleneck in the send message activity
 that occurs between windows. As a result of this, it appears that the
 system is hung.

 Messages that are sent [via WinSendMsg()] are not interrupts. They do
 not override messages currently being processed. These messages sent
 via WinSendMsg() send messages that are block waiting for the
 "badly-behaved" application to finish processing the message. While
 blocking, other windows may attempt to send messages to either of
 these applications (the application with a blocked send message, or
 the badly-behaved application). These processes will also block on
 their send messages. This sequence of events continues, and ends up
 blocking most of the threads with windows in the system.

 The problem described above normally is encountered by the user when
 attempting to switch to another window while the badly-behaved
 application is holding up message processing. Many messages are sent
 at this time to switch focus, activation, selection, adjust window
 z-order, etc. Since messages sent to the badly-behaved application
 block, the switch to the other window cannot be completed and the
 bottleneck occurs.

 A feature does exist in the current PM system for dealing with
 badly-behaved applications. If task switches cannot be made using
 hotkeys such as CTRL+ESC, ALT+ESC, or by using the mouse, a message
 box will appear informing the user that an application is failing to
 process its messages, and asks if this application should be shut
 down. When a task switch is requested, a timer is set at approximately
 15 seconds. If the switch does not occur in that time, the system
 walks through the list of blocked send messages to determine which
 application is the badly-behaved application.

 Only by destroying the process (badly-behaved application), or by the
 process completing its message processing, will the send messages be
 processed and the blocked send messages released. The situation
 described above only works for normal window threads. If a message
 queue thread boosts its priority to time-critical and goes into an
 infinite loop, the message box for killing badly-behaved applications
 cannot come up. Time-critical threads do as their name implies: they
 allow handling of critical events without interference. If the
 terminal emulator described above uses this type of technique, then it
 is by design and the system will not interfere with it.


 447. OS/2 DosDevIOCtl GETDEVICEPARAMS Doesn't Work with MS-DOS 3.x

 The FAPI call DosDevIOCtl(pbBPB, bpCommand, 0x0063, 0x0008, hDevice)
 (GETDEVICEPARAMS) does not work correctly under MS-DOS Version 3.30.
 It returns an "invalid command" error.

 The error is returned because this function call is not supported
 under MS-DOS Versions 3.x.


 448. OS/2 SDK: BPB Structure for Device Documentation

 The structure for the device of the BPB is not documented in either
 QuickHelp or the printed documentation.

 The BPB structures for the device and the current media are identical.
 The only difference is what is returned in the structure. If you are
 looking for the device BPB, the parameters for the device are
 returned. If you are looking for the current media, the parameters for
 the disk in the device are returned. For example, if you had a 360K
 disk in a 1.2-megabyte disk drive, the parameters would change,
 depending on whether you were looking for the device or the actual
 disk in the drive.

 We will clarify this information in a future release of the
 documentation.


 449. OS/2 SDK: DosErrClass() Not Documented Correctly in QuickHelp

 In QuickHelp, the error handling topic mentions "DosErrorClass()" in
 its body, but the API name is actually "DosErrClass()" (which does
 appear in the reference list).

 Microsoft has confirmed this to be a problem with the QuickHelp
 included with the Version 1.06 OS/2 SDK (Software Development Kit). We
 are researching this problem and will post new information as it
 becomes available.


 450. OS/2 SDK: Maximum Length Allowed for PATH in CONFIG.SYS

 Question:

 What is the maximum length allowed for subdirectory names in the PATH
 command in CONFIG.SYS?

 Response:

 When using Microsoft OS/2 Version 1.00 (OS/2 SDK Version 1.02), the
 PATH environment variable is restricted to 128 characters, a
 restriction made by the command-line buffer length of CMD.EXE. Under
 OS/2 Version 1.10 (OS/2 SDK Version 1.06), this restriction has been
 changed to 512 characters.

 To get around this restriction, you could use short subdirectory
 names. For example, you could use \LMP for LAN Manager in protected
 mode, and \LMR for LAN Manager in real mode. This naming convention
 would work because the LAN Manager allows you to specify the directory
 in which you want the LAN Manager installed. Also, you could
 consolidate by keeping most of your executables in subdirectories
 named \BINR, \BINP, and \BINB.


 451. OS/2 SDK: MARKEXE Return Values

 Question:

 MARKEXE is setting the error level to 3 for some of my .EXE files.
 What does this mean? The .EXE files seem to work in a window, but I
 hesitate to release them for general use because of the nonzero error
 level returned.

 Response:

 You need not be concerned with this error. Currently, MARKEXE does not
 explicitly set its return code; therefore, the return value returned
 from it is not meaningful. If you do a comparison of the file before
 and after running MARKEXE on it, you should only notice a 1-byte
 change in the OS/2 header that specifies what type of an executable
 the file is. In a future release of MARKEXE, we plan to make the
 return value information returned more meaningful.


 452. ANSI Key Reassignment Problem in OS/2 SDK

 There is a problem with ANSI key reassignments in the Version 1.06
 OS/2 Software Development Kit (SDK). The following steps show how
 to reproduce the problem:

 1. Start up a new copy of CMD.EXE from an existing copy of CMD.EXE.

 2. Perform a key reassignment by sending an ASCII escape sequence to
    redefine the key sequences to the screen. For example, the key
    sequence "ESC[65;81p" will redefine the "A" key to the "Q" key.

 3. Exit the child process and return to the parent CMD.EXE process.

 4. In the parent process, the key reassignment has been released. If
    you press the "A" key, an "A" will be displayed, instead of the
    redefined "Q" key.

 5. Repeat Steps 1 to 3 (above) a few times. The key reassignment in
    the child process will remain; if you press the "A" key, a "Q" will
    be displayed.

 Microsoft has confirmed this to be a problem in Version 1.06 of the
 OS/2 SDK. We are researching this problem and will post new
 information as it becomes available.



 453. OS/2 SDK: Freeing Virtual Address in DevHlp PhysToUVirt()

 Question:

 In the DevHlp PhysToUVirt(), does the virtual address have to be freed
 (request type #2) when you no longer need it?

 Response:

 Yes, we advise that you use "request type = 2" to free the selector;
 otherwise, the selector will stay in the LDT (local descriptor table)
 of the process.


 454. OS/2 SDK: Using Logo Display Option in Control Panel

 Question:

 What is the purpose of the Logo Display option available in the
 Control Panel in the OS/2 Software Development Kit (SDK) Version 1.06?

 Response:

 The Logo Display option allows you to add certain entries to the
 OS2.INI file so that other applications can check this entry to
 determine how long they should display a start-up logo screen before
 continuing. Some of the applications that do this are ICONEDIT,
 DLGBOX, and FONTEDIT. Please note that this is only a convention and
 does not affect applications that are not written to check the OS2.INI
 value for logo display.


 455. OS/2 SDK: Loading All Databases in the QuickHelp Directory

 Question:

 I have created my own QuickHelp database and have put it into the
 same directory as the databases that came with QuickHelp. My "qh"
 variable points to this directory. When I bring up QuickHelp, my
 database is not loaded automatically like the supplied databases.
 I can set my "qh" variable to include a -d <my database name>
 after the path and it works fine, but what if I create a second
 database? Is there some way to get QuickHelp to load all databases
 in the QuickHelp directory?

 Response:

 For now, you will have to add each new database name to the command
 line (or environment) using the -d switch, as in the following
 example:

    qh=d:\qh d:\qh\foo.hlp d:\qh\bar.hlp

 This will open the default databases from the d:\qh directory and also
 open the two additional databases "foo.hlp" and "bar.hlp" from their
 respective subdirectories.

 Please note that if you use the "qh" environment variable, you do
 not have to use the -d switch. This is required only when you invoke
 QuickHelp from the command line without a "qh" variable in the
 environment.

 Microsoft is considering changing this behavior so that QuickHelp will
 be allowed to open all *.hlp files in the directory passed by the "qh"
 variable or on the command line. We will post new information as it
 becomes available.


 456. OS/2 SDK: Trapping Critical Errors

 Question:

 Is it possible to capture critical errors such as the following?

    Drive Door Not Open.
    Printer not turned on.
    Disk out of space.

 We would like to trap the critical errors and display our own error
 messages/warnings rather than have the operating system step in and
 display the black and white monitor screen with the "retry, ignore,
 abort" options.

 Response:

 It is possible to tell the operating system that file I/O operations
 that would cause a hard-error pop-up should return a unique error code
 instead. You do this by specifying the 0x2000 bit flag in the
 fsOpenMode (seventh parameter) to DosOpen(). When this bit is set in
 the open mode parameter to DosOpen(), any subsequent calls that
 operate on that handle, with the exception of DosDevIOCtl(), will
 return an error code instead of invoking a hard-error pop-up. For
 instance, if you remove the floppy disk that you have just opened a
 file on using DosOpen(), and you do a DosWrite() on that file, the
 DosWrite() call will fail with a return code.


 457. Killing Hung Programs in DOS 3.x Box or in Protected Mode

 Question:

 How do you kill a hung program that is/was running in either the DOS
 3.x box or in protected mode?

 Response:

 This depends on how the program is hung, but the normal DOS methods
 apply to the DOS 3.x box. You should first try pressing CTRL+C,
 then CTRL+BREAK. If this doesn't work, switch to any
 protected-mode programs that you have running, close them down in
 an orderly fashion, then use CTRL+ALT+DEL to reboot the computer.

 The same method applies for protected mode programs, except that you
 can also send a kill signal to the process if you know its Process ID
 (PID). You would do this using the DosKillProcess() call. Another
 possibility is to use the Presentation Manager (PM) shell to force the
 application to be sent a kill signal. To do this, use the control menu
 for either the icon of the session that contains the program that is
 hung, or the system menu for the hung session, if that session is in a
 VIO window. In either case, bring up the control menu by either
 clicking on the icon or clicking on the control menu control in the
 upper left corner of the window and selecting "Close". The system will
 confirm that you want to close the session and then should recover.


 458. VioQueryFonts() QuickHelp Documentation Problem

 The version of Quickhelp included with the Version 1.06 OS/2 SDK
 (Software Development Kit) defines VioQueryFonts() with six
 parameters. VioQueryFonts() actually has seven parameters. Below is
 the correct documentation for VioQueryFonts().

 USHORT VioQueryFonts(pcbMetrics, pfm, cbMetrics, pcFonts,
                      pszFacename, flOptions, hvps)
 PLONG pcbMetrics;    /* pointer to variable for structure length */
 PFONTMETRICS pfm;    /* pointer to structure for font metrics    */
 LONG cbMetrics;      /* length of structure                      */
 PLONG pcFonts;       /* pointer to variable for number of fonts  */
 PSZ pszFacename;     /* pointer to string for face name          */
 ULONG flOptions;     /* enumeration options                      */
 HVPS hvps;           /* presentation-space handle                */

 The VioQueryFonts() function retrieves a font-metrics structure (or
 structures) that contains characteristics of the fonts that match the
 specified face name. These characteristics, or font metrics, are
 returned for as many matching fonts as will fit in the structure
 pointed to by the pfm parameter.

 After examining the returned data, the application selects the font
 most appropriate for its requirements, and if necessary, forces
 selection of a particular font by specifying the lMatch field (as
 returned in the pfm parameter) in the FATTRS structure for the
 VioCreateLogFont() function.

 By specifying zero for the pcFonts parameter and then examining the
 value returned, the application determines how many fonts match the
 specified face name.

 All sizes are returned in world coordinates. For more information,
 refer to the "Microsoft Operating System/2 Programmer's Reference,"
 Volume 1.

 Parameters   Description
 --------------------------------------------------------------------
 pcbMetrics   Points to the variable that receives the length (in
              bytes) of each FONTMETRICS structure. The structure
              pointed to by the pfm parameter must contain the number
              of bytes given by pcFonts x pcMetrics.

 pfm          Points to the FONTMETRICS structure that receives the
              font metrics of the specified matching fonts. The format
              for each record is defined in the GpiQueryFontMetrics()
              function.

 cbMetrics    Specifies the length (in bytes) of the font-metrics
              structure(s).

 pcFonts      Points to the variable that receives the number of fonts
              for which the application requires metrics.

 pszFacename  Points to the null-terminated string that specifies the
              face name.

 flOptions    Specifies whether to enumerate public or private fonts.
              This parameter may be any combination of the following
              values:

              Value        Meaning
              --------------------------------------------------------
              VQF_PUBLIC   Enumerate public fonts.

              VQF_PRIVATE  Enumerate private fonts.

 hvps         Identifies the advanced video-input-and-output (AVIO)
              presentation space. This handle must have been created
              previously by using the VioCreatePS() function.

 Return Value

 The return value is the number of fonts not retrieved. The return
 value is -1 if an error occurs.

 See Also

 GpiQueryFonts, VioCreateLogFont, VioCreatePS, _FATTRS, _FONTMETRICS


 459. OS/2 SDK: ALT+ESC Doesn't Select Foreground Session Correctly

 Microsoft has confirmed that there is a problem with OS/2 not
 selecting foreground sessions correctly in the OS/2 Software
 Development Kit (SDK) Versions 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, and
 1.06. We are researching this problem and will post new information as
 it becomes available.

 The following steps reproduce the problem:

 1. Start up PARENT.EXE in a session.

 2. Start up MEP.EXE.

 3. Have PARENT.EXE do a DosStartSession() to start up CHILD.EXE
    (specifying "related").

 4. Use DosSetSession() to establish a "bond" so that when the parent
    session (PARENT.EXE) is selected by the user, the child session
    (CHILD.EXE) will be brought to the foreground session instead.

 5. The Task Manager (or the Program Selector in Version 1.00) now
    looks like the following:

       Start Programs

       PARENT.EXE
       MEP.EXE
       CHILD.EXE

 6. If you press ALT+ESC to switch between the sessions, the MEP.EXE
    session will be skipped in the sequence.

 Keywords: buglist1.03 buglist1.04 buglist1.05 buglist1.06


 460. OS/2 SDK: Accessing Buffer Memory on an Auxiliary Memory Board

 Question:

 If the processor is going to access buffer memory on an auxiliary
 board, does the physical address of the memory have to be above 1
 megabyte, rather than in the standard ranges used for MS-DOS?

 Response:

 The memory on the auxiliary board should be mapped to an address range
 such that there is no conflict with the memory already present in the
 system. Conventionally, a ROM BIOS is mapped in the 640K to 1 megabyte
 range.

 If you do not want the memory manager to manage the buffer memory on
 the auxiliary board, this block of memory should be placed in a
 disjoint address space.


 461. Interpreting High-Order Byte Returned by DosGetVersion()

 The following is information about how to translate the high-order and
 low-order bytes of the DosGetVersion() function call into the major
 and minor version values.

 The high-order byte of DosGetVersion() is the major version and the
 low-order byte is the minor version. The current values returned in
 the major version byte represent the major version multiplied by 10,
 and the current values returned in the minor version byte represent a
 two-digit minor version. Thus, 10.00 translates to OS/2 Version 1.00,
 and 10.10 translates to OS/2 Version 1.10. The minor version byte has
 the potential to contain a two digit number. For example, a minor
 release of OS/2 Version 1.00 could have been called 1.01. To date, the
 least significant digit of this minor version byte has not been used.

 The following table lists the values of the high-order and low-order
 bytes of released OS/2 versions and what they translate to:

     Word    Hibyte    Lobyte  Version
     ----------------------------------
     0A00h  0Ah (10)  00h (00)   1.0
     0A0Ah  0Ah (10)  0Ah (10)   1.1


 462. OS/2 SDK: Large RAM Disks Used with VDISK.SYS Hang OS/2

 Microsoft has confirmed that there is a problem with the version of
 VDISK.SYS included with Versions 1.00, 1.01, 1.02, 1.03, 1.04, 1.05,
 1.06, and 1.10 of the OS/2 Software Development Kit (SDK). If a very
 large size for VDISK.SYS is specified, the system will not behave
 properly. With smaller sizes, the system will not have enough extended
 memory to operate without swapping to disk, so response time will
 increase and system performance will decrease. However, with extremely
 large virtual RAM disks (such as a 3-megabyte RAM disk on a system
 with 4 megabytes of extended memory), the system will hang
 unpredictably.

 We are researching this problem and will post new information as it
 becomes available. The workaround is to not use a very large virtual
 RAM disk with VDISK.SYS, so that the system will have enough extended
 memory to work properly and efficiently.

 Keywords: buglist1.03 buglist1.04 buglist1.05 buglist1.06 buglist1.10


 463. OS/2 SDK: System Not Closing Open Keyboard Handle

 Microsoft has confirmed that there is a problem with the system not
 closing the logical keyboard if the program that opened the keyboard
 fails to close it before exiting. This problem can be duplicated by
 running the KBDOPEN.C program below at least 17 times in a row in a
 Presentation Manager (PM) text window (e.g. with CMD.EXE). The program
 will fail with a return code of 440 (ERROR_KBD_NO_MORE_HANDLE). The
 program can be run an unlimited number of times full screen with no
 failure. The program is as follows:

 KBDOPEN.C:

 #define  INCL_SUB
 #include <os2.h>
 #include <stdio.h>
 main()
    {
    HKBD keyboard;
    USHORT rc;
    if (rc = KbdOpen(&keyboard))
       printf("Keyboard open failed, rc = %d\n", rc);
    }

 Microsoft has confirmed this to be a problem in Version 1.06. We are
 researching this problem and will post new information as it becomes
 available.

 To work around this problem, you must close the logical keyboard,
 using an exitlist routine if necessary.


 464. OS/2 SDK: Support of 16550 UART in OS/2 1.00 and 1.10

 Question:

 In addition to the 8250 UART and the 16450 UART, does the OS/2 COM
 device driver provide support for the 16550 UART?

 Response:

 The 16550 UART initializes itself in 16450 emulation mode and thus
 operates exactly as a 16450, using none of the extra abilities of this
 newer generation UART (such as FIFO buffers, etc.). Therefore, the
 OS/2 COM device drivers of OS/2 Versions 1.00 and 1.10 will work with
 the 16550 UART, treating it like a fast 16450 UART.


 465. Information and Guidelines to Use When Submitting OS/2 SRs

 ISVONLY |

 The following is a list of the information that Microsoft needs to
 process your OS/2 Service Requests:

 1. Hardware configuration

    a. Make/model of computer, and disk drive type

    b. Make/model of hard disk drive

    c. Make/model of monitor and display adapter, and ROM version
       numbers

    d. Make/model of disk controller

    e. Amount and type (conventional, extended, expanded) of memory in
       machine

    f. CPU speed

    g. Amount of hard disk memory free

    h. Any added cards that are installed, e.g. added memory, pointing
       devices, floating-point accelerator, or asynchronous cards

 2. Software configuration

    a. Operating system version number

    b. Product vendor (if product was purchased outside of Microsoft)

    c. A copy of your AUTOEXEC.BAT file

    d. A copy of your CONFIG.SYS file

    e. A copy of your STARTUP.CMD file

    f. A copy of your environment variables

    g. Any TSR (terminate-and-stay-resident) programs, or monitors that
       you have installed

 Following the guidelines listed below will help you get a faster
 response time for your Service Requests:

 1. Split your questions into multiple Service Requests

    Questions that are specific to the area they address are sent to a
    specialist in that area. A Service Request covering a variety of
    questions or products is assigned at random to be answered. You
    always get a faster response to your Service Request from a
    specialist.

    The Service Request cannot be released until all questions on it
    have been answered. This restriction slows an otherwise immediate
    response. Thus, the response time is the time it takes to answer
    the most difficult question; sometimes this can be a week or more.

    Multiple Service Requests allow several individuals to work on
    answering your questions, e.g. with multiple Service Requests,
    there may be four or more individuals answering your questions
    instead of one engineer working on answering all of your questions
    submitted in one Service Request.

 2. Provide code examples where applicable

    If you have a problem with any API, or if you have a programming
    question, always reduce the program to the minimum needed to
    reproduce the problem. Also, please make sure the code is self
    contained. Please provide the sample code in a form so that it
    can be compiled and linked without errors (unless the problem is
    with compiling or linking). We prefer that the sample code be
    written in C; however, MASM code is acceptable. If you are using
    the Version 5.10 C Compiler, please use the -W3 warning level
    option, and verify that no error messages are returned. We also
    recommend that you check all return codes from all function calls.
    Please include copies of all include files. Also, send in copies of
    the make file used to maintain the program, as well as the compiler
    and linker options used to compile and link your program. Please
    remember to archive the source code and all related files with the
    PKware file-compression utility, and submit the archived file as an
    attachment to the Service Request.

    Very large examples are not useful to help isolate the problem
    (unless the problem is directly related to the size of the
    example). If it is impossible to send the original code, write a
    separate example.

    Providing a sample program or a large program as an attachment to
    the Service Request allows easy verification that the problem is
    solved in the next release. This procedure allows us to verify
    that you are using the call correctly. Also, if the problem is
    not solved in the next release, this procedure gives us what we
    need to take the problem to development to get it resolved.

 3. General Service Request information

    a. Provide as much background information as possible if your
       problem or question is unique.

    b. Please do not send the Service Request description as an
       attachment.

    c. Please remember to insert an appropriate summarized version of
       your Service Request in the Subject line.

    d. Please do not direct questions to a specific person at
       Microsoft.

    e. Please report differences in behavior between different versions
       of the product or documentation.

    f. Assign the correct Severity to the Service Request.

    g. Select the correct product information when filling out the
       Service Request screen.

    h. Verify that the phone number is correct in your ONLINE.INI file
       so we can easily reach you if necessary.

    i. Please query the OnLine Knowledge Base before submitting a
       Service Request.

 By following the above guidelines, we can process your Service
 Requests much more efficiently.


 466. CTRL+C/CTRL+BREAK Difference, Depending on Keyboard Mode

 Different signals are returned for the CTRL+C and CTRL+BREAK key
 combinations, depending on the keyboard mode. For example:

    Keyboard Mode     Input Key      Signal Returned
    -------------     ---------      ---------------

    ASCII Mode        CTRL+C         SIG-CTRLC
                      CTRL+BREAK     SIG-CTRLC

    Binary Mode       CTRL+C         Nothing
                      CTRL+BREAK     SIG-CTRLBREAK

 Microsoft has confirmed that this information should be included in
 the "Microsoft Operating System/2 Programmer's Reference"
 documentation. We will post new information when the documentation has
 been updated to include this information.


 467. Making 3.5-Inch Install Disks for AT Machines

 Microsoft does not supply OS/2 version 1.20 on 3.5-inch disks for use
 on non-PS/2 machines. However, an increasing number of non-PS/2
 machines are configured with a high-density (1.44 MB) 3.5-inch floppy
 as the "A:" drive. Usually, these machines will also have a 1.2 MB
 "B:" drive, so it is possible to open the machine and swap drive
 cables, then boot from the 5.25-inch install disk and complete the
 installation process.

 If only one or two machines are being configured with OS/2 1.20, this
 is probably the easiest solution. Once the software has been
 installed, the drive cables can be swapped back. However, if it is
 necessary to install OS/2 1.20 on a number of machines that are
 configured with a 3.5-inch boot drive, this becomes very tedious. The
 instructions below describe the process of creating a set of 3.5-inch
 installation disks from the provided 5.25-inch disks.

 You will need eight high-density 1.44 MB disks. Format the disks, and
 as they are formatted, give them the following volume labels:

    Disk                          Volume Label
    ----                          ------------

    Disk #1 (Install disk)        OS2 INSTALL
    Disk #2 (Disk #1)             OS2 DISK 1
    Disk #3 (Disk #2)             OS2 DISK 2
    Disk #4 (Disk #3)             OS2 DISK 3
    Disk #5 (Disk #4)             OS2 DISK 4
    Disk #6 (Disk #5)             OS2 DISK 5
    Disk #7 (Drivers 1)           OS2 DRIVER1
    Disk #8 (Drivers 2)           OS2 DRIVER2

 For all of the disks except the install disk, you can use the XCOPY
 command, using the /s, /e, and /v parameters to indicate that you want
 to copy subdirectories if they exist, even if empty, and you want the
 data verified. Create Disks #2 - #8 using XCOPY.

 To make the install disk, you must create a bootable disk. The program
 that performs this function is called SYSINSTX.COM, and can be found
 on the install disk. You must have a machine that either is already
 running OS/2 1.20 or that can be booted from the 5.25-inch install
 disk for this to work correctly. The SYSINSTX utility takes a drive
 letter as its only parameter. This drive letter refers to the
 destination drive, containing the disk that is to receive the version
 1.20 system files. Once this has been completed, use XCOPY, as above,
 to copy over the remaining files.


 468. Toggling CAPS LOCK Light from VIO Window Fails in OS/2 1.20

 There is a problem in OS/2 Version 1.20 that is associated with
 attempting to toggle the CAPS LOCK mode from an application that is
 running in a VIO window.

 In a VIO window under OS/2 Version 1.20, the CAPS LOCK mode of the
 keyboard can be successfully toggled, but the CAPS LOCK light is not
 similarly toggled.

 The problem is that when an application makes KBD or KBD IOCTLs to set
 the shift state of the LED indicators, the KBD device driver SHOULD
 receive a Category 4 IOCTL 5AH. Unfortunately, this does not occur if
 the application is running in a VIO window.

 The source of this problem lies in the part of the PM shell that
 creates and manages VIO windows.

 Microsoft has confirmed this to be a problem in OS/2 Version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 469. Critical Error in DOS 3.x Box Can Cause System to Hang

 Two cases of the system hanging when a critical error is generated
 while in the DOS 3.x box have been reported. The following information
 describes the exact circumstances in which this problem occurs.

 This problem involves the use of the monochrome printer adapter (MPA).

 If the VIO_IBMMPA video device driver is loaded, and you go into the
 DOS 3.x box and enter "dir a:" with no disk in Drive A, the system
 will hang. On one occasion it was possible to press ALT+ESC to exit
 out of the DOS 3.x box, but every other time, the only keys that had
 any effect were the CTRL+ALT+DEL keys.

 The second scenario requires that VIO_IBMMPA not be loaded. You need
 to go into the DOS 3.x box and enter "MODE MONO" (this is on an EGA
 system with the monochrome adapter as the secondary monitor). At this
 point, if you enter "dir a:" with no disk in Drive A, the system will
 hang again.

 If VIO_IBMMPA is not loaded and you stay away from the monochrome
 adapter (no mode mono), you will get the standard hard error pop-up
 screen.

 If you do the same thing on a PS/2 with a VGA and no monochrome
 adapter, it works correctly.

 The equipment that the hanging occurred on is a clone 386/20 with an
 EGA and a monochrome adapter attached to it.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 470. OS/2 Serial I/O Data Communications Guidelines

 Listed below are some guidelines that should be considered when
 performing serial I/O data communications under OS/2.

 1. The COM driver included with OS/2 is specified to provide
    one-way communication at 9600 baud. Attempting two-way
    communication at 9600 baud may result in lost characters.

 2. The use of better microprocessors (for example, an 80386 instead of
    an 80286, or a faster 80386 instead of a slower 80386) tends to
    improve performance.

 3. To improve serial I/O, use OS/2 Version 1.2 on a machine with a
    16550 UART. More recent computers use the faster 16550 UART instead of
    the older and slower 16450 UART. Under OS/2 Version 1.10, the COM
    driver treats the 16550 as a fast 16450. However, under OS/2 Version
    1.20, the new features of the faster 16550 are supported.

 4. Because OS/2 is a multitasking operating system, there is no way to
    monopolize the entire system in order to absolutely ensure that no
    data is missed during serial I/O. However, you can minimize
    the possibility of losing data that is coming in through the COM
    port by doing the following:

    a. Use some sort of hardware or software handshaking so that there
       is no data loss. Hardware handshaking is preferred, but software
       handshaking is fine as long as "full duplex automatic receive
       flow control" is also enabled.

    b. Use the SetDCBInfo IOCTL (Category 1, Function 53H) to specify
       MODE_WAIT_READ_TIMEOUT time-out processing (this is a bit in the
       fbTimeout byte in the DCBInfo structure passed to the IOCTL).

    c. The user buffer size should be as large as possible to decrease the
       system call overhead per byte transferred. Using 1K DosRead() calls
       is a good place to start.

    d. To get maximum throughput without overrunning the device driver
       buffer, you need to get another DosRead() request down to the
       device driver as soon as possible after the current DosRead()
       completes. This requires two "time-critical" threads, which
       should behave as follows:

          Thread 1 - DosRead into a pool of buffers
                     DosRead into next free buffer
                     Save number of bytes read in variable associated
                       with the buffer
                     Wake thread 2 to process data in buffer

          Thread 2 - Process data
                     Wait for data from thread 1
                     Process data in buffer

 5. If you have the 3.x box enabled, avoid bringing it to the
    foreground when performing serial I/O. Mode switching introduces
    fairly large interrupt latency periods.


 471. OS/2: Determining If Given Drive Is of Removable Media

 Question:

 Our application needs to be able to tell whether or not a given drive
 is of removable media. What is the recommended way of doing this?

 Response:

 You need to open the disk with the OPEN_FLAGS_DASD option and then
 call the IOCtl for removable media. You should do a DosError() call
 beforehand to get the error returned to the open call because there
 may not be any media in the drive and you will get a hard error if you
 don't make the DosError() call.

 Below is a code fragment that demonstrates this type of functionality.

 The sample code below should be compiled with the following options:

    cl /Lp /W3 ioctl.c

 Sample Code
 -----------

 #define INCL_DOS
 #include <os2.h>
 #include <stdio.h>

 int main(int argc, char *argv[]);

 int main(int argc, char *argv[])
 {
     HFILE   hfile;
     USHORT  usAction;
     ULONG   ulFileSize   = 0L;
     USHORT  usFileAttr   = FILE_NORMAL;
     USHORT  usOpenFlags  = FILE_OPEN;
     USHORT  usOpenMode   = OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE
                            | OPEN_FLAGS_DASD;
     ULONG   ulReserved   = 0L;

     BYTE    fRemovable;
     BYTE    Reserved     = 0;

     DosError(HARDERROR_DISABLE);

     if(DosOpen(argv[1],&hfile,&usAction,ulFileSize,usFileAttr,
             usOpenFlags,usOpenMode,ulReserved))

      {
       printf("Bad open.\n");
       DosExit(EXIT_PROCESS,0);
      }

     if(DosDevIOCtl(&fRemovable,&Reserved,DSK_BLOCKREMOVABLE,0x08,
                     hfile))
      {
       printf("Bad IOCtl.\n");
       DosExit(EXIT_PROCESS,0);
      }

     if(fRemovable)
      printf("Non-removable\n");
     else
      printf("Removable\n");

     DosClose(hfile);

     return(0);


 472. OS/2 SDK: Adding Support for Expanded Memory in Device Driver

 Question:

 Could you please provide us with some information on how to add
 support for our built-in EMM (Expanded Memory Manager) hardware in the
 DOS 3.x box under OS/2?

 Response:

 This can be done in one of the following ways:

 1. You can modify your DosHlpSizeMem() routine and return less memory
    than actually is present in the system, then let your EMM driver
    use that extra memory.

 2. You can develop an OS/2 device driver. This driver would ask for a
    user-defined amount of memory from the system using the DevHlp
    "AllocPhys". The driver then would install a software interrupt
    handler to handle EMM interrupts (e.g. INT 67H) using the DevHlp
    "SetROMVector". When a program running in the DOS 3.x box issues an
    INT 67H, this software interrupt handler would get control. This
    would allow you to manage the allocated memory.


 473. OS/2 SDK: BACKUP/RESTORE Problem on Files in 32nd Subdirectory

 If you try to use BACKUP or RESTORE to backup or restore files in the
 32nd subdirectory from the root directory, only one file is backed up
 or restored. Microsoft has confirmed this to be a problem in the
 Version 1.06 OS/2 Software Development Kit (SDK). We are researching
 this problem and will post new information as it becomes available.

 The workaround is to not use this many levels of subdirectories. In
 any case, this deep nesting of subdirectories (32 is the maximum level
 allowed in MS-DOS) seriously degrades performance.


 474. OS/2 SDK: Obtaining OS2.INI Details

 Question:

 What are the predefined OS2.INI strings and where can I get a list of
 these strings?

 Response:

 We plan to release a utility that displays the information in the
 OS2.INI file in a future release of the OS/2 SDK (Software Development
 Kit). Until this utility becomes available, you can write a similar
 utility by using the WinQueryProfileString() function call. If you
 pass this function an "application name" of NULL, it will return in
 the buffer the full list of application names. If you pass the
 function a valid application name and a NULL key name parameter, it
 will return in the buffer a full list of the valid key names for that
 application. In both cases, the buffer will be filled with
 null-terminated strings, with two nulls after the last string. In this
 fashion, you could loop through all of the application names and
 obtain all of the key names.


 475. OS/2 SDK: Interrupt Latency Benchmark

 Question:

 Has a benchmark been done to determine the typical latency time and
 task switch times for OS/2 on a 6 MHz IBM AT computer?

 Response:

 The interrupt latency values for an AT running at 6 MHz with one wait
 state are as follows:

                        3.x Box in      3.x Box in
                        Background      Foreground
                       ============================

    Dispatch latency          6 ms             6 ms
    Interrupt latency       500 us          1100 us
    Disable time            400 us           400 us

 These values do not include random latency caused by applications with
 IOPL that disable interrupts, or real mode applications doing CLI/STI.


 476. OS/2 SDK: Setting Environment Variable in Application

 Question:

 I have an application in which I am setting environment variables. I
 would like these variables set when I exit the application; however,
 the parent process (I assume CMD.EXE) doesn't recognize any changes.
 Thus, when I exit the application, it appears as though I never made a
 change.

 How do I tell a parent process to set an environmental variable? In
 general, how do I tell CMD.EXE to change its environment?

 Response:

 The command processor of OS/2, CMD.EXE, does not allow child processes
 to update the environment of their parents. The parent application,
 when using DosExecPgm() or DosStartSession(), passes an environment to
 the child process, and the child process receives a copy of this. The
 child process can modify the environment it has received from its
 parent, but the child cannot update the parent's environment.

 This environment inheritance behavior is isolated to the command
 processor, CMD.EXE (and COMMAND.COM for MS-DOS and for the OS/2 DOS
 compatibility mode), and another command processor could choose to use
 different inheritance rules. Actually, the command processor is almost
 completely in charge of the responsibilities of controlling the
 environment of different processes and who gets to see, use, or modify
 them. So, a UNIX-like command processor such as a C shell may choose
 to implement a mechanism such as the UNIX EXPORT command, which allows
 a specified environment string of a parent to be updated by a child.

 This behavior is consistent with the behavior of the command processor
 of MS-DOS, COMMAND.COM. Environment inheritance works in one direction
 only (from parent to child process).


 477. OS/2 SDK: When to Allocate Memory with DosAllocSeg()

 Question:

 My application needs up to 30 4K segments. I can either create all of
 the segments with DosAllocSeg() at the beginning of the application,
 or I can wait until each segment is actually needed to allocate it.
 Does allocating the segments at the beginning of the application
 actually take memory (or swap space) away from other applications,
 even if the segments may not ever be accessed?

 Response:

 At the time the application calls DosAllocSeg(), the memory is
 obtained for your use. This might require memory compaction and also
 might involve swapping before the API call returns. The same thing is
 true for any memory allocation call. In your case, you would probably
 want to refrain from allocating the memory until it is actually
 needed.

 This is the current behavior for OS/2 Versions 1.00 and 1.10; however,
 in future versions the memory model may change such that either method
 has effectively the same result. The actual method you decide to use
 will depend on such factors as the total size of what is being
 allocated, how easy it is to model your code each way, and how likely
 it is that you will really need the memory. If you are allocating a
 small total amount of memory, and if it would be easiest to allocate
 this memory up front and you will probably use it, then it would be
 acceptable to do this. Generally, it is good practice to allocate
 resources as needed and free them when you are finished; however, the
 final design of your code is a decision you need to make.


 478. Menu Cursor Not Highlighted Correctly in Program Selector

 There is a problem with the Program Selector shipped with OS/2 Version
 1.00. The following steps duplicate the problem:

 1. Move the mouse cursor to the first character of the program name
    displayed at the top of the programs (top left end) in the "Switch
    to a running program" list.

 2. Display the screen of the screen group and return to the Program
    Selector.

 3. Move the menu bar (reversed portion) at the third (or subsequent)
    selection from the top with the vertical arrow keys.

 4. Move the menu bar horizontally with the horizontal arrow keys.

 5. Move the cursor to its original position.

 6. Move the menu bar with the vertical arrow keys.

 The part of the menu bar that was reversed in pink (where the menu
 cursor was located formerly) has now turned red.

 It is possible to duplicate this incorrect "highlighting" problem with
 only two items on either or both sides of the Program Selector menus.
 It is in fact possible to highlight every line on both sides at once.

 Microsoft has confirmed this to be a problem with the Program Selector
 in OS/2 Version 1.00; however, it is only a cosmetic problem. This
 problem does not interfere with the functionality of the Program
 Selector.

 We are researching this problem and will post new information as it
 becomes available.

 Keywords: buglist1.03 buglist1.04


 479. OS/2 SDK: Device Driver DosExitList() Processing

 Question:

 We are using a third party IEEE device driver that currently is a bit
 unstable and therefore occasionally traps out while performing an I/O
 operation on our behalf. When this happens, no DosExitList()
 processing for our application appears to occur. Is this normal
 behavior?

 Response:

 Yes, this is expected behavior. If a trap occurs while executing the
 code of a device driver, the system is considered corrupt and
 unstable. No DosExitList() processing will be performed.

 What is also happening is that technically it is your thread that is
 trapping, since it is your thread traveling down into the kernel and
 executing within the device driver. With the exception of interrupt
 time, the GDT (Global Descriptor Table) and LDT (Local Descriptor
 Table) entries for the device driver are the ones belonging to your
 application's thread of execution. When you trap at ring 0, there is
 no way for the thread to make it back up to ring 3 to perform the
 exitlist.

 There is no modification you can make to the device driver other than
 correcting its logic to avoid a trap.


 480. OS/2 SDK: Number of GDTs and LDTs Allocated at Config Time

 Question:

 Is the number of GDTs (Global Descriptor Tables) allocated during
 configuration time fixed, or is there a parameter in CONFIG.SYS that
 controls how many GDTs are allocated?

 Response:

 Under OS/2, there is one GDT and one or more LDTs (Local Descriptor
 Tables) allocated at configuration time. The LDTs belong to the
 processes that are executing. Of all the LDTs present, only one of the
 LDTs is active: the one that belongs to the process that has the CPU
 at that time.


 481. OS/2 SDK: DosGetMessage() and Message Segments

 Question:

 How is the segment created that is referred to in the documentation on
 the DosGetMessage() function call? Also, if DosGetMessage() is to be
 issued by a DLL (Dynamic Linked Library), should I use MSGBIND to bind
 the messages to the DLL, or to the .EXE file that uses the DLL? Can
 both the .EXE file and the DLL have message segments?

 Response:

 Two of the parameters that are specified in the DosGetMessage() API
 are the message number to retrieve, and the name of the file
 containing the messages. To retrieve the requested message,
 DosGetMessage() first searches the process's message segment, if there
 is one present. If DosGetMessage() cannot find the message, then it
 searches the specified file for the message.

 The MKMSGF program is used to build a message file. The message file
 can then be bound to the message segment of an executable file using
 the utility MSGBIND.

 The MSGBIND utility binds a message segment to an "executable
 program." It does this by reading an input file that specifies which
 executable files to modify.

 These utilities are described in the "Microsoft Operating System/2
 Programmer's Learning Guide and Programming Tools" manual in Sections
 3.4 and 3.5, on Pages 32 to 35.

 The messages are bound to executable files only; DLLs do not have
 message segments.


 482. OS/2 SDK: Increasing Keyboard Buffer Size

 Question:

 Is there any way to increase the length of the keyboard buffer in
 OS/2? I could write my own keyboard monitor and then have the monitor
 buffer the keys with a larger buffer, but there must be a system
 parameter that allocates the initial buffer.

 Response:

 There are only two ways to increase the size of the keyboard buffer.
 The first way is to write a keyboard device driver and the second way
 would be to write a monitor such as the one mentioned above.

 There are no system parameters available that you can send to the
 keyboard driver to make it initialize its buffers to be any bigger
 than they already are.


 483. OS/2 SDK: ESC

 There is a problem with ANSI.DLL and ESC[>4H. You can see it best by
 running the sample program TERMINAL, connected to another machine.
 Create a text file with the following line:

         ESC[>4H (where ESC is replaced with the ASCII escape
                  character 27 decimal)

 Now, type the file and your screen will look very strange. At this
 point, the machine is fine, and if you enter the correct commands
 (which will not be displayed on the screen) you can exit your program
 and the screen will be restored.

 You can get a similar effect by typing the same file in OS/2. The
 screen will flash, then restore itself.

 Microsoft has confirmed this to be a problem with the OS/2 SDK
 (Software Development Kit) Versions 1.06 and 1.10. We are researching
 this problem and will post new information as it becomes available.


 484. VioGetPhysBuf() Only Allowed in Foreground Full-Screen Group

 Question:

 As part of a program we are developing, we wish to write directly to a
 monochrome monitor that is included as an add-on to our PCs. Our
 program runs fine if we are in OS/2 full-screen command mode. However,
 we get a protection violation if we execute it using the Program
 Starter or from a windowed CMD.EXE. Why is this error occurring?

 Response:

 The VioGetPhysBuf() in your program is failing with error 494, which
 is ERROR_VIO_EXTENDED_SG. VioGetPhysBuf() is not allowed from a window
 or a PM (Presentation Manager) screen group. It has always been the
 intent not to allow the VioGetPhysBuf() call from the extended screen
 groups. However, this information is not documented; we will post new
 information when it has been documented.

 If you must get to the MDA memory segment, there is another way to do
 this. Write a simple device driver whose only function is to install
 and respond to IOCtl calls to pass back selectors for the video
 memory. This is done using the DevHlp routine PhysToUVirt(). You can
 make IOCtl calls from any screen group and the selector passed back
 will always be valid.


 485. RESTORE Sometimes Restores Files Out of Specified Range

 The RESTORE command restores all files, including the files out of the
 range that were indicated with the /a:, /b:, /e:, or /l: option,
 unless the hard disk to be restored contains the same files as those
 to be BACKUPed.

 Microsoft has confirmed this to be a problem with Versions 1.00, 1.01,
 1.02, 1.03, 1.04, 1.05, and 1.06 of the OS/2 SDK (Software Development
 Kit). We are researching this problem and will post new information as
 it becomes available.

 Keywords: buglist1.03 buglist1.04 buglist1.05 buglist1.06


 486. Information Needed When Submitting Service Requests

 OS/2
 ISVONLY |

 A list of the information Microsoft needs to process your OS/2 Service
 Requests is as follows:

 1. Hardware configuration

 a. Make / Model of computer

 b. Amount of memory in machine

 c. Make / Model of monitor and display adapter

 d. Make / Model of Disk controller

 e. Any added cards that are installed, e.g. added memory, pointing
    devices, floating-point accelerator, asynchronous cards

 2. Software configuration

 a. A copy of your CONFIG.SYS file

 b. A copy of your STARTUP.CMD file

 c. A copy of your environment variables

 If you need to send in sample code, we request that the code be in a
 form so that it can be compiled and linked without errors (unless
 compiling/linking are the reason for the SR). Please include copies of
 all include files. Also, send in copies of the Makefile used to
 maintain the program as well as the compiler and linker options used
 to compile and link your program.

 By following the above guidelines, we can process your SRs much more
 efficiently.


 487. OS/2 SDK: COMMAND.COM Requirements to Run 3.x Box

 OS/2 does not start the 3.x box if COMMAND.COM is deleted from the
 root directory. The "SHELL=\os2\command.com /p" statement does not
 boot the 3.x box.

 Below is the relevant information on these statements. A more thorough
 discussion of these statements can be found on Pages 782-783 of "The
 MS-DOS Encyclopedia."

 There are two copies of COMMAND.COM installed by OS/2. One copy is
 placed in the root directory of the boot drive, and another copy is
 placed in the \OS2 subdirectory of this drive. Only one copy is
 needed; whenever possible, you should eliminate files from the root
 directory. The reason a copy of COMMAND.COM is placed in the root
 directory is for compatibility, since many applications may expect it
 to be there. An optimal system would only have one copy of COMMAND.COM
 with a SHELL statement in the CONFIG.SYS file that properly refers to
 this file.

 The usage for the SHELL statement of both MS-DOS and OS/2 (for the DOS
 compatibility mode of OS/2) is as follows:

    SHELL=[drive:][path]<command_processor> [<arguments>]

 <command_processor> is the name of the executable command processor.
 This is normally COMMAND.COM.

 <arguments> are zero or more command line arguments that are specific
 to the command processor being used. See the documentation on the
 specific command processor for more information.

 The usage for the COMMAND.COM is as follows:

    COMMAND.COM [<starting_directory>] [/E:<env_size>] [/P]
                [/C <command>]

 <starting_directory> is the directory in which MS-DOS will reload
 COMMAND.COM. If this is the root directory, this option is not
 necessary. This option should only be used during the first execution
 (the root copy) of COMMAND.COM.

 /E:<env_size> specifies the size of the environment, where <env_size>
 is in bytes. This option should only be used during the first
 execution (the root copy) of COMMAND.COM.

 /P means that this is the parent/root copy of the command processor.
 This option should only be used during the first execution (the root
 copy) of COMMAND.COM.

 /C <command> specifies that the DOS command <command> is to be
 executed and then the copy of COMMAND.COM will exit. This option
 should only be used during the second and subsequent (child copies) of
 COMMAND.COM.

 OS/2 installs COMMAND.COM (for the DOS compatibility mode) in the root
 directory of the boot drive, as well as in the directory \OS2. The
 CONFIG.SYS statement specifies the copy in the \OS2 directory.
 However, since the <starting_directory> option is not specified on the
 SHELL line in the CONFIG.SYS file, if the copy of COMMAND.COM is not
 present in the root directory, COMMAND.COM will not load and the DOS
 compatibility mode will halt.

 The solution to this is to modify the default OS/2 CONFIG.SYS entry
 for the SHELL statement, adding the <starting_directory> of X:\OS2,
 where X is the boot drive. Another way to keep the DOS compatibility
 mode working properly is to not delete COMMAND.COM from the root
 directory of the boot drive.

 We have requested that the following change be reviewed and considered
 for inclusion in a future release. The default CONFIG.SYS file should
 be modified to contain the following statement so that this problem
 does not occur:

    shell=c:\os2\command.com c:\os2


 488. File System Utility Cannot Delete Nested Subdirectories

 Question:

 We have found a problem with the File System Utility in the
 Presentation Manager screen.

 We created a long list of nested subdirectories. The path length of
 these subdirectories was 128 characters. When we attempted to delete
 one of the subdirectories, we were unable to. We used the delete
 option under the File menu and the system deleted the bottom three
 subdirectories in the list, but that was all; we were unable to delete
 the other subdirectories. We then went into the 3.x box to try to
 delete the subdirectories from there, but we were unable to because
 MS-DOS would not allow us to enter a path that long. Finally, we were
 able to use the MS-DOS XTree program to rename the nested
 subdirectories so that they were only one character long each, which
 shortened the path length, and we were then able to delete the
 subdirectories. We have the following questions regarding this
 problem:

 1. Is this a bug in the File System Utility?

 2. What is the maximum path length allowed under the File Manager?

 3. What is the maximum path length allowed in the 3.x box?

 Response:

 The following are answers to the above questions:

 1. Microsoft has confirmed this to be a problem with the OS/2 SDK
    (Software Development Kit) Version 1.06. We are researching this
    problem and will post new information as it becomes available.

 2. The maximum path length allowed under the File Manager and in
    protected mode is limited by the operating system. Under OS/2 1.00
    and 1.10, the maximum path length allowed is 127 characters. This
    length is subject to change and may increase in a future release.

 3. The maximum path length allowed in the 3.x box is 63 characters
    for compatibility.


 489. OS/2 SDK: Increasing Available Memory for DOS 3.x Box

 Question:

 The DOS 3.x box seems to only give applications about 467K of memory.
 Is there any way to maximize this memory?

 Response:

 There are a few things that you can do to maximize memory available in
 the 3.x box.

 The primary thing you need to do is to remove as many device drivers
 as possible. Under OS/2 1.00, all of a device driver's code and data
 must be in low memory (below 1 MB). Under OS/2 1.10, device drivers
 can have code and data above 1 MB, but it is not always as efficient
 to do so. If you are using any installable device drivers that you
 don't need, such as the COM driver, EGA driver, mouse driver, or
 vdisk, then you will be able to get more memory available in the 3.x
 box by removing these drivers from your CONFIG.SYS file. You can also
 lower the amount of memory taken up by some buffers, such as the
 buffers in the BUFFERS=, FCBS=, and THREADS= options. You should also
 be sure that your RMSIZE value is set to 640.

 It is our concern also that the DOS box have the maximum amount of
 memory available for applications, and we will be addressing this
 concern in future releases of OS/2. However, for now there is a
 contention among kernel code, buffers, and drivers, that must remain
 below the 1 MB boundary and MS-DOS applications running in the 3.x
 box.


 490. OS/2 SDK: Invocation Order of Items Placed in DosExitList()

 Question:

 How do you control the execution order of items placed in the
 DosExitList()?

 Response:

 The high byte of the first parameter, fFnCode, defines the invocation
 order in OS/2 1.10. This does not work in OS/2 1.00. It is only valid
 when the low-order byte is 1. This list determines the order in which
 the exit list routines will be invoked. Routines given a value of 0
 will be invoked first, and routines with a value of 255 will be
 invoked last. If more than one exit list routine is added with the
 same value, then the last routine added will be invoked first. The
 values used by the OS/2 components are as follows:

    Value       Component

    A0H - A8H   OS/2 Presentation Manager
    B0H         OS/2 KBD
    C0H         OS/2 VIO


 491. OS/2 SDK: ExecFlags Values for DosExecPgm() Not Documented

 The following ExecFlags values for the DosExecPgm() function call are
 not documented in the versions of QuickHelp included with the Versions
 1.05 and 1.06 OS/2 SDK (Software Development Kit):

    Value          Description

    5              The program is loaded and is not running until the
                   session manager dispatches the threads belonging to
                   the process.

    6              The process and all of its descendants will execute
                   under conditions for debugging.

 Microsoft has confirmed this to be a problem in Versions 1.05 and
 1.06. We are researching this problem and will post new information as
 it becomes available.


 492. Increasing Maximum Number of Open Files with DosSetMaxFH()

 Question:

 When implementing a database server application using named pipes, the
 following error was returned from DosMakeNmPipe():

    4 "ERROR_TOO_MANY_OPEN_FILES"

 This error occurs when the total number of pipes plus database files
 reaches approximately 15. How can we increase the maximum number of
 files that we can open?

 Response:

 The DosSetMaxFH() API can be used to set the maximum number of file
 handles a process can open. The range is from 20 to 255.


 493. OS/2 SDK 1.06 Wrongly Assumes System Is a PS/2

 The OS/2 SDK (Software Development Kit) Version 1.06 install program
 needs to know the ROM BIOS model and submodel bytes of a system, to
 determine if the system is an AT compatible system or a PS/2 (more
 properly termed an MCA architecture) compatible system. If the model
 byte has a value of FCH, the OS/2 install program checks the submodel
 byte to see if it is a recognized AT; if not, it assumes that it is a
 PS/2. The values for the submodel byte that identify a system as an
 recognized AT are 00H, 01H, 02H, 06H, and 09H. Any other submodel byte
 value causes the install program to assume that the system is a PS/2.

 For systems that cannot run or use the normal OS/2 installation
 program, a method is available for manually installing OS/2 that
 bypasses this installation program. This manual installation procedure
 is described in Section 3.1.1 of the file INSTALL.TXT, located on the
 OS/2 SDK Version 1.06 TOOLKIT1 disk.

 If the OS/2 install program wrongly assumes that the system is a PS/2,
 it tries to use the PS/2 device drivers instead of the AT drivers
 (i.e., CLOCK02.SYS is used rather than CLOCK01.SYS, and COM02.SYS is
 used rather than COM01.SYS). In general, OS/2 comes with a set of
 device drivers with "01" in them for ATs and "02" in them for PS/2s.

 When the OS/2 installation program mistakes an AT system for a PS/2
 system, it wrongly tries to copy the "02" device driver files onto the
 target system. However, on the 5.25-inch disks included with the OS/2
 SDK Version 1.06, the PS/2 "02" device drivers are not included. This
 is because IBM PS/2 systems only come with 3.5-inch disk drives. Thus,
 a set needs to be created to fool the OS/2 install program; this can
 be done by copying the set "01" files to the "02" files. If a set of
 "02" files is available, the OS/2 install program will continue to
 install OS/2 on the target system.

 However, after installation, once the OS/2 kernel is loaded, the
 kernel DOES properly identify the system as an AT and not as a PS/2;
 in such a case, the kernel will be looking for the set of "01" files.
 So, a set of valid AT-style "01" files must exist on the system. Since
 the OS/2 install program did not copy the "01" files, they must be
 copied manually, or the "02" files must be renamed. The end result is
 that a set of proper AT-style "01" device drivers exists on the OS/2
 target system in its normal "01" filenames.

 This procedure is not a supported method of installing OS/2; the
 supported procedure is to use the manual installation technique
 mentioned above and described in Section 3.1.1 of the file
 INSTALL.TXT, located on the OS/2 SDK Version 1.06 TOOLKIT1 disk. If
 the system is not 100-percent AT compatible, it may not run the IBM
 version provided with the Microsoft OS/2 SDK Version 1.06. Owners of
 such systems should contact their OEM for information regarding
 versions of OS/2 adapted for their hardware.

 There is a file in the Software Library named SYSMODEL.ARC that
 contains a program that displays the model and submodel bytes of a
 system. SYSMODEL.ARC can be found in the Software Library by searching
 for the filename, the Q number of this article, or S12239.
 SYSMODEL.ARC was archived using the PKware file-compression utility.

 SYSMODEL.ARC obtains this information by calling ROM BIOS interrupt
 15H, with AH=C0. The C source code for this program is also included.
 For more information on IBM (and 100-percent compatible) ROM BIOS
 information, refer to the reference "IBM PS/2 and PC BIOS Interface
 Technical Reference," part number 68X2260, available from IBM by
 calling (800) IBM-PCTB. Another reference that contains similar
 material is the Microsoft Press book, "Programmer's Quick Reference
 Series: IBM ROM BIOS," by Ray Duncan, ISBN 1-55615-135-7.


 494. OS/2 SDK: XMS Drivers for DOS Compatibility Mode

 The release of OS/2 provided with the Microsoft OS/2 Software
 Development Kit (SDK) does not provide a device driver for using XMS
 (eXpanded Memory Specification) memory in the DOS compatibility mode.

 The Microsoft eXpanded Memory Manager (XMM), HIMEM.SYS, will only work
 in an MS-DOS environment where the extended memory in the system is
 accessible by MS-DOS. In OS/2, all extended memory is used for
 protected mode programs, so none is available in the DOS compatibility
 box.

 It would be possible to write an XMM that supports a subset of the
 standard XMS API. This XMM would have to be a bimodal OS/2 device
 driver. The driver would allocate some extended memory, which could be
 used as extended memory blocks (EMBs), as described in the formal XMS
 document, XMS.TXT. In addition, the XMM would also be able to
 implement upper memory block (UMB) support, since these areas of
 memory are between 640K and 1 MB, an area of memory that OS/2 does not
 control. Note, however, that UMB support currently is not implemented
 in HIMEM.SYS.

 However, the high memory area (HMA) portion of XMS cannot be
 implemented, since this portion of memory must occupy the first 64K of
 extended memory (which starts at the 1 MB address). OS/2 already
 occupies that area of memory: the "high memory kernel" is loaded there
 during system startup. This area cannot be relocated to another area,
 since MS-DOS applications that use the HMA rely on it having the same
 physical address, as well as it being addressable in real mode with
 the A20 line of the 80286 or 80386 chip being enabled. These unique
 features of the HMA make it nonrelocatable.

 For more information on XMS memory, refer to the official
 specification, the "eXtended Memory Specification Version 2.0,"
 jointly developed by Microsoft Corporation, Lotus Development
 Corporation, Intel Corporation, and AST Research, Inc., which is
 available free from Microsoft by calling (800) 426-9400 (make sure
 that you ask for the supplemental XMS disk, too). The contents of the
 XMS disk, which contains a machine-readable copy of the XMS
 specification named XMS20.ARC, are available on many information
 systems and bulletin-board systems, such as the Microsoft OnLine
 Software Library and ARPAnet's SIMTEL20 archives. XMS20.ARC can be
 found in the Software Library by searching on the filename, the Q
 number of this article, or S12023. XMS20.ARC was archived using the
 PKware file-compression utility.

 For more information on the high memory area (HMA) subsection of XMS
 memory, refer to the "Microsoft Systems Journal," Volume 10, Number 6,
 November 1988, in the article titled "The High Memory Area: 64KB More
 Memory in Real Mode," by Chip Anderson, Pages 53-57.


 495. OS/2 SDK: DISKCACHE Information

 Question:

 No matter what value I set DISKCACHE to in my CONFIG.SYS file, the
 disk performance does not seem to improve. When running any normal
 programs such as the editor or the C compiler, or even just test
 programs that only read and never write, it is clear that everything
 is read from the disk on each invocation, with no discernible
 improvement in disk performance. Why is this happening?

 Response:

 This behavior is due to the cache implementation. OS/2's built-in
 cache is different in its operation than most other cache schemes you
 might be familiar with (e.g. SMARTDRV, etc.). The performance you are
 seeing is consistent with the current implementation.

 The cache algorithm passes all requests greater than the sector
 threshold (currently the threshold is seven sectors) directly to the
 disk driver, and the cache is not used. Anything over seven sectors is
 considered sequential access. There are two reasons for this; they are
 as follows:

 1. To prevent the cache from being flushed by a large read request.

 2. As alluded to above, for a large read request, the cache gets in
    the way because it will further break down the request into
    page-sized requests to suit the cache. This would further delay the
    read such that it is as fast or faster (average case) to read
    straight from the disk.

 We are looking into alternate caching methods for future releases. In
 the meantime, caches larger than 512K or 1 MB probably will not
 provide improved performance. If you want to have fast load times for
 the C compiler, etc., and you have memory to spare, we recommend using
 this memory for a RAM disk instead.


 496. OS/2 SDK: Device Driver Return Error 104 Documentation

 Question:

 When an OS/2 device driver tries to clear a system semaphore (which
 was created and set by the user, passed to the driver using an IOCtl,
 and marked in_use at task time), the DEV_HLP returns an error code of
 104 (68 hex). What does this error mean?

 Response:

 You are getting a return value that indicates the handle is invalid at
 interrupt time. Error 104 is documented in the BSEERR.H include file.

 In your device driver, you must use the SemHandle() DevHlp to convert
 the handle the user passes in the IOCtl call to a system handle the
 device driver can use at interrupt time. This is only necessary if you
 need to be able to use the semaphore at interrupt time.

 You need to do this because at task time, the handle you are passing
 is contained in the user's LDT (Local Descriptor Table). If you only
 access the semaphore during kernel mode, there will be no problem
 because the LDT is still around at that time. But at interrupt time,
 the LDT is gone and all that is left is the GDT (Global Descriptor
 Table). Thus, you no longer have addressability to the semaphore.

 The SemHandle() DevHlp will create a GDT entry for the semaphore, and
 the handle will be valid at either task time or interrupt time.


 497. OS/2 SDK 1.06: Problems on Dell 310/325 Systems with 80387s

 On some Dell 310 and 325 80386 systems, the IBM OS/2 Version 1.10
 standard edition (Microsoft OS/2 SDK Version 1.06) may not work if the
 system has an Intel 80387 Numeric Processor Extension (NPX) installed.
 Removal of this 80387 NCP allows OS/2 to work with these releases of
 OS/2. Microsoft has confirmed this to be a problem in Version 1.06 of
 the OS/2 SDK. This problem was corrected in Version 1.10 of the OS/2
 SDK.


 498. DosMuxSemWait() Example Has Mismatched Braces in IF Statement

 In the most recent version of QuickHelp, the "Microsoft OS/2 1.0
 Programmer's Reference" (Section 3.2, Pages 152-155), and the
 "Microsoft OS/2 1.1 Programmer's Reference" (Volume 3, Section 2.2,
 Pages 92-94), the example for DosMuxSemWait() has an invalid C
 statement in it. The following is the code from this example:

     DEFINEMUXSEMLIST(MuxList, 2)         /* creates structure array */
     USHORT usSemIndex;
     MuxList.cmxs = 2;
     DosCreateSem(CSEM_PUBLIC, &MuxList.amxs[0].hsem,
         "\\sem\\timer0.sem");
     DosCreateSem(CSEM_PUBLIC, &MuxList.amxs[1].hsem,
         "\\sem\\timer1.sem");
         .
         .
         .
     DosMuxSemWait(&usSemIndex, &MuxList, 5000L);
     if (usSemIndex == 1) {
         DosSemSet(MuxList.amxs[1].hsem);

 In the if() statement above, there is an opening brace but no closing
 brace. Since there is only one line of code inside the if() loop, the
 opening brace is not needed. Or, a closing brace should be added.
 Thus, to correct this, one of the following two methods can be used:

     if (usSemIndex == 1)
         DosSemSet(MuxList.amxs[1].hsem);

 or

     if (usSemIndex == 1) {
         DosSemSet(MuxList.amxs[1].hsem);
     }

 The example omitted the closing brace to imply that actual code would
 continue to perform other activities with the semaphore (such as
 setting the appropriate semaphore again). Thus, the code could be
 written more properly as follows:

     if (usSemIndex == 1) {
         DosSemSet(MuxList.amxs[1].hsem);
         .
         .
         .
     }

 Microsoft has confirmed this to be a problem in the QuickHelp included
 with the OS/2 SDK Version 1.06. We are researching this problem and
 will post new information as it becomes available.


 499. QuickHelp DosError() Sample Source Incorrectly Uses DosExit()

 In the QuickHelp entry for the DosError() API, the source code example
 uses the DosExit() API incorrectly. DosExit() is listed as follows:

    DosExit(1, EXIT_PROCESS);

 Instead, DosExit() should be listed as follows:

    DosExit(EXIT_PROCESS, 1);

 The problem is that the first and second parameters are switched.
 However, this will not affect the behavior adversely, because OS/2
 will translate this to DosExit(1,1), since EXIT_PROCESS maps out to a
 value of 1 anyway.

 Microsoft has confirmed this to be a problem in the QuickHelp included
 with the OS/2 SDK Version 1.06. We are researching this problem and
 will post new information as it becomes available.


 500. QuickHelp SYS1943: Asterisk (*) Causes GP Violation

 QuickHelp causes a general protection violation when the asterisk
 character (*) is used within the search topic field. One or more
 additional characters in the search string are usually required to
 cause this violation.

 Microsoft has confirmed this to be a problem with the QuickHelp
 included in the OS/2 SDK Versions 1.06 and 1.10. We are researching
 this problem and will post new information as it becomes available.

 The following sequence of events produces a protection violation with
 QuickHelp:

 1. Open an OS/2 full-screen command prompt screen group.

 2. At the command prompt, type the command "QH".

 3. When the "Microsoft QuickHelp" screen is displayed, type "s"
    (search).

 4. When "Enter topic to search for:" is displayed, type "*tr".

 An error window will be displayed with the session title and the
 following contents:

    SYS1943: A program caused a protection violation.

    TRAP 000D
    AX=0000 BX=0000 CX=0000 DX=04E7 BP=A520
    SI=E4E8 DI=1248 DS=0C5F ES=04E7 FLG=2A96
    CS=02FF IP=0c35 ss=0087 SP=A518 MSW=FFFD
    CSLIM=19D0 SSLIM=AB8F DSLIM=009F ESLIM=1A41
    CSACC=F8 SSACC=F3 DSACC=F3 ESACC=F3
    ERRCD=0000 ERLIM=**** ERACC=**

 You can then end the program and the session is returned to normal.


 501. OS/2 SDK: Removing Subdirectories That Contain Hidden Files

 When the removal of an otherwise empty subdirectory fails, Microsoft
 OS/2 Versions 1.00, 1.01, 1.02, 1.03, 1.04, 1.05, and 1.06 will
 return one of the following error messages:

 1. In an OS/2 screen group, the following error message will be
    returned:

       SYS0016: The directory cannot be removed

 2. In the DOS compatibility box, the following error message will be
    returned:

       Invalid path, not directory, or directory not empty

 In most cases, if either of these messages is displayed, it means
 that there is at least one file or subdirectory contained in the
 directory being deleted. However, the error message is not totally
 complete. There are two other situations when these messages will be
 generated; they are as follows:

 1. If, in one of the OS/2 screen groups or the DOS compatibility box,
    the current directory is set to that subdirectory.

 2. If there are hidden files in that subdirectory. The attributes of
    these files need to be set to unhidden and then deleted. For
    example, the Microsoft M Editor creates hidden files in a hidden
    \DELETED subdirectory. These files should only be removed using
    the EXP(unge) command included with the M Editor.

 In the first case, scan through each of the opened OS/2 screen groups
 and either change directories to another directory, or EXIT from that
 screen group. In the second case, using the EXP(unge) command may be
 helpful only if there is a hidden subdirectory named DELETED. If
 there are other hidden files or subdirectories, it may be necessary
 to use other utilities to unhide and delete the hidden files or
 subdirectories.


 502. OS/2 SDK: DosMuxSemWait() Semaphore and Event Limits

 The following information describes the semaphore and event limits
 involving the DosMuxSemWait() API.

 The MUXSEM and MUXSEMLIST data structures are defined in the Microsoft
 OS/2 SDK (Software Development Kit) include file BSEDOS.H, in the
 section around INCL_DOSSEMAPHORES. The MUXSEMLIST data structure
 contains a list of the semaphores to be acted on by the OS/2
 DosMuxSemWait() API. This MUXSEMLIST structure holds up to 16
 semaphores.

 OS/2 Version 1.10 has an upper limit of 256 system semaphores at one
 time. It also has an upper limit of up to 16 events per
 DosMuxSemWait() call. Finally, it has an upper limit of 128
 system-wide maximum number of MuxSemWait events. This information is
 summarized as follows:

    #define MAX_SYSSEM     256 /* maximum number of system semaphores */
    #define MAX_MUXEVENTS   16 /* maximum number of events per
                                  DosMuxSemWait call */
    #define MAX_MUXENTRIES 128 /* total system wide maximum number of
                                  MuxSemWait events */


 503. Bound Executable File Clears Command Line Buffer in MS-DOS

 Question:

 Why does a bound executable file clear the command-line buffer in
 MS-DOS Version 4.00? Even the most simple C program, when made a FAPI
 with BIND.EXE, clears the F3 buffer after the program has finished
 executing.

 Response:

 The COMMAND.COM command-line buffer is being cleared because the bound
 application is allocating all of MS-DOS memory, or at least enough to
 cause COMMAND.COM to be reloaded. The transient portion of
 COMMAND.COM, sitting at the top of available memory, gets written
 over, causing COMMAND.COM's resident portion to reload the transient
 portion. The transient portion of COMMAND.COM is where the
 command-line buffer information is stored.

 This problem does not occur with the COMMAND.COM of OS/2's DOS
 compatibility mode, but it DOES occur with normal MS-DOS. This
 difference is not easily explainable; the DOS compatibility mode
 appears to be better suited to accept these bound files. The stub
 loader that is used while running under DOS to load/exec the OS/2 EXE
 code/data that is in this bound executable file behaves differently
 when running in the OS/2 DOS compatibility mode as opposed to "normal"
 DOS.


 504. DosCaseMap() Case Error and DosGetMessage() Missing in API.LIB

 Problem:

 In the library API.LIB, DosCaseMap() is not all caps, as required for
 PASCAL calling conventions. Also, DosGetMessage() is not listed in
 API.LIB.

 Response:

 The code for DosGetMessage() is actually in OS2.LIB, the
 protected-mode library. Most of the APIs in this library do not have
 any actual code and are only import definition records, but
 DosGetMessage() is an exception. There is a small routine here that
 calls the routine DosTrueGetMessage(), and the code for
 DosTrueGetMessage() is in API.LIB. The problem that you are seeing
 only occurs when you try linking directly to the FAPI (Family API)
 library, API.LIB rather than using it in conjunction with the BIND
 utility. For some of the routines in API.LIB to work properly, it is
 necessary that a piece of start-up code be executed. This start-up
 code is placed into the .EXE file as part of the binding process. It
 will not be present if a program is compiled for MS-DOS and is linked
 with the API.LIB library. The only way to ensure that the routines in
 API.LIB function properly is to compile the program for OS/2 (although
 this can be done while running under MS-DOS with the -Lp command line
 parameter to the C compiler) and then using the BIND utility to bind
 the program for use in both OS/2 and MS-DOS. When used this way,
 DosGetMessage() is properly resolved.

 In a similar manner, the problem with the case of the APIs in API.LIB
 is resolved when you bind. The BIND utility does not consider case as
 significant when binding an application, and so it properly resolves
 the calls to the MS-DOS routines in API.LIB that are in mixed case. As
 a matter of consistency, however, we have suggested that the case be
 changed to all uppercase for the DosCaseMap() API, as well as any
 other APIs that have this problem, in a future release of the product.


 505. Cannot Use KbdSetStatus with fsMask Set to 0x000A in Real Mode

 Problem:

 When I use KbdSetStatus() and set the second parameter, fsMask, to
 cooked mode on and echo mode off (Ox000A), I get the following error
 message when I run my program in real mode:

    378 ERROR_KBD_INVALID_INPUT_MASK

 This error is not returned when I run my program in protected mode.

 Response:

 This set of parameters is not supported in real mode. We have asked
 that this information be added to the "Microsoft Operating System/2
 Programmer's Toolkit Programmer's Reference" Version 1.00 manual and
 QuickHelp.


 506. Using Old MS-DOS Device Drivers under OS/2

 Question:

 Can old MS-DOS device drivers be used under OS/2?

 Response:

 Yes, some old MS-DOS device drivers can be used in OS/2. They would
 need to be loaded in the OS/2 CONFIG.SYS file. However, not all MS-DOS
 device drivers can be used. Block device drivers cannot be loaded
 (thus, only MS-DOS character drivers can be loaded). The MS-DOS
 character device driver cannot have a hardware interrupt handler
 (i.e., the device must be POLLED rather than interrupt-driven). Also,
 the MS-DOS character device driver cannot have exclusive control of
 some types of hardware, such as the mouse or the clock. This
 information is also documented in the "Microsoft Operating System/2
 Device Drivers Guide" in Section 1.13, "Compatibility with Old Device
 Drivers."


 507. OS/2 SDK: Resizing the SWAPPER.DAT File

 Question:

 I am using OS/2 Version 1.10 with 3.5 MB of memory. I am using OS/2
 heavily and my SWAPPER.DAT file has reached 1.7 MB. Does this file
 keep growing indefinitely?

 Response:

 Under OS/2 1.10, rebooting the machine will cause the SWAPPER.DAT file
 to be resized to its default size, which is about 650K. There is no
 way to shrink the size of the SWAPPER.DAT file during a session of
 OS/2.

 Under OS/2 1.00, the size of the SWAPPER.DAT file does not change when
 the system is rebooted. One way to reduce the SWAPPER.DAT file to its
 default size is to boot with a different operating system (e.g.
 MS-DOS), delete the SWAPPER.DAT file, and then reboot OS/2.

 You can also delete the SWAPPER.DAT file under OS/2 1.00 without
 booting MS-DOS. To do this, change the SWAPPATH environment variable
 to  something else, and then reboot OS/2. You can then delete the
 SWAPPER.DAT file and set the SWAPPATH environment variable back to its
 original setting.


 508. DosFindNext() Searches Incorrect Subdirectory in Version 1.06

 There is a problem when calling DosFindFirst()/DosFindNext() on the
 root directory of a drive in which the first entry in the root
 directory is a subdirectory (not a file). With only DosFindFirst()/
 DosFindNext(), this works as expected. When _beginthread() is called
 immediately before the DosFindFirst()/DosFindNext() code,
 DosFindFirst() works properly (finding the first subdirectory entry).
 However, DosFindNext() incorrectly shifts down to begin looping into
 the files of this first subdirectory, instead of continuing with the
 second and subsequent entries in the root directory, as expected.

 Using DosCreateThread() instead of _beginthread() will result in
 the same problem.

 Microsoft has confirmed this to be a problem with the DosFindNext()
 function call in the Version 1.06 OS/2 SDK (Software Development Kit).
 We are researching this problem and will post new information as it
 becomes available.

 Another issue to complicate the problem is that the first run of
 this sequence of function calls will fail (as expected). However,
 the second and subsequent runs of this sequence of function calls
 will work (unexpectedly). To get this problem to occur reliably, a
 large program must be run to flush the system. If you execute "cl
 -help" between each run of this sequence of function calls, the
 problem will occur consistently. Under MS-DOS, this symptom could be
 explained by uninitialized variables that the first sequence of
 function calls initializes, and the second and subsequent sequence of
 function calls can use, while executing CL.EXE in this case can
 be used to flush memory back to an uninitialized state. However, this
 situation is not as easily explained under OS/2.

 One workaround for this problem is to call DosSleep() to allow the
 system to coalesce the newly created thread after creating the thread
 and before beginning the DosFindFirst()/DosFindNext() loop, thus not
 interfering with the DosFindFirst()/DosFindNext() loop. For example,
 with this delay after creating the thread, the DosFindFirst()/
 DosFindNext() loop will properly find all files on the root directory,
 regardless of whether or not the first entry is a subdirectory. If you
 use DosSleep() with a value of 500L, the problem seems to be
 eliminated.


 509. Product Purchase Information for International ISVs and IHVs

 International ISVs and IHVs that wish to obtain OS/2 and LAN Manager
 products such as the OS/2 SDK (Software Development Kit), OS/2 DDDK
 (Device Driver Development Kit), and SQL NDK (Structured Query
 Language Network Development Kit) should contact their nearest
 Microsoft subsidiary office. If the subsidiary does not distribute the
 product you want to purchase, contact the domestic US Microsoft
 International Customer Service at the following number:

    +1 (206) 882-8661

 They can obtain Microsoft licensed products that are not handled by a
 regional Microsoft subsidiary office.


 510. OS/2 SDK: SPOOL.EXE and PMSPOOL.EXE Information

 Question:

 What is the difference between PMSPOOL.EXE and SPOOL.EXE. Are they
 linked together at all?

 Response:

 PMSPOOL.EXE and SPOOL.EXE divide up the functionality of the PM
 (Presentation Manager) spooler. PMSPOOL.EXE is the visual interface
 of the spooler. It is what puts the icon on the screen and processes
 the messages. No spool queue management is done by PMSPOOL.EXE, and
 the OS2.INI file is not updated to reflect that the spooler is active
 at boot-up time if this is the only file that is loaded.

 SPOOL.EXE is the spool queue manager. It accepts and dispatches print
 jobs. It also changes the OS2.INI file and marks the spooler as
 active.

 SPOOL.EXE calls PMSPOOL.EXE after the queues are set up to give the
 spooler the visual interface that it needs to be operative under PM.

 If you type "PMSPOOL" at the command prompt, you will get the visual
 interface, but not the spooler itself. It will appear to be there
 (visually), but actually will not be.


 511. OS/2 SDK: "usNumSeg" Value Incorrect in DosAllocHuge() Example

 Microsoft has confirmed that there is a documentation error involving
 the DosAllocHuge() function call example on Page 49 of the "Microsoft
 Operating System/2 Programmer's Toolkit Programmer's Reference Version
 1.0" manual, and in the version of QuickHelp included with the Version
 1.06 OS/2 SDK (Software Development Kit).

 The example on Page 49 states that the "usNumSeg" parameter should be
 set to "3". It should be instead set to "2", since the example is
 allocating only two segments that are 64K in size, and the third
 segment is only 200 bytes.


 512. DosClose() Invalidates File Handle If Drive Door Is Open

 Question:

 There seems to be a problem with the DosClose() function. If I attempt
 a DosClose() with a file handle for a floppy-disk file, and the
 floppy-disk door is open, I get a pop-up window asking me whether to
 end, retry, or return the error to the program. If I choose to return
 the error, close the floppy-disk door, and do another DosClose() with
 that file handle, I get an error indicating that the file handle is
 invalid. Since the file has not been closed, why is the file handle
 considered invalid?

 Response:

 When the floppy disk is removed from the disk drive, the system is in
 an inconsistent state. There is no way to tell which floppy disk is in
 the disk drive; therefore, the file handle is invalidated. This occurs
 because even though OS/2 writes a serial number on the floppy disk,
 MS-DOS Version 3.30 does not. This would cause problems if OS/2
 counted on the serial number. Also, if the MS-DOS Version 3.30 DISKCOPY
 utility copied the floppy disk with the same serial number and then
 the first floppy disk were modified, the second floppy disk could be
 put in the disk drive at a critical point and OS/2 would not be able
 to tell that the wrong floppy disk was in the disk drive.


 513. OS/2 SDK: Interpreting Trap Information

 Question:

 Our OS/2 machine had a trap occur. The registers were dumped and then
 the system halted. Where can I find documentation that tells me why
 this happened? Also, how can I interpret the dump information?

 Response:

 Most of the information from this trap dump is a raw dump of the Intel
 80286 register set. Chapter 9 ("Interrupts and Exceptions") in the
 "Intel 80286 Software Reference" manual is the best reference for this
 register set; the manual explains how to interpret the register set.

 One thing OS/2 puts in the dump that is not in the 80286 register set
 is the OS/2 session ID.

 The following is a list of what to look for in the register dump:

 1. Check the ring level. Bits 5 and 6 of the CSACC byte contain the
    descriptor privilege level (DPL), also known as the ring level.
    For more information on DPL, refer to Figure 6-7 of the "Intel
    80286 Programmer's Reference" manual. If the ring is 3, then the
    trap most likely came from an application. If the ring is 0, then
    the trap probably came from a device driver or the OS/2 kernel.

 2. Check to see if the LDT (local descriptor table) or GDT (global
    descriptor table) is being referenced.

 3. Check to see if the segment registers are nonzero, which they
    should be.

 4. Check to see if the SP is beyond the SS.

 5. Check to see if ES or DS contain an "*" (asterisk); it could be
    pointing to an invalid selector.

 Again, Chapter 9 of the "Intel 80286 Programmer's Reference" manual
 describes the many 80286 traps and exceptions that could possibly
 cause a dump to occur.


 514. Next Scheduling Opportunity for Blocked High-Priority Thread

 Question:

 When will a blocked high priority thread be given control following a
 DevHlp Run? The documentation refers to the "next scheduling
 opportunity," but doesn't define it.

 Response:

 The OS model we have has two modes: user and kernel. User mode occurs
 when the processor is executing user application ring 2 or ring 3
 code. Kernel mode occurs when the processor is executing ring 0 code.
 Whenever the CPU transitions from kernel to user mode, or when a
 process in kernel mode calls internal scheduler routines to yield the
 CPU to another thread or to block until an event occurs, these are the
 "scheduling opportunities" we look for so that higher-priority threads
 are allowed to be executed.


 515. OS/2 SDK: Interrupt Latency Information

 Question:

 What is the longest possible interrupt latency?

 Response:

 The theoretical limit is infinite. The lowest-priority interrupt can
 be prevented from being executed by higher-priority interrupt
 saturation.


 516. OS/2 SDK: Intercepting File I/O or DLL Calls

 Question:

 I have the following questions on intercepting file I/O or DLL calls:

 1. Is it possible to intercept file I/O calls before they go through
    the file system and either do some other processing or pass the
    call on to the file system unaltered?

 2. Is it possible to intercept DLL (dynamic linked library) calls by
    providing a DLL with the same function entry points (same names)?

 Response:

 The following are answers to the questions listed above:

 1. File I/O calls are entries into OS/2 system DLLs. See the answer
    below for more information on this topic.

 2. OS/2 provides no mechanism for intercepting a DLL entry. In terms
    of most OS/2 APIs, this means that OS/2 provides no mechanism for
    intercepting an OS/2 API. However, SOME OS/2 APIs, and many of the
    KBD and VIO APIs, have been designed so that they CAN be replaced.
    Other than these APIs, which have been designed to provide an
    interface for replacing (and/or intercepting) them, none of the
    other OS/2 APIs have a mechanism to be intercepted. In more general
    terms, this applies to function entry points in a DLL. Intercepting
    a DLL entry is possible if a DLL is designed so that it can be
    replaced (such as the VIO and KBD entry points in the OS/2 system
    DLLs). Otherwise, there is no other mechanism you can use to do
    this.

    Intercepting a DLL entry might be done in a situation where a
    function was behaving improperly. A reasonable thing to do would be
    to replace the DLL. This is one advantage of DLLs, since they are
    modular and easily replaceable portions of a program.

    The entry point of a DLL can be obtained by using
    DosGetProcAddr() after using DosLoadModule() on a DLL.

 An application can reroute the way that a DLL function enters itself
 (but not for other applications). It is possible for a program to
 reroute a DLL function by using the IMPORT statement of the .DEF
 file. The application can change the entry point for the program to
 another name. For example, a function called DosFooBar() could be
 mapped into DosFubar(). Then, the application could create its own
 function and name it DosFooBar(), which could perform its own tasks,
 and then turn around and call the REAL function, which it knows as
 DosFubar(). This technique is useful for debugging purposes. For
 example it could be used to show a count of file handles by rerouting
 DosOpen() to RealDosOpen(), then have a stub DosOpen() which displays
 the request information, passes the request to RealDosOpen(), and then
 displays the file handle after RealDosOpen() returns. This method can
 be used by an application for its own view of DLL entry points. It
 cannot be used by child processes or other programs running. This
 technique does not allow applications to take over the system, however.


 517. OS/2 SDK: BPB BIOSPARMETERBLOCK Documentation Error

 Microsoft has confirmed that the BPB structure definition documented
 in the QuickHelp included with the Version 1.06 OS/2 SDK (Software
 Development Kit) is incorrect.

 Listed below is the correct documentation for this structure:

 typedef struct _BIOSPARAMETERBLOCK {    /* bspblk */
     USHORT usBytesPerSector;
     BYTE   bSectorsPerCluster;
     USHORT usReservedSectors;
     BYTE   cFATs;
     USHORT cRootEntries;
     USHORT cSectors;
     BYTE   bMedia;
     USHORT usSectorsPerFAT;
     USHORT usSectorsPerTrack;
     USHORT cHeads;
     ULONG  cHiddenSectors;
     ULONG  cLargeSectors;
     BYTE   abReserved[6];
     USHORT cCylinders;
     BYTE   bDeviceType;
     USHORT fsDeviceAttr;
 } BIOSPARAMETERBLOCK;

 The BIOSPARAMETERBLOCK structure contains BIOS parameter blocks.

    Parameters          Description
    ----------          -----------

    usBytesPerSector    Specifies the bytes per sector.

    bSectorsPerCluster  Specifies the sectors per cluster.

    usReservedSectors   Specifies the reserved sectors.

    cFATs               Specifies the number of file-allocation tables.

    cRootEntries        Specifies the maximum number of entries in the
                        root directory.

    cSectors            Specifies the number of sectors.

    bMedia              Specifies the media descriptor.

    usSectorsPerFAT     Specifies the number of sectors per
                        file-allocation table.

    usSectorsPerTrack   Specifies the number of sectors per track.

    cHeads              Specifies the number of heads.

    cHiddenSectors      Specifies the number of hidden sectors.

    cLargeSectors       Specifies the number of large sectors.

    abReserved[6]       Specifies six reserved bytes. These must be zero.

    cCylinders          Specifies the number of cylinders defined for
                        the device.

    bDeviceType         Specifies the type of device. It can be one of
                        the following values:

                        Value            Meaning
                        -----            -------

                        DEVTYPE_48TPI    48 tracks-per-inch, low-density
                                         floppy-disk drive

                        DEVTYPE_96TPI    96 tracks-per-inch, high-density
                                         floppy-disk drive

                        DEVTYPE_35       3.5-inch (720K) floppy-disk drive

                        DEVTYPE_8SD      8-inch, single-density
                                         floppy-disk drive

                        DEVTYPE_8DD      8-inch, double-density
                                         floppy-disk drive

                        DEVTYPE_FIXED    Fixed disk

                        DEVTYPE_TAPE     Tape drive

                        DEVTYPE_UNKNOWN  Other (unknown type of device)

    fsDeviceAttr        Specifies information about the drive. If this
                        value is 0x0001, the media are not removable. If
                        it is 0x0002, the media can detect changes. This
                        field can be one or both of these values.

 See Also

 DSK_GETDEVICEPARAMS, DSK_SETDEVICEPARAMS


 518. OS/2 Initialization File Information

 The following is a list of detailed information concerning the major
 OS/2 initialization files:

 CONFIG.SYS:    This file is read once by OS/2 when the system boots,
                and is used to determine many system characteristics.

 STARTUP.CMD:   This file is run once by OS/2 when the system starts,
                and is used to run programs that only need to be run
                once during the lifetime of a system, such as starting
                a network.

 AUTOEXEC.BAT:  This file is run once by OS/2's DOS compatibility mode
                the first time the DOS screen group is selected, just
                as with MS-DOS systems.

 OS2.INI:       This file is used by Presentation Manager (PM) and PM
                applications. It is an initialization file similar to
                the Microsoft Windows file WIN.INI. However, while
                WIN.INI is an ASCII file, OS2.INI is a binary file,
                and it is not easy to directly manipulate this file.
                Instead, you can use the OS/2 APIs such as
                WinQueryProfileData(), WinQueryProfileInt(),
                WinQueryProfileSize(), WinQueryProfileString(),
                WinWriteProfileData(), and WinWriteProfileString() to
                change OS2.INI. For more information on these APIs,
                refer to the "Microsoft OS/2 Programmer's Reference"
                manual.

 OS2INIT.CMD:   This file is run every time a new copy of CMD.EXE is
                executed. This file name is NOT hard coded in OS/2; the
                name is user-configurable. In previous releases of
                OS/2, the CONFIG.SYS PROTSHELL statement used the /K
                switch of CMD.EXE, followed by the filename of
                OS2INIT.CMD. Thus, whenever a copy of CMD.EXE was
                executed, the OS2INIT.CMD file was run. One reason why
                this was useful was that in OS/2 1.00, environment
                variables were not inherited by child processes, and
                OS2INIT.CMD was used to re-SET all of the standard
                environment variables. However, in OS/2 1.10,
                environment variables can now be SET in CONFIG.SYS, and
                these variables are the default variables passed to all
                processes (unless the parent wants to send something
                else to its children). Therefore, the use of
                OS2INIT.CMD in this manner is not as useful in OS/2
                1.10 as it was in 1.00. Thus, the default installation
                of OS/2 does not include "/K OS2INIT.CMD" after CMD.EXE
                in the PROTSHELL statement, as in previous releases of
                OS/2. However, you may add this information back to
                your PROTSHELL statement if you wish to use it.


 519. Communication between the DOS 3.x Box and an OS/2 Session

 Question:

 I have a program running in the DOS 3.x box, which communicates with
 OS/2 processes through a "common" memory area (the physical address
 is converted to a selector by a simple OS/2 device driver). I have the
 following questions about the DOS 3.x box:

 1. How can a program in the DOS 3.x box yield to OS/2?

 2. What is the priority of the DOS 3.x box?

 3. Is there a fast way to allow communication between a program
    running in the DOS 3.x box and an OS/2 session?

 Response:

 Listed below are the answers to the above questions:

 1. A program in the DOS 3.x box can be made to yield to OS/2 by
    calling DosSleep(0L) from your DOS FAPI application. Otherwise,
    there is no way to give up your time slice.

 2. The priority of the DOS 3.x box is approximately the same as a
    normal OS/2 foreground application, with added boosts to its
    priority based on the fact that it is the DOS 3.x box and may have
    applications that are time dependent. Very high priority threads
    and interrupts may run before the DOS 3.x box will run. However,
    the DOS 3.x box will be running most of the time when it is in the
    foreground.

    In the background, the DOS 3.x box has no priority and receives no
    time slices.

 3. There aren't very many ways to communicate between the two sessions,
    as this is not done very often. The DOS application must poll to be
    able to communicate with an OS/2 session because no IPC (Inter-
    Process Communication) mechanisms are allowed in the DOS 3.x box.

    However, since OS/2 does have IPC mechanisms (namely semaphores),
    you could instead write a device driver to handle the memory
    sharing. Then, the OS/2 application could wait on a semaphore
    instead of having the DOS application do polling. When data is
    available, the device driver could clear the semaphore and let the
    OS/2 application run.


 520. Do NOT Use Device Monitors in the PM Screen Group

 Character device monitors should ONLY be used in full-screen screen
 groups used by full-screen VIO applications. Do not count on character
 device monitors [e.g. APIs such as DosMonReg()] working in the
 Presentation Manager screen group. Monitoring character devices using
 the DosMon* APIs may not work in future releases of OS/2. In the
 future, all attempts to register a monitor for these screen groups
 should fail.

 A monitor in the Presentation Manager screen group cannot monitor
 device activity for an individual application. It must monitor all
 programs currently running in this screen group. This makes using a
 monitor in the Presentation Manager screen group impossible. Monitors
 are only useful for VIO applications running in full-screen groups.
 Advanced VIO (AVIO) and Presentation Manager applications running in
 the Presentation Manager screen group don't have to worry about the
 inability to use the DosMon* APIs: they can use the message queues
 provided by the Presentation Manager to obtain the analogous
 information as a monitor. This sort of message "monitoring" is the
 recommended method in this screen group.


 521. Using Charles Petzold Sample Code in Production Application

 Question:

 What is your position regarding the use of the sample code copyrighted
 by Microsoft and Charles Petzold in a production application?

 Response:

 The book "Programming the OS/2 Presentation Manager" by Charles
 Petzold is distributed by Microsoft Press. Mr. Petzold has royalty
 contracts from Microsoft Press for his code. Therefore, the use of
 this code is more restrictive than the other sample code from the OS/2
 Software Development Kit (SDK).

 To obtain legal permission to use code from any of Petzold's sample
 programs from his PM book, write to Microsoft Press at the following
 address:

    Microsoft Press
    Attn: Susan McRhoton
    16011 NE 36th Way
    Box 97017
    Redmond, WA 98073-9717

 The letter should include a description of your product, the number of
 copies you expect to distribute, the cost of the product, the source
 module you want to use, and the percentage of the source code you are
 going to use. Microsoft Press will either grant or deny your request.


 522. OS/2 SDK: Adding to PM Main Menu with WinAddProgram()

 Question:

 I would like to add an entry to the OS/2 Presentation Manager's main
 menu using the WinAddProgram() function. Can I do this from a
 character-based application? WinAddProgram() doesn't work consistently
 if I haven't done a call to WinCreateMsgQueue().

 Response:

 WinAddProgram() is meant to be used by Presentation Manager (and AVIO)
 applications. VIO applications (windowable and full-screen) have no
 concept that they are running in the Presentation Manager
 windowable, graphical environment, and therefore don't have access to
 modify this environment.


 523. OS/2 SDK: Installing New Versions of DLLs in CONFIG.SYS

 Question:

 Can I install new versions of DLLs (dynamic linked libraries), such as
 DISPLAY.DLL, without booting the computer with MS-DOS?

 Response:

 Yes, you can install new versions of DLLs; however, there are a few
 things you should be aware of. Once a DLL is loaded, OS/2 locks it so
 you can't change it. The environment variable that is used for
 locating the DLL is the LIBPATH variable that is specified in
 CONFIG.SYS.

 The following method will allow you to change DISPLAY.DLL without
 booting the computer with MS-DOS:

 1. Add another directory path before the original directory path to
    the LIBPATH line in CONFIG.SYS. For example:

       Original LIBPATH statement: LIBPATH=C:\OS2\DLL
       New LIBPATH statement:      LIBPATH=C:\NEWDLL;C:\OS2\DLL

 2. Place the new version of DISPLAY.DLL in C:\NEWDLL.

 3. Reboot the computer.

 The new version of DISPLAY.DLL will be loaded first because it is
 located earlier in the LIBPATH statement than the old version of
 DISPLAY.DLL. This procedure can then be reversed to replace the
 version of DISPLAY.DLL that was originally being used and to restore
 the LIBPATH back to its original state.


 524. Keyboard Monitors Not Supported in the Compatibility Box

 Question:

 The keyboard monitor that I wrote works correctly with a
 protected-mode screen group. Will I be able to use this same keyboard
 monitor to monitor keystrokes for the compatibility-box screen group
 from a protected-mode process?

 Response:

 Keyboard monitors are not supported in the compatibility box. To
 accomplish what you are trying to do, we suggest that you write a
 terminate-and-stay-resident (TSR) program in the compatibility box
 that emulates the keyboard monitor you are using with a protected-mode
 screen group.

 If you want to communicate between the two modes (compatibility and
 protected), write a shared-memory device driver that both the
 real-mode TSR monitor and the protected-mode monitor can read and
 write to.


 525. OS/2 SDK: Using WINDOWAPI in Module Definition File

 Problem:

 When I build and run the program listed below, I get a directory
 listing in the window that I started the program from. However, if I
 change the line in the module definition file from WINDOWCOMPAT to
 WINDOWAPI and rebuild the program, the program returns me to the
 command prompt.

 Program
 -------

 #include <stdio.h>
 #include <process.h>

 main()
 {
     spawnl(P_WAIT, "C:\\OS2\\CMD.EXE", "C:\\OS2\\CMD.EXE",
            "/c dir", NULL);
 }

 Module Definition File
 ----------------------

  NAME           os2stub   WINDOWAPI

 PROTMODE

 Response:

 This is expected behavior. When you use the WINDOWAPI setting, you are
 telling the linker that this is a Presentation Manager (PM)
 application. However, your application is not a PM application if it
 has no application window, no message queue, etc. When your
 application is run, the system switches to the PM display to start the
 program (this is where all PM applications are run from). Because
 there is no code for your application that is relevant to PM, the
 application returns.

 You should use the "WINDOWCOMPAT" option in your module definition
 file.


 526. Address Space of Physical Video Buffer Using VioGetPhysBuf()

 Question:

 I am using VioGetPhysBuf() to perform physical video I/O in an OS/2
 VIO application. The VIOPHYSBUF structure that this API uses has the
 following field in it:

     SEL asel[1];

 This field is an array of selectors to point to the PVB (physical
 video buffer). This array is only defined to be 1. I need to use two
 selectors, thus getting up to 128K of PVB access space. How can I use
 the VIOPHYSBUF structure definition to accomplish this?

 Response:

 The "Microsoft Operating System/2 Programmer's Toolkit Programmer's
 Reference" for Version 1.00 documentation for the "VIOPHYSBUF.asel"
 field states the following on Page 338:

    Specifies an array that receives the selectors used to address the
    physical video buffer. If more than one selector is received, the
    first selector addresses the first 64K bytes of the physical video
    buffer, the second selector addresses the next 64K bytes, and so
    on. The number of selectors depends on the actual size of the
    physical buffer as specified by the cb field. The last selector may
    address less than 64K bytes of buffer.

 The "Comments" section for this data structure states the following:

    The actual size of the asel[1] field depends on the size of
    physical memory. The program must ensure that there is adequate
    space to receive all selectors.

 Because of current architecture limitations, the PVB is located in the
 region from A000H to C000H in the system memory map, which limits to
 two the maximum number of selectors that this API can use. Generally,
 the first selector points to the 64K region starting at A000H, and the
 second selector points to the 64K region starting at B000H. To address
 a video adapter that supports an address space larger than 128K, you
 must page banks of up to 128K memory, one bank of memory at a time
 (e.g. one bitplane at a time).

 The problem is how to use two selectors instead of only one. The
 VIOPHYSBUF structure is defined in the include file BSESUB.H, which is
 included with the Microsoft OS/2 Software Development Kit (SDK) and
 the OS/2 Programmer's Toolkit (PTK). The definition for this structure
 is as follows:

     typedef struct _VIOPHYSBUF {    /* viopb */
         PBYTE    pBuf;
         ULONG    cb;
         SEL      asel[1];
     } VIOPHYSBUF;
     typedef VIOPHYSBUF far *PVIOPHYSBUF;

 The "VIOPHYSBUF.asel" field is typical of how a C structure is mapped
 onto a data structure that has a variable-length array at the end.
 This is about the closest that C can come to handling this kind of
 situation, and does not imply that the dimension of the array is "1".

 In addition to the VIOPHYSBUF structure, another example of this kind
 of data structure in the OS/2 PTK include files is the TRACKFORMAT
 structure. The definition of this structure is as follows:

     typedef struct _TRACKFORMAT {    /* trckfmt */
         /* ... some fields omitted here ... */
         struct {
             BYTE bCylinder;
             BYTE bHead;
             BYTE idSector;
             BYTE bBytesSector;
         } FormatTable[1];
     } TRACKFORMAT;

 For example, to allocate TWO selectors using the existing definition
 of the VIOPHYSBUF structure, allocate a buffer area big enough to
 handle the largest dimension that you want to use. Then, cast a
 pointer to this area to be a pointer of this type and use however many
 elements of the array that were there. For example, the allocation
 could be as follows:

   PVIOPHYSBUF pviopb;
   USHORT cElements = 2;

   pviopb = (PVIOPHYSBUF)malloc(sizeof(VIOPHYSBUF) + ((cElements - 1)
             * sizeof(SEL)));

 In the above calculation, the subtraction of 1 from cElements is used
 because one array element is included in the sizeof(VIOPHYSBUF) value,
 which is the SEL asel[1] field.

 Alternately, you could have two VIOPHYSBUF structures allocated in
 your program, and each one could only have a single selector to a
 portion of the PVB. Then, your application could call VioGetPhysBuf()
 multiple times to obtain these selectors.

 For more information on video hardware programming, refer to the
 hardware technical reference document(s) for your video adapter. In
 addition to the vendor-supplied hardware technical reference
 document(s) on the video adapter, many books are available that
 discuss register-level programming for popular video adapters such as
 the EGA and VGA. The MANDEL example, included with some versions of
 the OS/2 SDK and OS/2 PTK, demonstrates how to write a base VIO
 application that performs register-level programming of the EGA
 adapter.


 527. OS/2 SDK: Older Definition of VIOMODEINFO Structure Invalid

 The proper definition for the VIOMODEINFO structure, as defined in
 BSESUB.H, is as follows:

     typedef struct _VIOMODEINFO {   /* viomi */
         USHORT cb;
         UCHAR  fbType;
         UCHAR  color;
         USHORT col;
         USHORT row;
         USHORT hres;
         USHORT vres;
     } VIOMODEINFO;
     typedef VIOMODEINFO FAR *PVIOMODEINFO;

 The "VIOMODEINFO.cb" field is defined as the sizeof(VIOMODEINFO),
 which is 12 bytes, not 14. The "Microsoft Operating System/2
 Programmer's Reference Volume 3" for Version 1.10 describes this field
 on Page 370, with the following information:

    Specifies the length of the [VIOMODEINFO] data structure (in
    bytes). This field must be set to 12.

 Older versions of BSESUB.H (for example, the version included with the
 Microsoft C Compiler Version 5.10) incorrectly show the "fmt_ID" and
 "attrib" fields at the end of this structure. These two fields should
 not be there. The include files from a recent Microsoft OS/2 Software
 Development Kit (SDK) or OS/2 Programmer's Toolkit (PTK) should be
 used instead; they are more up-to-date than the Microsoft C Compiler's
 OS/2-specific include files or very old OS/2 SDK include files.

 In summary, do not use the "fmt_ID" and "attrib" fields. Also, the
 "cb" field should be set to the proper sizeof(VIOMODEINFO), which is
 12 bytes.


 528. OS/2 SDK: CBIOS and ABIOS Information and References

 This article summarizes the terms CBIOS and ABIOS, and provides ABIOS
 reference information for writers of OS/2 device drivers.

 In this context, the term BIOS stands for "Basic Input/Output System".
 It is the ROM code in the IBM Personal Computer (and OEM-compatible)
 systems. This is also commonly referred to as the "PC ROM BIOS". The
 BIOS provides a set of low-level services, which manipulate the
 system's hardware. On PC-compatible versions of MS-DOS, the MS-DOS
 kernel issues calls to the ROM BIOS in order to complete I/O requests.

 The BIOS can only be used in real mode of an Intel 80286 or 80386 CPU
 (the Intel 8086 only operates in real mode.) In general, these
 real-mode system services are not reentrant, and they are limited to
 using memory under the 1 MB address space (not being able to use
 extended memory). When the PS/2 family of computers was released, a
 new term called "Compatibility BIOS" or "CBIOS" was given to the BIOS.
 The term ABIOS stands for "Advanced Basic Input/Output System," or
 "Advanced BIOS," termed when IBM released their Personal System/2
 family of computers. This set of system services are bimodal; that is,
 they will operate in the real mode of the 80286 and 80386, as well as
 in protected mode. A PS/2 system has both a BIOS and an ABIOS.

 On PS/2 (and compatible) systems that have an ABIOS, Microsoft
 releases of OS/2 do NOT use the ABIOS system services. Instead, the
 OS/2 device drivers bypass the ABIOS abstraction layer and talk
 directly with the hardware, as with the PC/AT family of computers
 (which do not have ABIOS). On IBM PS/2 systems, IBM releases of OS/2
 may use the ABIOS system services. The ABIOS-specific DevHlps will
 fail if the OS/2 kernel does not use the ABIOS interface to the
 hardware. Thus, the ABIOS DevHlps are not available on non-ABIOS
 systems, such as PC/ATs.

 Implementations of OS/2 that use the ABIOS as an abstraction layer to
 communicate with the hardware will support four DevHlp device driver
 helper routines. These DevHlps are as follows:

    DevHlp Service    Code

    FreeLIDEntry      34H
    GetLIDEntry       35H
    ABIOSCall         36H
    ABIOSCommonEntry  37H

 As stated above, if the OS/2 kernel does not support ABIOS, these
 ABIOS-specific DevHlps will return failure. Information on these
 DevHlps is listed in the technical references provided by Microsoft,
 IBM, and OS/2 OEMs; some of these references are listed below.

 The following is a list of reference information available for CBIOS
 programmers:

    "IBM PS/2 and PC BIOS Interface Technical Reference"
    IBM Corporation
    Part number 68X2260
    1987
    [This document can be ordered from IBM by calling (800) IBM-PCTB.]

    "IBM PS/2 Seminar Proceedings"
    IBM Corporation
    May 1987
    Volume 5, Number 4
    Pages 16-23: Compatibility BIOS

    "Programmer's Quick Reference Series: IBM ROM BIOS"
    Ray Duncan
    Microsoft Press
    1988
    ISBN 1-55615-135-7

 Also refer to the hardware technical reference for your computer. Many
 of these references include the source code listing to the ROM BIOS.
 In addition to these references, there are many third-party books
 whose primary topic is MS-DOS programming. Many of these books discuss
 using CBIOS.

 The following is a list of general reference information available for
 ABIOS programmers:

    "Advanced BIOS Supplement"
    "IBM PS/2 and PC BIOS Interface Technical Reference"
    IBM Corporation
    Part number 68X2288
    1987
    [This document can be ordered from IBM by calling (800) IBM-PCTB.]

    "IBM PS/2 Seminar Proceedings"
    IBM Corporation
    May 1987
    Volume 5, Number 4
    Pages 41-71: Advanced BIOS

 Currently, probably the most definitive information on the ABIOS
 system services is the "IBM PS/2 and PC BIOS Interface Technical
 Reference: Advanced BIOS Supplement," available from IBM. If you have
 an OEM system that uses an ABIOS, refer to the OEM for technical
 documentation on their ABIOS implementation.

 The following is a list of general reference information available for
 ABIOS device driver writers:

    "IBM OS/2 Technical Reference Version 1.10"
    "I/O Subsystems and Device Drivers Volume 1"
    IBM Corporation
    1989
    Part number 00F8873

    "Microsoft OS/2 Device Drivers Reference Version 1.10"
    Microsoft Corporation
    1989
    Part number 07017
    (This reference is part of the Microsoft OS/2 Device Driver Kit.)

    "Advanced OS/2 Programming"
    Ray Duncan
    Microsoft Press
    1989
    ISBN 1-55615-045-8

 Currently, probably the most definitive information on using the ABIOS
 system services in an OS/2 device driver is the "IBM OS/2 Technical
 Reference Version 1.10: I/O Subsystems and Device Drivers Volume 1,"
 available from IBM. The Microsoft OS/2 Version 1.00 Device Driver
 documentation, included with the Microsoft OS/2 Version 1.00 Device
 Driver Kit (DDK), did not contain information on the OS/2 ABIOS
 DevHlps. This information has been added to the Version 1.10 Device
 Driver documentation listed above.


 529. Using Keyboard Monitor to Disable the F10 Key in OS/2 1.00

 Question:

 Can I disable the F10 key to switch to the Update Menu in the OS/2
 Version 1.00 (1.00, 1.01, 1.02) Program Selector?

 Response:

 Yes; to do this, use a keyboard monitor that monitors screen group 1
 and looks for the F10 key. The sample monitor code in the file
 MONITORS.C, included with the Version 1.02 OS/2 SDK (Software
 Development Kit) and the Version 1.00 Programmer's Toolkit, can be
 modified to do this.

 When the F10 key is found, the program should just return. Pass
 everything else to the next process in the chain via the DosMonWrite()
 call.


 530. OS/2 ABIOS DevHlps Availability

 Question:

 Does the Microsoft version of OS/2 (in contrast to the IBM version of
 OS/2) use ABIOS to communicate with the hardware on systems that have
 ABIOS? I would like to use the ABIOS DevHlps in my device driver, but
 I cannot use them on some implementations of OS/2.

 Response:

 Microsoft releases of OS/2 do NOT use the ABIOS system services.
 Instead, the OS/2 device drivers bypass the ABIOS abstraction layer
 and talk directly with the hardware, as with the PC/AT family of
 computers. IBM releases of OS/2 may use the ABIOS system services. The
 DevHlps specific to ABIOS kernel implementations (FreeLIDEntry,
 GetLIDEntry, ABIOSCall, and ABIOSCommonEntry) fail if the OS/2 kernel
 does not use the ABIOS interface to the hardware. Thus, a device
 driver can tell if the OS/2 kernel it is running on supports these
 ABIOS DevHlps by trying to use them. If the OS/2 kernel does not
 support ABIOS, these ABIOS-specific DevHlps return failure.
 Information on these DevHlps are listed in the technical references
 provided by Microsoft, IBM, and OS/2 OEMs.


 531. OS/2 SDK: Tutorial on Writing a Multithreaded Program

 The sample program listed below demonstrates the basics of starting a
 thread in a multithreaded program. It is a trivial example, and
 obviously performs no real function.

 In the sample program, there is minimum coordinating control to keep
 the threads synchronized. There is no use of semaphores that would be
 needed in anything but such a trivial example. A flag is used to HOLD
 the main program until the threads are completed. DosSleep() is used
 to pause the second thread.

 Please refer to Section 2 of MTDYNA.DOC for more information on the
 use of multithreaded programs.

 The sample program is as follows:

 /* Use the following commands to compile and link the sample
    program listed below.

 cl -Alfw -Zl -Gs mt.c /link llibcmt doscalls

 The options used in the "cl" line listed above are described below:

   -A (l)pointer size large  (f)pointer size far  (w) ss!=ds; ds fixed
   -Zl no default lib search (use only llibcmt.lib)
   -Gs no stack check

    llibcmt(.lib) is the large model library that supports
    multithreaded programs.

 del mt.obj
 */

 #define INCL_BASE      // this defines/includes all
 #include<mt\os2.h>     // multithreaded include file
 #define STACKSIZE 4096 // used to create a stack for the thread to use
 void far thread1();    // prototype
 void far thread2();
 int hold;              // flag to hold main until threads complete
 main()
 {
     SEL stacksel;  // used to return stack selector (unsigned short)
     TID tid1,tid2; // thread ids (USHORT  - unsigned int)
     PCH pStack1,pStack2; // stack pointers (far char *)
 //
     hold=0;
 /*
     This program was originally written with Doscreatethread().
     It is recommended that you use _beginthread instead, as the
     DosCreateThread() call can give unpredictable results.

     pStack1 = MAKEP(stacksel,0);
     tid1 = _beginthread(thread1,pStack1,STACKSIZE,"");

     When using _beginthread, you must use 0 (zero) instead of
     STACKSIZE in the call to MAKEP. If you use 0, a pointer is
     returned to the bottom of the stack instead of the top. You then
     send the STACKSIZE value as a parameter in the _beginthread call.
     The null parameter at the end of the _beginthread call is the
     parameter list that can be sent with this call.

     */

     DosAllocSeg(STACKSIZE,&stacksel,0);  // return stacksel, use below
     pStack1=MAKEP(stacksel,STACKSIZE);   // return pStack1, use below
     DosCreateThread(thread1,&tid1,pStack1); // return tid1
     hold++;

     DosAllocSeg(STACKSIZE,&stacksel,0);
     pStack2=MAKEP(stacksel,STACKSIZE);
     DosCreateThread(thread2,&tid2,pStack2);
     hold++;

 while (hold);

     /*
     Hold was set to zero, then incremented for each thread started.
     When the threads complete they will each decrement the hold
     count and the main program will end when all threads have
     completed.
     */
 }

 void far thread1()
 {
     DosBeep(1000,100);
     VioWrtTTy("hello from thread 1\r\n",21,0);
     hold--;
 }

 void far thread2()
 {
     DosSleep(1000L); // pause the thread
     DosBeep(3000,100);
     VioWrtTTy("hello from thread 2\r\n",21,0);
     hold--;
 }


 532. Turning Standard Device Driver into Base Device Driver

 Question:

 I have written a standard device driver and must make it a base device
 driver. What changes are required to do this?

 Response:

 The most reliable thing to do is to leave your device driver as an
 installable driver.

 The only way to make an installable device driver a base device
 driver is to modify a list of base device drivers kept inside the
 OS/2 kernel. The Version 1.10 OS/2 BAK (Binary Adaptation Kit) allows
 OEMs to modify this list if they wish, as part of their adaptation
 process. OEMs are also allowed to modify or enhance other
 hardware-dependent portions of the OS/2 kernel. As a result, each
 OEM's version of OS/2 is customized for their hardware and therefore
 is different from all other OEM versions of OS/2. There is no way you
 can modify the base device driver list without deleting all the
 other changes or enhancements a given OEM may have made.

 The best you might be able to do is to rewrite DISK01.SYS (which is a
 base driver) to include your features. However, this has potential
 problems; when your DISK01.SYS driver replaces the OEM's DISK01.SYS
 driver, all the changes the OEM may have made to their DISK01.SYS
 driver will be lost, possibly breaking the system.


 533. OS/2 SDK: GINFOSEG cusecTimerInterval Documented Incorrectly

 Microsoft has confirmed that the cusecTimerInterval parameter of the
 GINFOSEG structure is not documented correctly in the versions of
 QuickHelp included with the Version 1.06 and Version 1.10 OS/2 SDKs
 (Software Development Kits), and on Page 343 of the "Microsoft
 Operating System/2 Programmer's Reference Volume 3 for Version 1.1"
 manual. The correct documentation should state the following:

    cusecTimerInterval    Specifies the timer interval (in tenths of
                          milliseconds, units = 0.0001 seconds)

 We will post new information when this error has been corrected in
 the documentation.


 534. OS/2 SDK: Example of Using a Single-Threaded DLL

 The following four files are required when writing a single-threaded
 DLL (dynamic linked library):

 1. Main program file

 2. Main definition file

 3. DLL code file

 4. DLL definition file

 In the example below, we will use the following names for these four
 files: STMAIN.C, STMAIN.DEF, STDLL.C, and STDLL.DEF, respectively.
 Another file, ST.CMD, is used to run the compile and link steps. This
 method is used instead of using a make file. Included below are the
 files used to create a simple example of how to use a single-threaded
 DLL.

 The STMAIN.DEF file declares the name of the program and the name of
 the DLL that contains the function "dlltest" (STDLL2). The STDLL.DEF
 file contains information on the name of the DLL and the functions it
 contains. For more information on .DEF files, refer to Section 2.6,
 "Using Module-Definition Files," in the "Microsoft Operating System/2
 Presentation Manager Softset" manual.

 STMAIN.C
 --------
 /*
 COMPILE and LINK commands:
 cl -AC -G2 -c stmain.c
 link stmain.obj/NOI,,,clibce.lib doscalls.lib/NOD,stmain.def;
 */
 #define INCL_BASE
 #include<os2.h>
 extern void far dlltest(void);  // prototype declaration of function
                                 // in DLL
 main()
 {
 printf("single thread main\n"); // verifies we are in main program
 dlltest();                      // function call that is in the DLL
 printf("single thread main\n"); // verifies we are back in main
 }

 STMAIN.DEF
 ----------

 NAME STMAIN
 IMPORTS STDLL2._dlltest

 STDLL.C
 -------

 /*
 COMPILE and LINK commands:
 cl -Alfw -G2 -Gs -c stdll.c
 link stdll.obj,stdll2.dll/NOI,,llibcdll.lib doscalls.lib/NOD,
      stdll.def;
 copy stdll.dll2 c:\dll
 rem    this places the DLL in LIBPATH
 */
 #include <stdio.h>
 void far _loadds dlltest(void);  // function declaration
 void far _loadds dlltest(void)   // body of function
 {
    fprintf(stdout,"this is from dlltest\n");
 }

 STDLL.DEF
 ---------

 LIBRARY STDLL2 INITINSTANCE
 rem You must use INITINSTANCE in the LIBRARY line if you are using
 rem the C Runtime. If you don't use INITINSTANCE, other instances
 rem of the application that refer to this DLL will not initialize
 rem their data segments.
 DESCRIPTION 'SAMPLE DLL'
 PROTMODE
 EXPORTS _dlltest
 DATA MULTIPLE

 ST.CMD
 ------

 cl -AC -G2 -c stmain.c
 link stmain.obj/NOI,,,clibce.lib doscalls.lib/NOD,stmain.def;
 cl -Alfw -G2 -Gs -c stdll.c
 link stdll.obj,stdll2.dll/NOI,,llibcdll.lib doscalls.lib/NOD,
      stdll.def;
 copy stdll2.dll c:\dll
 rem copy stdll.dll2 c:\dll ** this puts the DLL on LIBPATH**


 535. OS/2 SDK: Reasons Why LIBPATH Isn't a Dynamic Value

 Question:

 It is very inconvenient to have to set the LIBPATH value at boot time.
 Why can't LIBPATH be a dynamic value, like an environment variable?

 Response:

 One reason the LIBPATH variable is not dynamic is because OS/2 must
 have a stable method of locating its DLLs (dynamic linked libraries).
 All the kernel APIs [i.e., DosFindFirst(), DosDelete(), etc.] and some
 other kernel functions, such as the subsystems BVSCALLS (video
 subsystem) and BKSCALLS (keyboard subsystem), are all implemented as
 ring 3 DLLs. If you allow the user to freely change the LIBPATH
 variable, the system could very easily lose track of the files it
 needs to perform basic kernel functions, or perhaps even load the
 wrong or outdated versions of a file with the same name.

 Another reason LIBPATH is not dynamic is because of speed
 considerations. Once the DLL path is known, it is static. OS/2 can use
 a different method of searching, rather than checking an environment
 variable and searching different directories each time a DLL is
 needed.

 One trick that you might be unaware of is to put a period (.) as the
 first directory in your LIBPATH variable. For example:

    LIBPATH=.;c:\;c:\os2\dll...)

 This will give LIBPATH the appearance of being dynamic in many
 situations. It will definitely help when you are trying to develop
 DLLs because you can avoid copying your newly built DLL to some
 directory in your LIBPATH. Instead, you can just run it from the
 current directory.

 However, there will be a performance penalty because OS/2 will have to
 continually update the pointer to the first search directory, based on
 the directory you are in at the time. Still, it is a very convenient
 method.


 536. OS/2 SDK: Intermittent KBD01.SYS CTRL Key Timing Problem

 Microsoft has confirmed that there is a problem with the KBD01.SYS
 file included with the Version 1.10 OS/2 SDK (Software Development
 Kit). There is a rare, intermittent timing problem with KBD01.SYS
 losing the toggle status of the CTRL key. The symptom occurs when you
 press the CTRL key simultaneously with another key. When this problem
 occurs, KBD01.SYS assumes that the CTRL key is being pressed, even
 though it isn't being pressed. Thus, a  CTRL character is added before
 any key you press. For example, if you press "A", "^A" is displayed
 on the screen. If you press and release only the CTRL key, the problem
 goes away.

 We are researching this problem and will post new information as it
 becomes available.


 537. OS/2 SDK: Initializing Another Programmer's Multithreaded DLL

 Question:

 A developer has written a multithreaded DLL (dynamic linked library)
 that requires its own initialization. The developer seems to have the
 following two choices:

 1. Let the Microsoft C Compiler do its initialization and his DLL code
    specific initialization not take place

 2. Let his DLL do its own initialization and therefore none of the
    Microsoft C Compiler initialization takes place

 Is there any way that the developer can do both of the
 initializations?

 Response:

 If the developer's DLL is a C run-time DLL, the developer has no
 choice but to choose the first option, and then use a workaround to
 get the code to run at initialization time. However, if the developer
 is not using any run-time calls, he or she can write his or her own
 startup code for the DLL in assembly language and get his or her code
 started.

 A workaround for the first option is to set a flag when the
 developer's initialization code has been run, and then have every
 function in the developer's DLL check this flag to determine if the
 initialization code has been run. If the function checked the flag
 and it hadn't been set, then the initialization routine would need to
 be executed. Another workaround is to have all applications using the
 developer's DLL call the initialization function first, before using
 any of the other code in the DLL.


 538. PM Printer Output Flow Explanation

 Question:

 How is control of the printer hardware done when Presentation Manager
 (PM) printing is used? If I issue a "PRINT CONFIG.SYS" command from
 the command prompt, I appear to go through the PRINT01.SYS driver. If
 I print using GPI calls in a PM program, I do not go through the
 PRINT01.SYS driver. I assume that the IBM4201.DRV file controls the
 printer hardware.

 Response:

 The output from using the PM spooler will end up going through the
 base device driver (LPT1:, LPT2:, COM1:, etc.).

 The process of how output goes through the PM spooler is described
 below. The PM spooler is a PM application with associated DLLs
 (dynamic linked libraries) that control the Spl* APIs that PM
 applications can call. The PM spooler also includes a spool queue
 manager, which queues up output for a device (by writing it to a
 temporary file until it is done) and then sends the completed output
 on to be printed. At this point, after the output exits the spool
 queue, the output enters the PM device driver (*.DRV). This .DRV file
 opens the base device driver and performs output to that device.

 The following steps summarize the above information (where PSCRIPT.DRV
 is the PM driver, and COM1: is the output device):

 1. A PM application does a GPI call that is sent to the PM spooler.

 2. The PM spooler queues up the output.

 3. The PM spooler sends the output to the PSCRIPT.DRV file.

 4. The .DRV file translates the output and sends the output to COM1:.

 A base application, which doesn't use the PM spooler or the PM .DRV
 files, talks directly with the base device driver (e.g. LPT1:).
 However, this could cause problems for the spooler. Therefore, the
 spooler uses a device monitor [DosMon*()] to monitor the OS/2 base
 device drivers that the device monitor is spooling to, and looks for
 output that is NOT coming from the spooler itself. In other words, the
 spooler looks for output sent to this device that is not coming from
 the PM .DRV file, as this .DRV file is what talks to this device, not
 the spooler.

 When the spooler monitors activity to the base device that is not
 coming from the .DRV file, the spooler takes the output and puts it
 inside the PM queue, forcing it to act like another print job.

 However, as mentioned above, the spooler always takes a completed
 queue job and passes it on to the .DRV file to be sent to the printer.
 In this case, the output originally came from a base application, not
 a PM application. This can cause problems because base applications
 generally do not write out printer escape codes, and this is what
 would be expected by the .DRV file. Therefore, the IBMNULL.DRV driver
 is used to pass exact output on to the printer, unmodified. This
 allows base applications to use a command of "PRINT CONFIG.SYS", and
 have the CONFIG.SYS file not be interpreted as printer escape codes.

 Thus, the printer output from the PM .DRV printer driver comes to the
 base .SYS printer device driver, and does not go directly to the
 hardware. However, there is an interface between the base printer
 device driver and the spooler that allows the spooler to send output
 to the printer driver and not have its (the spooler's) own printer
 device monitor return this output back to the spooler, looping
 forever. That is, output from PM applications that funnel out of the
 .DRV printer driver come to the base .SYS printer driver, but they
 come via a different interface.


 539. OS/2 SDK: Example of Using a Multithreaded DLL

 The following four files are required when writing a multithreaded DLL
 (dynamic linked library):

 1. Main program file

 2. Main definition file

 3. DLL code file

 4. DLL definition file

 In the example described below, the following names are used for the
 four files listed above: MT.C, MT.DEF, MTDLL.C, and MTDLL.DEF,
 respectively. Included below are the files used to create a simple
 example of how to use a multithreaded DLL.

 The MT.DEF file declares the name of the program and the name of the
 DLL that contains the function "dlltest" (MTDLL2). The MTDLL.DEF file
 contains information on the name of the DLL and what functions it
 contains. For more information on .DEF files, see Section 2.6, "Using
 Module-Definition Files," in the "Microsoft Operating System/2
 Presentation Manager Softset" manual.

 MT.C
 ----

 /* Compile and link the program in the following manner:
 cl -I%INCLUDE%\MT -Alfw -Zl -Gs -c mt.c -DDLL
 link mt.obj crtexe.obj /NOI,,nul,crtlib.lib doscalls.lib /NOD,mt.def
 del mt.obj
 */

 #define INCL_BASE
 #include<os2.h>
 #define STACKSIZE 4096
 extern void far dlltest(void);
 void far thread1();
 void far thread2();
 int hold;
 main()
 {
         SEL stacksel;
         TID tid1,tid2;
         PCH pStack1,pStack2;

         hold=0;

         DosAllocSeg(STACKSIZE,&stacksel,0);
      //0 alloc flag - non(share,discard)able
         pStack1=MAKEP(stacksel,0);
         tid1=_beginthread(thread1,pStack1,STACKSIZE,"");
         hold++;

         DosAllocSeg(STACKSIZE,&stacksel,0);
         pStack2=MAKEP(stacksel,0);
         tid2=_beginthread(thread2,pStack2,STACKSIZE,"");
         hold++;

 while (hold);
 }

 void far thread1()
 {
 extern void far dlltest(void); // not needed, this is declared
                                // above main
     DosBeep(1000,100);
     VioWrtTTy("hello from thread 1\r\n",21,0);
     dlltest();
     printf("thread1\n");
     hold--;
 /*
 This shows a few simple calls. The calls are in different order
 in the two threads to show that threads run as they are scheduled.
 */
 }

 void far thread2()
 {
     printf("thread2\n");
     DosBeep(3000,100);
     VioWrtTTy("hello from thread 2\r\n",21,0);
     dlltest();
     hold--;
 }

 MT.DEF
 ------

 NAME MT
 IMPORTS MTDLL2._dlltest

 MTDLL.C
 -------
 /* Compile and link the program in the following manner:
 cl -I%INCLUDE%\MT -Alfw -DDLL -cMTDLL.C
 link mtdll.obj crtdll.obj,mtdll.dll/NOI,nul,crtlib.lib
      doscalls.lib/NOD,mtdll.def
 del mtdll.obj
 copy mtdll.dll c:\dll
 rem the copy statement above is needed to place the DLL in the
 rem LIBPATH variable
 */

 #include <stdio.h>
 void far _loadds dlltest(void);
 void far _loadds dlltest(void);
 {
    fprintf(stdout,"this is from dlltest\n");

 }

 MTDLL.DEF
 ---------

 LIBRARY MTDLL2
 DESCRIPTION 'SAMPLE DLL'
 PROTMODE
 EXPORTS _dlltest
 DATA MULTIPLE


 540. OS/2 SDK: DosStartSession() Fails from Detached Process

 Question:

 When calling DosStartSession() from a detached process, the call fails
 with a 418 error code (SMG_INVALID_CALL). Why is this happening?

 Response:

 The behavior described above is correct. The session manager must
 restrict the use of ALL session manager API calls from a detached
 process because the RUN statement in CONFIG.SYS will cause a detached
 process to be started before the session manager has been initialized.
 This restriction is not documented. It should be described in the
 documentation for the "RUN", "DETACH", and all of the session manager
 API calls. We will post new information when the documentation has
 been updated.


 541. OS/2 SDK: Using IMPLIB Command to Create Import Library

 This article demonstrates how to use the IMPLIB command to create an
 import library. It also demonstrates how to use an import library when
 linking, instead of using a .DEF file when creating a multithreaded
 DLL (dynamic linked library).

 To create an import library, issue the following command, where
 MTDLL.LIB is the name you want to give the import library and
 MTDLL.DEF is the name of the .DEF file used when creating the DLL.

    implib mtdll.lib mtdll.def

 The following is a sample .DEF file:

 MTDLL.DEF
 ---------

 LIBRARY MTDLL2
 DESCRIPTION 'SAMPLE DLL'
 PROTMODE
 EXPORTS _dlltest
 DATA MULTIPLE

 The following example demonstrates how to compile and link a DLL:

  cl -Id:\c\include\mt -Alfw -G2 -c -DDLL mtdll.c
  link mtdll.obj d:\c\lib\crtdll.obj,mtdll2.dll/NOI,,crtlib.lib
       doscalls.lib/NOD,mtdll.def;
                        ^^^^^^^^^
 Note the use of MTDLL.DEF.

 The following information describes how to use an import library.

 A program may normally be compiled and linked in the following manner:

   cl -Id:\c\include\mt -Alfw -Zl -Gs -c -DDLL mt.c
   link mt.obj d:\c\lib\crtexe.obj /NOI,,nul,crtlib.lib
        doscalls.lib /NOD,mt.def
                          ^^^^^^
 Note that MT.DEF is included as the last parameter in the LINK
 command.

 Instead of using the .DEF file when linking, you may instead use a
 import library created by the IMPLIB command. The following example
 demonstrates how to do this:

  cl -Id:\c\include\mt -Alfw -Zil -Od -Gs -c -DDLL mt.c
  link mt.obj d:\c\lib\crtexe.obj/NOI,,nul,mtdll.lib crtlib.lib
       doscalls.lib/NOD;                   ^^^^^^^^^

 Notice the extra library, MTDLL.LIB, which is the import library
 created with IMPLIB. Also, no .DEF file is used.


 542. Server Adaptation OS/2 Won't Install on PS/2 with Large ESDIs

 The following information applies to the OS/2 SDK Version 1.07 and to
 the SQL Server NDK (Network Development Kit) Version 1.00.

 The Server Adaptation OS/2 included with the Version 1.07 OS/2 SDK
 (Software Development Kit) may fail to install on IBM PS/2s with large
 ESDI hard drives. The problem has to do with the ROM chip ID on the
 hard disk drive controller.

 The only ESDI ROM ID Microsoft has verified as working is 15F6587.
 This has been verified as working in a Model 60, and it has also been
 reported to work in the Model 80-111.

 The following IDs are reported not to work:

    15F6807
    15F6865
    15F6866

 If you order updated ROMs, check the ID before you install them.
 There may have been a part numbering mix-up on these ROMs that may
 or may not have been cleared up by now, so check the ID printed on
 any ROMs that arrive. Do not rely on the ROM ID number given by the
 part number description.


 543. OS/2 SDK: Exit List Processing Information

 Question:

 We would like some more information on DosExitList() processing. The
 system we are developing has multithreaded and single-threaded non-PM
 applications, as well as PM applications calling a single-threaded
 large model DLL (dynamic linked library) (with GLOBAL INITIALIZATION),
 whose functions contain semaphore protection around C run-time calls
 and data accesses. The DLL contains a "LOGIN" function called by each
 application to register itself with the DLL, and a "LOGOUT" function
 to de-register the application with the DLL.

 After an application has successfully called the "LOGIN" function, it
 adds a local "CLEANUP" function to its DosExitList() processing. The
 "CLEANUP" function in turn calls the DLL's "LOGOUT" function on behalf
 of the application if it terminates unexpectedly. If the application
 is operating normally, it will call the "LOGOUT" function in the DLL
 itself, and then it will remove "CLEANUP" from its DosExitList()
 processing.

 The problem we have noticed is that when a multithreaded application
 terminates unexpectedly and the DosExitList() processing calls
 "CLEANUP," which in turn calls the "LOGOUT" function in the DLL, the
 DosSemRequest() of the serialization semaphore used to protect the C
 run-time calls in "LOGOUT" returns an error of (ERROR_SEM_OWNER_DIED),
 which prevents us from completing the "LOGOUT" function correctly.

 What effects do thread termination and DosExitList() processing have
 on access to system resources such as RAM and system semaphores,
 queues, pipes, etc., for a (fatally) terminating application? Is there
 a problem calling the following routines:

 1. A DLL-based "CLEANUP" routine for an application

 2. An application-based "CLEANUP" routine, which in turn calls another
    routine in a DLL

 Also, is there any problem accessing GLOBAL (not STACK-based)
 variables in these "CLEANUP" routines, and is there any difference in
 the way DosExitList() handles DLL and application-based DosExitList()
 "CLEANUP" functions?

 Response:

 You can make almost any kernel call in an exit list function. However,
 functions such as DosExecPgm(), DosCreateThread(), DosStartSession(),
 etc., are not allowed. Also, you cannot assume the order in which the
 DosExitList() routines will be run in OS/2 Version 1.00. However, in
 OS/2 Version 1.10, the high-order byte of the first parameter,
 fFnCode, defines the invocation order of the DosExitList() routines.
 For more information on this topic, query on G890310-13698 and
 fFnCode. You also cannot assume that queues are still around at the
 time the DosExitList() function is executed.

 Signals are held during the exit list, but all threads, except for
 thread 1 of your process, are killed. All file handles (not closed by
 other exit list functions) will be available.

 From the information listed above, you can assume that all system
 resources should be available for you to access, given that you have
 access rights to them in the main thread of execution.

 When the exit list routines gain control, all system semaphores owned
 by the process will have ownership transferred to thread 1 of the
 process. This will allow requests for serialization of these
 semaphores by thread 1 to not block in the event that the semaphore is
 created by another thread in the process that has been killed. The
 semaphores must have been created with nonexclusive ownership.

 All kernel calls are available, and many of the calls are located in
 DLLs. You should also be able to access global data.


 544. OS/2 SDK: Obtaining Current Screen Group in Keyboard Monitor

 Question:

 I want to load a device monitor in my CONFIG.OS2 file, but I can't get
 the monitor to find a meaningful current screen group. I have the
 following command in my CONFIG.OS2 file:

    RUN=MON.EXE

 The MON.EXE program does the following to get the current screen
 group:

      PGINFOSEG     GlobalInfo;
      SEL           GlobalInfoSel;
      SEL           LocalInfoSel;
      .
      .
      .

      DosGetInfoSeg (&GlobalInfoSel, &LocalInfoSel);
      GlobalInfo = MAKEPGINFOSEG(GlobalInfoSel);
      DosMonOpen ("KBD$", &KBD_Handle);
      DosMonReg (KBD_Handle, &KInBuffer, &KOutBuffer, FRONT,
                 GlobalInfo -> sgCurrent);

 When MON.EXE is run from CONFIG.OS2, the code listed above doesn't
 seem to monitor the keyboard correctly. Is there a way to both load
 MON.EXE in CONFIG.OS2 and monitor an actual session's keyboard?

 Response:

 This is intended behavior. If you check the return code for the
 DosMonReg() function call, it will be nonzero. The ID returned in the
 "sgCurrent" field will indicate that you are in the detached screen
 group, or that you are in the hard-error screen group, which is
 essentially the same thing. By definition, this group has no keyboard
 or screen I/O access other than that provided through the VioPopUp()
 mechanism.

 The problem is that at initialization time (when the RUN commands are
 issued) no regular screen groups are initialized except maybe the
 detached group, the hard-error group, and the compatibility box (if
 you have one). "Normal" operation does not really begin until the PM
 session manager is in place.

 Because the detached screen group does not really have a keyboard to
 monitor, you will never see any keystrokes.

 To resolve the problem that you are experiencing, try detaching your
 monitor from a full-screen group and the method you are using above
 should work fine. Also, you could hard code in a screen group value
 such as "4", and your monitor will register to monitor that session
 (this would most likely be the first or second full-screen group you
 start up). There is nothing wrong with registering a session that does
 not yet exist. The thread will just block until the session is created
 and the appropriate monitor chain is activated.

 The method you are using is valid only when you intend to start it
 from a current session. If you make the DosGetInfoSeg() call too early
 (e.g. at initialization time), the current screen group may be an
 invalid or nonexistent value. You can also try to delay or otherwise
 inhibit the DosMonReg() call until you know that a screen group of
 interest to you exists.


 545. Using InPort Mouse with OS/2 SDK Version 1.07

 Problem:

 I am having a problem with the Microsoft InPort bus mouse when running
 the Version 1.07 OS/2 SDK (Software Development Kit) on the Dell PC's
 Limited 286 AT clone. When I use the mouse in the Presentation Manager
 (PM) screen group, the system reboots to the memory check.

 Response:

 The Version 1.07 OS/2 SDK is a kernel meant to be used with the OS/2
 LAN Manager product. The Version 1.07 OS/2 SDK contains an OS/2 1.00
 kernel, not a Version 1.10 kernel. Presentation Manager was introduced
 into OS/2 in OS/2 Version 1.10 and was not present in OS/2 Version
 1.00. OS/2 SDK Version 1.07 is not meant to be used with PM.

 When using OS/2 SDK Version 1.07, you must use the character-based
 shell that is provided with the Version 1.07 release, not PM. Also,
 you should use the mouse drivers included with the Version 1.07 OS/2
 SDK release.

 If you are using OS/2 SDK Version 1.06, which is OS/2 Version 1.10,
 which also supports and includes Presentation Manager, then you should
 use the mouse drivers included with the Version 1.06 OS/2 SDK release.


 546. OS/2 SDK: Category 8 Functions 45H and 65H Documentation Error

 Microsoft has confirmed that part of the documentation on Pages 276
 and 281 in the "Microsoft Operating System/2 Programmer's Reference
 Volume 3 for Version 1.1" for Category 8 Functions 45H
 (DSK_FORMATVERIFY) and 65H (DSK_VERIFYTRACK) is incorrect. The
 documentation incorrectly states that the first parameter should be
 "0L". Instead, the first parameter should be a pointer to an integer
 indicating the first sector to be accessed (usually 0).

 We will post new information when the documentation has been updated
 to correct this error.


 547. VER Command Used in 3.x Box Returns OS/2 Version Number

 Question:

 When I type "VER" in the DOS 3.x box, an OS/2 version number is
 displayed. Does that mean that any MS-DOS application that checks the
 MS-DOS version number will not work in the DOS 3.x box?

 Response:

 Yes. That is why new utilities had to be included with the
 compatibility box. These new utilities will not work under MS-DOS
 Versions 2.x, 3.x (3.00, 3.10, 3.20, 3.21, 3.22, 3.30, and 3.30a), and
 4.x (4.00, 4.00a, and 4.01). Likewise, the MS-DOS 2.x, 3.x, and 4.x
 utilities will not work in the compatibility box due to version
 checks.


 548. OS/2 1.10 Does Not Access Memory Beyond 16 MB

 Question:

 On 80386 machines, does OS/2 access memory beyond the reported value?
 Specifically, does OS/2 access the last 2 gigabytes of system memory?

 Response:

 The CPU type does not affect OS/2 memory usage behavior (OS/2 Version
 1.10 is really an 80286 operating system). OS/2 will never try to
 access any memory beyond 16 MB. As a matter of fact, OS/2 will not
 even boot up on a machine with more than 16 MB of memory installed in
 it.


 549. OS/2 Tape Drive Backup Systems

 The companies listed below sell tape drives that work under OS/2. The
 products listed below are manufactured by vendors independent of
 Microsoft. We make no warranty, implied or otherwise, regarding these
 products' performance or reliability. This information is provided
 only for your convenience.

 1. Compaq has a tape drive that works in OS/2 protected mode.

 2. Sy-Tos has a 3.0 version of their tape drive that works in OS/2.
    For more information about their product, contact Sy-Tos at (508)
    898-0100.

 3. Irwin Magnetic Systems has a product called EzTape(R) for OS/2. For
    more information on this product, contact Irwin Magnetic Systems at
    (313) 930-9000.


 550. OS/2 Limitations on Fast Data Transfer Rates

 Question:

 We want to write an application that requires data transfer rates to
 and from a PC of no less than 320 kilobits/second, with 500
 kilobits/second desirable. Are there any inherent limitations that
 OS/2 and Presentation Manager (PM), as the base software for this
 application, might impose?

 Response:

 For the OS/2 device drivers, the amount of time from when an interrupt
 occurs to when interrupts are enabled again should be a maximum of 400
 microseconds (uS). This time is when the interrupt occurs, the kernel
 does some processing of the interrupt in its interrupt manager code,
 then passes it on to the appropriate device driver that handles the
 interrupt. If this driver is not one of the base drivers, the
 developer who wrote the driver may have not have stayed within the
 limit of 400 uS.

 There is a good discussion of these inherent delays in mode switching
 on an 80286 in the May 1987 issue of the "Microsoft Systems Journal,"
 Volume 2, Number 2, on Pages 61-66. The article titled "An Interview
 with Gordon Letwin, OS/2: Turning Off the Car to Change Gears" was
 interviewed and written by Lori Valigra.

 Switching to and from the DOS compatibility mode (3.x box) takes a lot
 of time, due to mode switching overhead. Based on Gordon's comments in
 the above article, this delay can be 1000 microseconds, in which no
 interrupts can be serviced.

 The COM driver included with OS/2 is specified to work with one-way
 communication at 9600 baud. This area is one in which mode switching
 to and from the 3.x box really degrades performance. Also, a better
 quality (i.e., faster) UART will help here. These timings are for a 6
 MHz IBM PC/AT; your actual timings may vary. Using an 80386 is
 generally better, especially when it comes to mode switching.

 In general, a better processor (80386 over 80286) will improve
 performance. Of course, in general, the better the hardware, the
 faster the system performance (faster UARTs for faster serial I/O,
 faster hard disks for faster disk I/O, faster memory, etc.). Also, if
 the DOS 3.x box is not enabled (PROTECTONLY=YES in CONFIG.SYS), the
 system performance will improve even more.


 551. OS/2 SDK: Use of Global Variables in DLLs

 Question:

 If a DLL (dynamic link library) has global variables in it, does each
 process that uses that DLL get its own copy of the variables, or are
 the variables shared among the various processes? Also, how do I
 specify which type of segment my DLL global variables go into? What
 happens by default? If the default is to put them in the shared
 segment, how do I create unique segments for each process so that
 there won't be any conflicts?

 Response:

 The method used to define whether or not a given segment is shared is
 to use the SHARED or NONSHARED attribute for the data segment in the
 module definition file. The default for all data segments in a DLL is
 for the segments to be SHARED between processes.

 As mentioned above, if all of your segments don't have the same
 attributes, the method used to make your global variables be contained
 within a NONSHARED segment (private to the process making the call) is
 to use the NONSHARED directive with the name of the segment in the
 SEGMENTS section of the module definition file. Or, if all data
 segments will have the same attributes, you should use the NONSHARED
 directive within the DATA section of the module definition file.

 The DATA section provides the defaults for all data segments within
 the library, while the SEGMENTS section allows the programmer to
 override the defaults for specific segments.


 552. BROWSE Works Only if OPENDLG.DLL Is in LIBPATH Subdirectory

 Question:

 I tried running BROWSE.EXE, which is included in the
 PMSDK\SAMPLES\BROWSE\AVBROWSE subdirectory. I got an error message
 that said it could not find OPENDLG.DLL. I used the command "BROWSE
 BROWSE.C", as instructed in the README file. Then, I tried to run MAKE
 on the BROWSE files and the file "OPENDLG.H" could not be found. Where
 is this file located?

 Response:

 Before executing BROWSE, you need to make sure that OPENDLG.DLL is
 located in a subdirectory that is included in your LIBPATH variable.

 OPENDLG.H is located in both the \PMSDK\SAMPLES\INCLUDE and in the
 PMSDK\SAMPLES\OPENDLG subdirectories.


 553. VioCreatePS() Can Create Presentation Space Up to 64K

 Question:

 What is the largest buffer I can allocate with VioCreatePS()? Page 203
 of the "Microsoft Operating System/2 Programmer's Reference Volume 3"
 Version 1.10 manual says that the largest buffer I can allocate is
 32K; however, on Page 309 of Charles Petzold's "Programming the OS/2
 Presentation Manager" it says that the largest buffer I can allocate
 is 64K.

 Response:

 Microsoft has confirmed that the "Microsoft Operating System/2
 Programmer's Reference Volume 3" Version 1.10 manual is in error. The
 largest size that you can allocate is 64K. As in Petzold's book, IBM's
 OS/2 1.10 documentation discusses this properly. Section 11-4 of the
 "OS/2 Version 1.10 Technical Reference: Programmer's Reference Volume
 2" states that the presentation space size that can be calculated with
 the following must not exceed 64K.

    (width * depth * (attributes + 1))

 The VioCreatePS() documentation in Versions 1.06 and 1.10 of QuickHelp
 is also in error.

 We will post new information when the documentation is updated to
 correct this error.


 554. AVIO and VIO Calls Do Not Directly Manipulate Physical Window

 Question:

 Do the AVIO calls do anything intelligent when they reach the bottom
 of the buffer (e.g. treat the buffer as a circular buffer)? Is it best
 to use a large separate circular buffer and scroll by copying the
 appropriate text to a VIO buffer that is only the size of the screen,
 or is it best to use VIO calls to treat the buffer as a circular
 buffer?

 Response:

 The VIO calls (including the AVIO calls) don't have any routines that
 manipulate the window directly. For example, when you call
 VioCreatePS(), a physical window is created. The VIO subsystem
 scrolling calls will move the logical window up, down, left, and
 right, around this physical window. However, there are no VIO or AVIO
 calls that will do things such as directly "folding" the physical
 window, similar to what the Windows application Excel can do when
 displaying a spreadsheet.

 A Windows or Presentation Manager application can create two logical
 windows that can be scrolled separately, thus achieving this sort of
 "folding" from the user's perspective.


 555. HLPMSG: Sample Help Message File Information

 There is a file in the Software Library named HLPMSG that contains a
 sample OS/2 application message file, which can be used by an
 application via the DosGetMessage() and DosPutMessage() APIs. It also
 can be used via the HELPMSG.EXE utility (which is transparently used
 when the user runs the HELP.BAT or HELP.CMD script files). HLPMSG can
 be found in the Software Library by searching on the keyword HLPMSG,
 the Q number of this article, or S12321. HLPMSG was archived with the
 PKware file-compression utility and contains the following files:
 FOO.TXT, FOOH.TXT, READ.ME, and MAKEFILE.

 The file FOO.TXT contains the error messages; the MAKEFILE runs the
 MKMSGF utility on this file, which generates FOO.MSG. The file
 FOOH.TXT contains the error message help text; the MAKEFILE runs the
 MKMSGF utility on this file, which generates FOOH.MSG. For comparison
 purposes, the files FOO.MSG and FOOH.MSG are roughly analogous in
 functionality to the OS/2 system message files, OSO001.MSG and
 OSO001H.MSG.

 To build the .MSG files, enter one of the following:

    NMAKE

 or

    MAKE MAKEFILE

 To see the results, type the following:

    HELPMSG FOO0001

 Or, use FOO0002-FOO0005 as the messages, since there are only five
 errors in the message text files. Make sure that the .MSG files are in
 either the DPATH (when in OS/2), in the APPEND path (when in the DOS
 3.x box), or in the current directory, so that OS/2 can find the
 files.


 556. Determining Current Country Code with DosGetCtryInfo()

 Question:

 The only way I have figured out to determine the current country code
 is to set the country field of the COUNTRYCODE structure to 0 (zero),
 call DosGetCtryInfo(), and then examine the country field information
 that is returned in the COUNTRYINFO structure. Is this the correct
 method?

 Response:

 Yes. DosGetCtryInfo() is the API that should be used to retrieve the
 current country code. And as stated above, if you set
 COUNTRYCODE.country to 0 (zero), the current country information will
 be returned. The syntax for the DosGetCtryInfo() API is as follows:

     DosGetCtryInfo(sizeof(buffer), &COUNTRYCODE, &COUNTRYINFO,
                    &buffer);

 The COUNTRYCODE structure contains information about the country and
 codepage that you are interested in. If the country and codepage are
 both set to 0 (zero), this means that you want to get the current
 country with the currently selected codepage. Therefore, the
 COUNTRYCODE structure is where you specify what you want
 DosGetCtryInfo() to get information about. COUNTRYINFO is the
 structure that returns this information.

 The country is user defined, not application defined. However, an
 application can select which of the codepages (which the current
 country supports) to use. Thus, you can give COUNTRYCODE.country a
 value of 0 (zero) and specify a particular COUNTRYCODE.codepage. The
 normal situation would be to specify 0 (zero) for both values, thus
 obtaining information about the current country with the current
 codepage.


 557. MouEventReadQue Doesn't Work Correctly in Windowed-Screen Mode

 Problem:

 I am having a problem using MouEventReadQue(). If you run the sample
 code listed below in full-screen mode, the output is as follows:

    MouInfo.fs -> 4         After pressing the left button
    MouInfo.fs -> 0         After releasing the left button
    MouInfo.fs -> 16        After pressing the right button
    MouInfo.fs -> 0         After releasing the right button

 If you next run the sample code listed below in windowed-screen mode,
 the output is as follows:

    MouInfo.fs -> 4         After pressing the left button
    MouInfo.fs -> 0         After releasing...
    MouInfo.fs -> 1         ... the left button
    MouInfo.fs -> 16        After pressing the right button
    MouInfo.fs -> 0         After releasing...
    MouInfo.fs -> 1         ... the right button

 Why is an extra mouse event (MouInfo.fs = 1) occurring when either
 button is released, even though the mouse has not moved at all? The
 following code can be used to reproduce this problem:

 ******************** TEST.C ********************

 /* Compiled as: cl -AL -Lp x.c */

 #define INCL_DOSERRORS
 #define INCL_SUB

 #include <os2.h>

 main ()
 {
         HMOU MouseHandle;         /* mouse handle                 */
         MOUEVENTINFO MouInfo;     /* mouse event packet structure */
         unsigned MouReadType = 1; /* 0=do not wait, 1=wait for
                                      mouse event                  */
         unsigned moustatus;

         /* open the mouse */
         MouOpen (0L, &MouseHandle );

         MouGetDevStatus (&moustatus, MouseHandle);
         moustatus = 0x100;
         MouSetDevStatus (&moustatus, MouseHandle);

         do {
                 MouReadEventQue ((PMOUEVENTINFO) &MouInfo,
                                  (unsigned far *)&MouReadType,
                                  MouseHandle);

                 printf ("MouInfo.fs --> %d\n", MouInfo.fs);
         } while (1);
 }  /* end main */
 ******************** END TEST.C ********************

 Response:

 Microsoft has confirmed this to be a problem with the Version 1.10
 OS/2 SDK (Software Development Kit). We are researching this problem
 and will post new information as it becomes available.

 As a temporary workaround, which shouldn't degrade performance very
 much, make an extra call to determine the mouse position. You could
 also check the type of screen group you are in. Then, if you are in a
 windowed screen group, you could ignore the third parameter after a 4
 0, 16 0, or 20 0 sequence of mouse events.


 558. OS/2 SDK: Using Memory Management Options in CONFIG.SYS

 Question:

 I have a question about movable data segments. Under Windows, you
 can't save data pointers for memory models other than for the small
 memory model, since segments are moved at Windows' discretion. How
 does OS/2 handle this issue, and how does this correspond to the
 MEMMAN command in CONFIG.SYS?

 Response:

 The problem with data pointers becoming invalid under Windows is not a
 problem in OS/2.

 The MEMMAN command in CONFIG.SYS configures the way the OS/2 memory manager
 utilizes physical memory and swapping.

 If the SWAP option is selected, the OS/2 memory manager is allowed to
 swap segments to the OS/2 swapper disk file named SWAPPER.DAT. If the
 NOSWAP option is selected, the OS/2 memory manager is NOT able to do
 this, and must keep segments in memory at all times.

 In addition to the SWAP and NOSWAP options (these two options are
 mutually exclusive), the MEMMAN also has the MOVE and NOMOVE options
 (these two options are also mutually exclusive).

 If the MOVE option is selected, the OS/2 memory manager can
 temporarily move segments when it needs to (while the application is
 not active or using the segment). If the NOMOVE option is selected,
 the OS/2 memory manager cannot do this.

 For the OS/2 memory manager to take the most advantage of memory, the
 normal options for MEMMAN are SWAP,MOVE. For more information on
 MEMMAN, refer to the "Microsoft OS/2 User's Guide."


 559. Incorrect Declaration of PFNSIGHANDLER in OS/2 Version 1.06

 In BSEDOS.H, the definition of the PFNSIGHANDLER type does not mention
 the fact that the function has the Pascal attribute. This causes an
 error message when you try to call DosSetSigHandler() with a function
 that you have declared with the Pascal attribute and you don't
 explicitly cast it to type PFNSIGHANDLER.

 The PASCAL keyword is needed by PFNSIGHANDLER. If it is NOT specified,
 the stack will be corrupted when the system calls the signal handling
 function and then returns. The two USHORTs are not removed from the
 stack and the system GP-faults trying to return to an incorrect
 address.

 Thus, the CORRECT way to define PFNSIGHANDLER is as follows:

    typedef VOID (PASCAL FAR *PFNSIGHANDLER)(USHORT, USHORT);

 The INCORRECT way to define PFNSIGHANDLER is as follows:

    typedef VOID (FAR *PFNSIGHANDLER)(USHORT, USHORT);

 In the version of BSEDOS.H that was included with the Version 1.05
 OS/2 SDK (Software Development Kit), PFNSIGHANDLER was properly
 defined. However, Microsoft has confirmed that in the Version 1.06
 OS/2 SDK, PFNSIGHANDLER was incorrectly changed to not include the
 PASCAL keyword. This problem (introduced in OS/2 SDK Version 1.06) was
 corrected in the Version 1.07 OS/2 SDK.


 560. OS/2 BAK Version 1.10 Will Not Install in 32 MB Partition

 Problem:

 In following the installation procedures in the manual and using the
 SETUP.BAT batch file that comes with the Version 1.10 OS/2 Binary
 Adaptation Kit (BAK), I ran out of disk space at about disk 27 out of
 29. I started with a clean 32 MB partition. The README.DOC file on
 Binary Disk 1 states that I can use MS-DOS Version 3.30 to build and
 develop the OS/2 BAK. However, MS-DOS Version 3.30 does not allow
 partitions larger than 32 MB.

 Response:

 Microsoft has confirmed that the README.DOC file is in error. Also,
 Page 16 of the "Microsoft Operating System/2 Binary Adaptation Guide"
 for Version 1.10 incorrectly states that MS-DOS Version 3.30 can be
 used to build and develop the OS/2 BAK.

 You can no longer perform the adaptation under MS-DOS Version 3.30.
 You must use another version of MS-DOS that supports partitions larger
 than 32 MB, such as MS-DOS Version 4.01 or Compaq's MS-DOS Version
 3.31. We will post new information when this error has been corrected
 in the documentation.


 561. Open File Handles Are Inherited by Detached Screen Group

 If you use the DETACH command from a screen group that has open files
 in it, the file handles of the open files are inherited by the
 detached screen group. Subsequent use of these files by the original
 screen group causes an error.

 This is expected behavior. When CMD.EXE encounters a DETACH statement,
 the program specified is executed via the DosExecPgm() function call.
 The DosExecPgm() call does not close file handles, and all handles
 that are open are therefore inherited by the child process (the
 DETACHed process).

 To work around this situation, do one of the following:

 1. Either close the handles before "execing" CMD.EXE (your program
    probably already does this, since the file handles are open while
    the command interpreter is running) or open the files with the
    inherit option turned off.

 2. Change the inheritance state on an open file by using the
    DosSetFHandState() function call and setting the noinheritance
    flag. Please refer to the QuickHelp documentation on the
    DosSetFHandState() function call for an example of how to do this.


 562. OS/2 SDK 1.10 QuickHelp Missing KBDKEYINFO Documentation

 Microsoft has confirmed that the documentation in the OS/2 Version
 1.10 Software Development Kit (SDK) QuickHelp database for the OS/2
 API does not include information on the KBDKEYINFO data structure (the
 struct called _KBDKEYINFO, a.k.a. the typedef called KBDKEYINFO) used
 by the KbdCharIn() API. This problem has been corrected in the
 QuickHelp database included with the Microsoft OS/2 Version 1.10
 Programmer's Toolkit (PTK). Below is the text for this KBDKEYINFO
 structure, taken from the Version 1.10 PTK QuickHelp database.

 #define INCL_KBD

 typedef struct _KBDKEYINFO {    /* kbci */
     UCHAR  chChar;
     UCHAR  chScan;
     UCHAR  fbStatus;
     UCHAR  bNlsShift;
     USHORT fsState;
     ULONG  time;
 } KBDKEYINFO;

 The KBDKEYINFO structure contains information when a key is pressed.

 Parameters  Description
 ---------------------------------------------------------------------
 chChar      Specifies the character derived from translation of the
             chScan field.

 chScan      Specifies the scan code received from the keyboard,
             identifying the key pressed. This scan code may be
             modified during the translation process.

 fbStatus    Specifies the state of the retrieved scan code. It can be
             any combination of the following values:

             Value               Meaning
             ---------------------------------------------------------
             SHIFT_KEY_IN        SHIFT key is received (valid only in
                                 binary mode when shift reporting is
                                 turned on).

             CONVERSION_REQUEST  Conversion requested.

             FINAL_CHAR_IN       Final character received.

             INTERIM_CHAR_IN     Interim character received.

 bNlsShift   Specifies a reserved value; must be zero.

 fsState     Specifies the state of the SHIFT keys. It can be any
             combination of the following values:

             Value          Meaning
             ---------------------------------------------------------
             RIGHTSHIFT     Right SHIFT key down.

             LEFTSHIFT      Left SHIFT key down.

             CONTROL        Either CTRL key down.

             ALT            Either ALT key down.

             SCROLLLOCK_ON  SCROLL LOCK mode turned on.

             NUMLOCK_ON     NUM LOCK mode turned on.

             CAPSLOCK_ON    CAPS LOCK mode turned on.

             INSERT_ON      INSERT key turned on.

             LEFTCONTROL    Left CTRL key down.

             LEFTALT        Left ALT key down.

             RIGHTCONTROL   Right CTRL key down.

             RIGHTALT       Right ALT key down.

             SCROLLLOCK     SCROLL LOCK key down.

             NUMLOCK        NUM LOCK key down.

             CAPSLOCK       CAPS LOCK key down.

             SYSREQ         SYS REQ key down.

 time        Specifies the time stamp of the keystroke (in
             milliseconds).

 See Also:

 KbdCharIn, KbdPeek, KBD_PEEKCHAR


 563. OS/2 DLL File Format

 Information about the format of an OS/2 DLL (dynamic linked library)
 file can be obtained from two sources. An earlier version of the OS/2
 SDK (Software Development Kit) included a file named NEWEXE.H that
 describes the structure of the new EXE format, which is also the
 format of an OS/2 DLL file. Also, Appendix D of Ray Duncan's "Advanced
 OS/2 Programming" book contains a detailed layout of the file
 structure.

 In the Software Library is a file named NEWEXE that contains an
 archived copy of NEWEXE.H. This file can be found in the Software/Data
 Library by searching on the keyword NEWEXE, the Q number of this
 article, or S12338. NEWEXE was archived using the PKware
 file-compression utility.


 564. Using OS/2 SDK Version 1.10 with OS/2 LAN Manager

 Question:

 Can I run the final release of the OS/2 LAN Manager under the Version
 1.10 OS/2 SDK (Software Development Kit)?

 Response:

 Yes, you can use OS/2 LAN Manager under OS/2 SDK Version 1.10.
 However, by not using the LAN Manager kernel, you will lose the
 ability to use the LAN Manager disk cache.

 If this feature is not important to you, you can use the OS/2 SDK
 Version 1.10 kernel.

 When upgrading to OS/2 SDK Version 1.10, be sure that the "\OS2\DLL"
 path appears before "\LANMAN\NETLIB" in your LIBPATH variable, so that
 the system will default first to the OS/2 Version 1.10 NAMPIPES.DLL.
 For example:

    LIBPATH=C:\OS2\DLL;C:\LANMAN\NETLIB;


 565. Version 1.00 DUALBOOT Utility Can't Be Used in OS/2 SDK 1.10

 Question:

 Can I use the old (Version 1.00) DUALBOOT utility with the Version
 1.10 OS/2 SDK (Software Development Kit)?

 Response:

 No. The older DUALBOOT utility was built into the OS/2 1.00 loader
 program and thus has dependencies toward that release. The OS/2 1.10
 loader does not have these hooks. The new DUALBOOT utility is isolated
 from the kernel, so that OEMs can easily choose whether to include it
 or not with their OS/2 release. For example, IBM doesn't include the
 DUALBOOT utility with its release.

 In addition, OS/2 1.00 had to contend with two sets of CONFIG.SYS and
 AUTOEXEC.BAT files when loading OS/2 or MS-DOS. OS/2 1.10 doesn't have
 to worry about this, as the new DUALBOOT utility takes care of the
 problem of renaming the appropriate set of CONFIG and AUTOEXEC files
 for the currently selected operating system, MS-DOS or OS/2.

 The new DUALBOOT utility has many more features than the older one, in
 response to feedback that we have received from OnLine OEMs and ISVs.
 Among these, it has closer conformance to SAA's CUA, it allows you to
 change the default operating system, has a time delay to auto-boot the
 default operating system if you don't select one, and allows you to
 easily install or uninstall DUALBOOT.

 One reason why it is now a separate utility is so that it can be used
 on IBM's release of OS/2, as well as the Microsoft releases of OS/2.
 The previous release of DUALBOOT was partially in Microsoft-specific
 portions of the OS/2 1.00 loader, and in a Microsoft-specific OS/2
 1.00 installation program. DUALBOOT has been isolated so the same
 installation program and loader can be used by OEMs with very little
 modification, unlike the 1.00 DUALBOOT utility.


 566. Serial Port Buffering in OS/2

 Question:

 How does OS/2 implement COM port buffering? I have a program that,
 when running on a heavily loaded machine, regularly loses characters
 that are coming in through a COM port.

 Response:

 Because OS/2 is a multitasking operating system, no single function
 (such as reading the serial port) can monopolize the entire system
 (like it could in MS-DOS) to ensure that no data is missed during
 real-time input. However, you can minimize the possibility of losing
 data that is coming in through the COM port by doing the following:

 1. Never switch to the 3.x Box when expecting serial data from the COM
    port.

 2. Use the DosReadAsync() function to get serial data from the COM
    port.

 3. Use the SetDCBInfo IOCTL (Category 1, Function 53H) to specify
    MODE_WAIT_READ_TIMEOUT time-out processing (this is a bit in the
    fbTimeout byte in the DCBInfo structure passed to the IOCTL).


 567. OS/2 SDK: Determining If Application Is in the Foreground

 Problem:

 DosGetInfoSeg() will not properly return the current foreground or
 background status (via the boolean flag in the local information
 segment).

 Response:

 This is not a problem with the DosGetInfoSeg() function call; however,
 the documentation is unclear. What the flag means is that the current
 process has the input focus, not that the current process is in the
 foreground.

 To determine whether an application is in the foreground, compare the
 session ID in the local info seg with the current foreground session
 ID in the global info seg. The following program demonstrates how to
 do this:

 #define INCL_BASE
 #include <os2.h>
 #include <stdio.h>

 void main(void);

 void main(void)

 {
     SEL       GlobSel;
     SEL       LocSel;

     GINFOSEG  FAR *pgisInfo;
     LINFOSEG  FAR *plisInfo;

     DosGetInfoSeg(&GlobSel,&LocSel);

     pgisInfo = MAKEPGINFOSEG(GlobSel);
     plisInfo = MAKEPLINFOSEG(LocSel);

     if ((pgisInfo -> sgCurrent) == (plisInfo -> sgCurrent))
         printf("Current foreground process\n"
                "Process Screen Group = %u Current Screen Group = %u\n",
                plisInfo -> sgCurrent,pgisInfo -> sgCurrent);
     else
         printf("\n\n\n\n\n\nNot current foreground app\n"
                "Process Screen Group = %u Current Screen Group = %u\n",
                plisInfo -> sgCurrent,pgisInfo -> sgCurrent);
 }


 568. OS/2 SDK: QuickHelp POLYLINE Sample Code Is Incorrect

 Microsoft has confirmed that the following problems exist in the
 versions of QuickHelp included with the Version 1.06 and Version 1.10
 OS/2 SDK (Software Development Kit); we are researching these
 problems and will post new information as it becomes available. The
 POLYLINE.C sample code is incorrect and needs the following changes
 made to it:

 1. The definitions for CLR_PALE* should be replaced with CLR_DARK*
    (error).

 2. DosCreateThread() should be prototyped properly because it is
    producing a warning message.

 3. The Thread() function should be prototyped properly because it
    is producing a warning message.

 4. STRING.H should be #included in POLYLINE.C, because a warning
    message is being displayed.

 Another problem related to the POLYLINE example in QuickHelp is that
 if you select any of the source files (POLYLINE.C, POLYLINE.H,
 POLYLINE.RC, or POLYLINE.DEF) other than the makefile (POLYLINE.MAK)
 and then use the Reference menu selection to try to select the
 makefile, QuickHelp will incorrectly attempt to select "POLYLINE" with
 no .MAK extension. This results in an error of "polyline topic not
 found."

 The POLYLINE sample source code is still contained in the versions of
 QuickHelp included with Versions 1.06 and 1.10 of the OS/2 SDK, but
 this source code has been removed from the version of QuickHelp
 included with the OS/2 Version 1.10 PTK (Programmer's Tool Kit).


 569. OS/2 SDK: PMDD.SYS Functionality

 Question:

 What is the functionality of PMDD.SYS? I cannot find any
 documentation on it in the manuals.

 Response:

 It is the SINGLEQ driver. Its purpose is to provide serialization of
 multiple events from multiple input devices (e.g. keyboard, mouse,
 light pen, trackball, etc.). It has no options and is necessary for
 PM (Presentation Manager) operation. This is how PM can respond to
 mouse and keyboard events in sequence but seemingly at the same time
 without delay. All the input events are funneled into the SINGLEQ
 driver, and PM reads out of this queue. This way all events are
 captured, and the sequence of events is preserved.

 PMDD.SYS is not documented because it's a necessary item that the
 INSTALL program puts in the user's CONFIG.SYS file and is therefore
 apparent to the user. If you only have one input device, it is
 possible that you can get by without it, but this is subject to
 change in future versions of PM.


 570. OS/2 SDK: EGA.SYS Functionality

 Question:

 My system is equipped with a VGA card and monitor. After installing
 OS/2 Version 1.10, the CONFIG.SYS file contains a line with
 "DEVICE=C:\OS2\EGA.SYS". Why is the EGA.SYS driver installed? Is this
 optional during installation?

 Response:

 The EGA.SYS driver is a real-mode-only driver. It is added to your
 CONFIG.SYS file if you accept an installation that includes the DOS
 3.x Box. It is a driver that shadows the EGA registers, and if it
 isn't included, it may prevent certain high resolution graphic
 programs from working properly in the DOS 3.x Box. It is also used by
 the mouse driver in certain video modes when in the DOS 3.x Box.

 The functionality of EGA.SYS is not really related to the
 monitor/adapter type, but to what modes your applications may or may
 not use under real mode. Any time you run an application that might
 program the monitor/adapter to an EGA mode (whether you have a VGA or
 not), you will probably want to have this driver loaded. This is
 true for graphics modes only; text modes are not a problem.

 You could leave EGA.SYS out without causing a problem. The driver
 will not load if OS/2 finds EGA.SYS in CONFIG.SYS, and PROTECTONLY is
 set to YES.


 571. OS/2 SDK: Using MSGBIND to Bind Message Segment to Executable

 Question:

 Can the MSGBIND utility be used to bind a message file that is larger
 than 64K?

 Response:

 The MSGBIND utility is used to modify an OS/2 executable file to
 contain RAM-based messages. It takes a message file and "binds" the
 file to the executable. Thus, the executable does not need to have
 external message files to be able to display messages with the
 DosGetMessage(), DosInsMessage(), and DosDosPutMessage() APIs.

 The code segment for the message APIs are placed in a code segment
 publicly called MSGSEGCODE. The MSGBIND utility and the Dos*Message()
 set of APIs are designed so that only a single segment of messages can
 be bound to an executable file. Therefore, although a message file can
 be larger than 64K, a message file must fit into a single segment in
 order for MSGBIND to bind the message segment to the executable. If a
 message file is larger than 64K, then the executable can use the
 Dos*Message() set of APIs to manipulate this external file.


 572. OS/2 SDK: QuickHelp 1.10 Numeric Keypad ENTER Key Problem

 Microsoft has confirmed that the following problem occurs with the
 version of QuickHelp included with the Version 1.01 OS/2 SDK (Software
 Development Kit). The numeric keypad ENTER key on a 101 keyboard
 doesn't always work in QuickHelp. For example, after installing
 QuickHelp as a TSR (terminate-and-stay-resident) program, do the
 following:

 1. Press ALT+Q.

 2. Press "V".

 3. Press "I".

 4. Select QuickHelp.

 5. Press "R".

 6. When the ENTER key on the numeric keypad is pressed, there is no
    response. However, when the ENTER key on the main keyboard is
    pressed, the appropriate response is returned.

 We are researching this problem and will post new information as
 it becomes available.


 573. Determining If File Handle Is for a File or Character Device

 Question:

 Given a file handle, is there any way to tell if that handle is for a
 file or for a device? I want to be able to check for the serial (COM)
 ports.

 Response:

 To determine whether a handle is for a device or a file, use the
 DosQHandType() call. This function will tell you whether the handle is
 a device, a file, or a pipe. Also, if the handle is a network handle,
 this value is ANDed with the device, file, or pipe value.

 To determine whether a serial port is being used, look for COMn:.


 574. KBDKEYINFO and KBDINFO Information Incorrect in Windowed Mode

 The KBDKEYINFO and KBDINFO structures contain different values,
 depending on whether you are running in full-screen or windowed mode.
 In certain cases, the information contained in these structures can be
 incorrect in windowed mode.

 Microsoft has confirmed this to be a problem in the Version 1.10 OS/2
 SDK (Software Development Kit). We are researching this problem and
 will post new information as it becomes available.

 The program below illustrates this problem. Before using this program,
 turn on all the lock keys (SCROLL LOCK, NUM LOCK, and CAPS LOCK). In
 full-screen mode, the fsState after the first KbdGetStatus() is set to
 "0X70", which is correct, but in windowed mode, it incorrectly returns
 0 (zero). The following is a sample program:

 /* test program */
 #include <os2.h>

 #define KbdHandle       0

 main ()
 {
         KBDKEYINFO kp;          /* keyboard packet */
         KBDINFO ks;
         unsigned err;

         printf ("Press ESC to quit...\n");

         do {
                 ks.cb = sizeof (ks);
                 KbdGetStatus (&ks, KbdHandle);
                 printf ("After KbdGetStatus:\n");
                 printf ("\t ks.cb (in hex): %X\n", ks.cb);
                 printf ("\t ks.fsMask (in hex): %X\n", ks.fsMask);
                 printf ("\t ks.chTurnAround (in hex): %X\n",
                         ks.chTurnAround);
                 printf ("\t ks.fsInterim (in hex): %X\n", ks.fsInterim);
                 printf ("\t ks.fsState (in hex): %X\n", ks.fsState);

                 err = KbdCharIn (&kp, IO_WAIT, KbdHandle);

                 printf ("\nAfter KbdCharIn:\n");
                 printf ("\t kp.chChar (in hex): %X\n", kp.chChar);
                 printf ("\t kp.chScan (in hex): %X\n", kp.chScan);
                 printf ("\t kp.fbStatus (in hex): %X\n", kp.fbStatus);
                 printf ("\t kp.bNlsShift (in hex): %X\n", kp.bNlsShift);
                 printf ("\t kp.fsState (in hex): %X\n\n", kp.fsState);
         } while (kp.chChar != 0x1B);
 }
 /* end test program */


 575. Current Mouse Driver List for OS/2 Version 1.10

 The following is a list of the mouse drivers currently released with
 OS/2 Version 1.10:

    Driver        System  Mouse
    ------------  ------  -----------------------------------------

    MOUSEA00.SYS  PC/AT   Mouse Systems Mouse
    MOUSEA01.SYS  PC/AT   Visi-On Mouse
    MOUSEA02.SYS  PC/AT   Microsoft Serial Mouse (039-099, 039-199)
    MOUSEA03.SYS  PC/AT   Microsoft Bus Mouse (037-099, 037-199)
    MOUSEA04.SYS  PC/AT   Microsoft InPort (parallel) Mouse
    MOUSEA05.SYS  PC/AT   IBM Personal System/2 Mouse
    MOUSEB00.SYS  PS/2    Mouse Systems Mouse
    MOUSEB01.SYS  PS/2    Visi-On Mouse
    MOUSEB02.SYS  PS/2    Microsoft Serial Mouse (039-099, 039-199)
    MOUSEB05.SYS  PS/2    IBM PS/2 Mouse


 576. OS/2 SDK: Reallocating Huge Segments of Memory

 Question:

 There appears to be a barrier at 64K for the DosAllocSeg(),
 DosReAllocSeg(), DosAllocHuge(), and DosReAllocHuge() APIs. How do you
 allocate an amount of memory starting at less than 64K that can be
 reallocated at a later time to an amount greater than 64K?

 Also, the DosAllocHuge() API includes a parameter that defines the
 largest number of segments that can be reallocated. How do you define
 a huge segment that can be reallocated to any larger size?

 Response:

 Due to the Intel 80286 protected mode memory management hardware
 model, OS/2 restricts each segment to 64K or less. Because of this
 environmental constraint, a single segment in OS/2 cannot be grown to
 be greater than 64K.

 However, OS/2 tries to overcome this hardware restriction by making
 what it calls huge segments, which are a series of multiple 64K
 segments with selectors spaced equidistantly that are linked together
 by a method of shifting between each 64K segment.

 The DosGetHugeShift() API returns the shift count, which is used to
 determine how near or how far these segments are spaced. The
 DosAllocHuge() API allocates the series of huge segments. When using
 this API, you specify the number of segments to allocate (and since
 the last segment can possibly be less than 64K, this is specified in
 bytes as a separate parameter). In addition to specifying how many
 segments to allocate, the DosAllocHuge() API has another parameter
 that allows you to specify the maximum number of segments that can be
 called by the corresponding DosReallocHuge() API.

 This means that if you allocate 3 segments (2 full segments plus a
 partial segment) and specify that a maximum of 10 segments will ever
 be used, then DosAllocHuge() will reserve 10 entries in your LDT
 (local descriptor table) and will allocate 3 segments of memory for
 your immediate use. Later, you could use the DosReallocHuge() API to
 allocate some of the additional 7 segments.

 However, once you've called DosAllocSeg() and specified the maximum
 number of segments that this series of huge segments will be, you
 cannot change this number to a larger value. Of course, you could free
 up the set of huge segments by invoking DosFreeSeg() and passing it
 the first selector in the set. You then could allocate the huge
 segment set again with your new maximum value. However, this is not a
 reasonable thing to do. We recommend that you choose a realistic
 maximum for the initial invocation of DosAllocHuge().


 577. Reading and Writing Files with Different Codepages

 Question:

 Does Microsoft have a standard way of dealing with saved files written
 in one codepage and read in another codepage?

 Response:

 Codepage support in MS-DOS Versions 3.30 and 4.00, and in OS/2
 Versions 1.00 and 1.10 does not have a way to tie a codepage to a
 file. We agree that it would be very useful to know what codepage a
 file was created under, so that this same codepage could be used to
 process the file at some later time.

 However, as mentioned, this support is not available. If the file is a
 data file of your own, or in some other way has the ability to store
 information in it, it would be wise to store the codepage in the file
 somewhere. This is difficult to do in some cases. For example, in .EXE
 files created by linkers or in ASCII text files that a user created in
 an editor, there really isn't room for such a field.

 The best place to store this information would probably be outside the
 file, stored with the other file characteristics such as the file
 date, time, attributes, size, etc. This idea of tagging a codepage to
 a file is under consideration by the MS-DOS and OS/2 groups, and will
 be considered for inclusion in future releases of these operating
 systems.

 If the information (on what codepage the file was created with) is not
 stored by the operating system (as is currently the case), and the
 information is not contained within the file itself, then there are
 few other places for a program to get this information. You could ask
 the user for this information, or you could store this information in
 some other location, such as an initialization file or an environment
 variable. Of course, all of these alternatives have disadvantages and
 are not foolproof, since they rely on the user to tell the application
 what codepage should be used.

 One way you can store this information is to have a variable in
 OS2.INI that specifies the default codepage for the application. When
 interpreting a file, you can then assume that this variable is the
 default codepage and act accordingly. Then, the application needs a
 way for the user to change the default codepage value, such as in a
 setup portion of the application. In addition, it might also be
 helpful to have such an option in a dialog box when reading any files,
 so that the user would have the ability to change this value on the
 fly.

 Finally, you can obtain this type of information from the country
 information, which you can get from OS/2 by calling the
 DosGetCtryInfo() function. If you specify default codepage and country
 information in the COUNTRYCODE structure (which tells this API which
 country and codepage to get information on), this API will return the
 COUNTRYINFO structure filled with the default country and codepage. If
 you have no other idea about which codepage to default to, you could
 try defaulting to the current country's default codepage.

 Please refer to the QuickHelp databases or to the "Microsoft Operating
 System/2 Programmer's Reference Volume 3" for more information on the
 DosGetCtryInfo() API and the COUNTRYCODE and COUNTRYINFO data
 structures.

 When all else fails, default to codepage 850, the multilingual
 codepage.


 578. Jumper UB Card to Work in 8-Bit Mode with NCR PC-916

 The NCR PC-916 computer will not run any OS/2 1.10 release until the
 Ungermann-Bass 16-bit network card in it is jumpered to run at 8-bit
 mode (you still use the 16-bit LANMAN driver, and it's 5 percent or
 less slower).


 579. How to Use Mouse Driver in DOS 3.x Box Under OS/2

 The OS/2 mouse device drivers included with the OS/2 SDK (Software
 Development Kit) have different command-line arguments. The following
 command-line argument, the MODE option, controls which environment the
 mouse driver will be used in:

    MODE=<mode>

 This option specifies whether you'll be using the mouse in an OS/2
 session, the DOS session, or both sessions. Acceptable values for mode
 are P (protected mode, OS/2 session), R (real mode, DOS session), and
 B (both sessions); the default is B.

 Therefore, if B is specified, the mouse driver is set up to work in
 both modes. This will allow three classes of applications to use mouse
 input: OS/2 base applications will be able to use the MOU* subsystem
 APIs, OS/2 Presentation Manager applications will be able to use the
 WM_MOU* message queue model mouse input, and real-mode applications
 running in the 3.x box screen group will be able to use the MS-DOS INT
 33H mouse input method.

 An MS-DOS mouse device driver (such as the Microsoft MOUSE.SYS driver)
 cannot be installed in the OS/2 CONFIG.SYS file. However, if no OS/2
 mouse device driver is installed, then it is possible to install a
 MS-DOS TSR (terminate-and-stay-resident) mouse driver (such as the
 Microsoft MOUSE.COM driver), since it does not have the same list of
 restrictions as real-mode device drivers.

 Running a MS-DOS mouse program such as MOUSE.COM is mutually exclusive
 with loading an OS/2 mouse device driver such as MOUSExxx.SYS.

 Finally, some versions of some applications (such as Windows/286) can
 at times bypass the conventional MS-DOS driver mechanisms and obtain
 mouse input directly from the mouse hardware. If these programs cannot
 be modified (or patched) or in some other way changed to use the
 MS-DOS INT 33H mouse input standard, then these applications cannot
 obtain mouse input in the OS/2 DOS 3.x box. In the case of Windows,
 there is a patch available that allows the mouse to work. Newer
 versions of Windows will work without the application of this patch.
 Information on this patch can be found by searching on the words
 "mouse and patch" in the KnowledgeBase.


 580. Determining Amount of Data Written to Swap File

 Question:

 When OS/2 swaps out memory, does it write 64K worth of data to the
 swap file, or does it only write the number of bytes contained in the
 segment?

 Response:

 The swapper writes only the bytes in the segment and always rounds
 writes out to a sector boundary. Reads are the same, with the swapper
 always starting reads on a sector boundary with at most one partial
 trailing sector.


 581. OS/2 SDK 1.10 PM Line Drawing Character Problem

 The ASCII line drawing characters defined to be 179 and 212 do not
 line up correctly in a Presentation Manager (PM) windowed command
 processor. The 212 character's vertical line is offset 1 pixel too far
 to the left.

 Microsoft has confirmed this to be a problem in Version 1.10 of the
 OS/2 SDK (Software Development Kit). We are researching this problem
 and will post new information as it becomes available.


 582. OS/2 SDK: Setting and Using File Attributes

 Question:

 I have the following questions regarding the use and setting of file
 attributes:

 1. Is it correct that OS/2 sets the FILE_ARCHIVED attribute of a file
    only when the file is created or opened with OPEN_ACCESS_WRITEONLY
    or OPEN_ACCESS_READWRITE?

 2. My program wants to use DosFindFirst() [and DosFindNext(), if
    necessary] to search for existing files that have the FILE_ARCHIVED
    attribute set. Setting the DosFindFirst() attribute argument to
    FILE_ARCHIVED doesn't seem to find only files with the ARCHIVED
    attribute. Rather, all NORMAL files are returned. Is there a way to
    tell DosFindFirst() to only return names of files with the ARCHIVED
    attribute set?

 3. What does it mean when an application gives only the attribute
    parameter FILE_ARCHIVED to DosFindFirst()?

 Response:

 The following are answers to the questions above:

 1. Yes, you are correct. However, the explanation is usually more
    generalized: whenever a file is modified, the archive bit is set.
    This only happens when a file is opened and written to, or when a
    file is created.

 2. No, whenever DosFindFirst() and DosFindNext() search for files, all
    normal files, plus whichever other files have the attribute you are
    looking for, are returned. All you can do is check the attributes
    when you get a file returned from your DosFindFirst()/Next() call
    to see if any other attributes are set.

 3. When an application gives only the attribute parameter
    FILE_ARCHIVED to DosFindFirst(), you will get back all files that
    have the archive bit set, plus all normal files. You need to check
    the attribute byte of each file to see if it has the attribute bit
    set.



 583. OS/2 SDK: Determining If Math Coprocessor Is Present

 Question:

 Is there an API call for determining the presence of a math
 coprocessor?

 Response:

 Yes; the DosDevConfig() API call allows you to determine such things
 as number of printers attached, number of serial ports, number of
 floppy disk drives, presence of a coprocessor, and a few other machine
 configuration variables, depending on the type of information that you
 request. The following program demonstrates how to determine if a
 coprocessor is installed:

 #define INCL_BASE
 #include <os2.h>
 #include <stdio.h>

 void main(void);

 void main(void)

 {
     BYTE    fPresent;
     USHORT  usResult;

     usResult = DosDevConfig(&fPresent,DEVINFO_COPROCESSOR,0);

     if (usResult)
         printf("Error in DosDevConfig call: %u\n",usResult);
     else
         if (fPresent)
             printf("Coprocessor present.\n");
         else
             printf("No coprocessor present.\n");

 }


 584. Using Processor Extension Exist Subclass Vector

 Question:

 I am trying to provide an application with a VIO pop-up instead of
 the standard OS/2 Exception VIO pop-up for the
 "processor_extension_not_available" exception. I am using DosSetVec()
 to set up my own vector. I then put up my own VIO pop-up and pass
 control to the default vector returned in the DosSetVec() invocation.

 All works well in the application. However, when the first
 floating-point routine is called, this exception is taken. It appears
 by registering my own vector here; the first floating-point operation
 executed causes this exception itself. How can I cause the
 floating-point operations to be performed without this exception?

 Response:

 The behavior you are seeing when you use DosSetVec() to install your
 exception handler for the "processor_extension_not_available"
 exception is correct. Although the documentation is not very clear
 about this topic, the purpose of making this exception available to
 application programs is to allow them to install their own
 floating-point emulator even if a numeric coprocessor is installed in
 the system.

 As a result, every time a floating-point operation is executed after
 you install this handler, the exception will be taken because OS/2 has
 modified the MSW EM and MP bits to indicate "no coprocessor is
 present." Also, since access to the MSW is allowed only at privilege
 level 0, your application cannot change this behavior (because it runs
 at level 3).


 585. Installing CTRL+C and CTRL+BREAK Signal Handlers

 Question:

 How can different signal handlers be installed for CTRL+C and
 CTRL+BREAK signals? Whenever I attempt to install two signal handlers,
 the CTRL+C signal handler is invoked when either CTRL+C or CTRL+BREAK
 is generated from the keyboard.

 Response:

 You can never generate these two signals; the method of keyboard input
 (cooked or raw) is a factor in how they are read in.

 When keyboard input is in cooked mode, CTRL+C and CTRL+BREAK both
 generate a SIGINTR signal.

 When keyboard input is in raw mode, CTRL+C signals are not trapped and
 are read in via the keyboard input mechanism as the 0x03 character
 (and the 0x02E scan code). Therefore, in raw mode, you should check
 the key received by the keyboard input mechanism if you want to act on
 the CTRL+C character.

 If you require two different handlers to be available for these two
 different keystrokes, you should set up a CTRL+BREAK signal handler to
 intercept the CTRL+BREAK key and read keystrokes in raw mode looking
 for the CTRL+C key.


 586. Spawning a Full-Screen or Windowed Session

 Problem:

 From my application, I would like to give the user the ability to
 spawn off another session that will run a full-screen editor (in
 either a window or a full-screen mode). I tried to do this using
 DosCreateSession(), but I wasn't successful; I kept getting the return
 error code of 491 (ERROR_SMG_INVALID_PROGRAM_TYPE).

 Response:

 Use DosStartSession() instead of DosCreateSession(). The two APIs for
 executing an application are DosStartSession() and DosExecPgm(). The
 DosStartSession() API has more functionality, and it allows you to
 specify the type of executable you are trying to execute (e.g. full-
 screen, Presentation Manager, etc.). This information is stored in the
 "SessionType" field of the STARTDATA data structure used by
 DosStartSession(). The "SessionType" field, which determines what
 session type the program should be executed in, can have one of the
 following values:

    0  Let OS/2 or the STARTDATA.PgmHandle determine the session type.
    1  Full-screen VIO application in its own screen group.
    2  Windowable VIO application in a PM screen group.
    3  PM (or AVIO) application in a PM screen group.

 Because you want to execute a full-screen VIO application in its own
 screen group, you should set STARTDATA.SessionType equal to 1 when you
 use DosStartSession().

 Included below is a condensed version of the logic that CMD.EXE uses
 to determine which API to call when executing an application. CMD.EXE
 has to execute full-screen and windowable VIO applications, AVIO
 applications, and PM applications, from either a full-screen group or
 a PM screen group. CMD.EXE will use either DosExecPgm() or
 DosStartSession() to execute a program based on both of the following:

 1. What kind of executable the program to execute is [this information
    is obtained by reading the EXE header or by calling DosQAppType()]

 2. What kind of screen group is currently being run [this information
    is stored in DosGetInfoSeg()'s LINFOSEG.typeProcess]

 In summary, DosStartSession() is used to execute PM and AVIO
 applications. DosStartSession() is also used when CMD.EXE is running
 in a PM screen group and trying to execute a full-screen application;
 DosExecPgm() is used when executing VIO applications. The following
 table shows these relationships:

                          Windowable VIO
    Executable            (aka PM Screen)    Full-Screen VIO
    Type of File          Screen Group       Screen Group
    --------------------  -----------------  -----------------

    Full-Screen VIO       DosStartSession()  DosExecPgm()
    Windowable VIO        DosExecPgm()       DosExecPgm()
    Advanced VIO          DosStartSession()  DosStartSession()
    Presentation Manager  DosStartSession()  DosStartSession()


 587. WIN Memory Management Routine Information

 Question:

 Why were the WinCreateHeap() function and its associated WIN functions
 made into WIN functions rather than just base functions?

 Response:

 The Windows (WIN) memory management routines are APIs that were added
 by the Presentation Manager (PM) developers in the OS/2 development
 group. They were added because they are presumably faster in some
 areas than the base memory management routines.

 The WIN memory management routines should be used only by PM or AVIO
 applications. You must call WinInitialize() before you call
 WinCreateMsgQueue(). After these two calls are made, you can then
 begin using the WIN memory management APIs, starting with the
 WinCreateHeap() API. WinInitialize() must be called before any other
 WIN function is called. WinCreateMsgQueue() internally initializes
 some WIN memory management information, so it must be called before
 WinCreateHeap() (or any other GPI calls, for that matter) is called.


 588. DevHlp_Lock Return Handle Information

 Question:

 Is the lock handle returned from DevHlp_Lock just a 32-bit physical
 address? If it is an address, can it be passed across process
 contexts?

 Response:

 The handle returned by the DevHlp_Lock function is NOT a 32-bit
 physical address. It is a unique number used to identify that block of
 memory to the OS/2 memory manager. You must supply this handle to
 DevHlp_UnLock when you are done using the memory.

 To obtain a 32-bit physical address after using DevHlp_Lock, you must
 do a DevHlp_VirtToPhys. This will give you a fixed 32-bit address that
 can be used across process contexts. We strongly recommend that you
 also do a DevHlp_VerifyAccess in protected mode to confirm that the
 user has access to the memory segment in question before the
 DevHlp_Lock is done. All of this information is explained in the
 Microsoft OS/2 DDDK (Device Driver's Development Kit) Version 1.10
 documentation, and also in the book "Advanced OS/2 Programming," by
 Ray Duncan.


 589. Allocating Memory in One Thread & Freeing It in Another Thread

 Question:

 Can you allocate memory in one thread and free it in another thread?
 The QuickHelp documentation under the "Heap Management Overview"
 implies that different threads can't share a heap.

 Response:

 Yes, you can allocate memory in one thread and free it in another
 thread. Threads are both part of a single process, and the memory is
 owned by the process, not the thread. However, you have to make sure
 that your threads cooperate with these "global" resources. If one
 thread tries to free up memory that another thread is using, then your
 code will not function properly. Because potential problems may occur,
 applications that don't need to commonly allocate and free memory in
 different threads should not do so, and the applications should
 instead allocate and free the memory in a single place; this avoids
 potential contention problems within threads. However, a properly
 designed application whose threads properly cooperate should have no
 problem commonly allocating and freeing memory.

 Also, consider that many threads allocate memory for their own stack
 and local variables. This memory, while actually not owned by any one
 thread, is generally considered to be off limits by other threads.


 590. Caller's Process Context Information

 Question:

 We have a device driver whose primary scheduling is off of the threads
 that started up the process; this is how our device driver (which
 requires a lot of asynchronous scheduling capability) gets its
 timeslice independent of any calling user threads. When the user
 threads call our strategy routine with IOCTLs and the like, are we
 running in the caller's process context? Hence, when the threads
 awaken, is it considered a separate process context?

 Response:

 When an application (user thread) calls a device driver [through OS/2
 via DosDevIOCtl(), DosRead(), DosWrite(), etc.], the strategy routine
 runs in that user thread's context. This means that the strategy
 routine is on the user thread's kernel stack, and in the user thread's
 LDT (local descriptor table). These values will be unique for every
 thread that invokes the device driver. Thus, the device driver does
 run in the calling thread's process context when it is entered; this
 is different from any other process's context that may have previously
 called your device driver.


 591. Trying to Predict Dynamic Linked Library Initialization Order

 Problem:

 Is there any way to predict the initialization order of DLLs (dynamic
 linked libraries)? I have a DLL that, as part of doing its
 initialization routine, needs to call another DLL. However, the second
 DLL needs to perform some housekeeping code when it gets initialized.
 As it stands now, the second DLL has not been initialized before I
 call it, and consequently it doesn't load correctly. How can I correct
 this problem?

 Response:

 There is no reliable, portable way for OS/2 to guarantee the load
 order or the initialization order of a DLL when an application has
 multiple DLLs.

 One method of reliably determining the way DLLs are used is to use an
 initialization mechanism similar to the one that PM (Presentation
 Manager) uses. PM has a specific initialization function in each DLL
 [for example, something such as WinInitDLL() for PMWIN.DLL and
 GreInitDLL() for PMGRE.DLL]. The application controlling the DLLs and
 requiring some specific loader order should call into the
 initialization functions explicitly in the order that they require.

 Another method of reliably determining the way DLLs are used is to
 explicitly call them yourself via DosLoadModule(), rather than by
 letting the EXE loader implicitly load the DLLs for you. In this way,
 you'll know that a certain DLL will be called before another, since
 your application called them in that order.

 One other method that you could use is to modify the initialization
 routines of the DLLs so that one calls the other; this will ensure
 that the second one is loaded properly. This is rather reverse logic:
 the first DLL calls the second one, which ensures that the second one
 is fully loaded. This is rather like the first DLL making sure that
 the second one is loaded first, but in reverse order. This sort of
 calling sequence will help lock your dependencies between the DLLs,
 and will enforce that the DLLs are loaded/initialized in ways that you
 can depend on.

 The first method (PM initialization mechanism) is the cleanest method,
 but you may use any of the methods described above.


 592. DosExit() Terminates Parent Before Child Processes Are Done

 When the DosExit() system function is called, it waits for all of the
 child processes to terminate before terminating the parent [which
 called DosExit()]. The DosStartSession() function can be used to start
 a completely independent process that no longer is affected by
 anything the parent process does [including the use of DosExit()].


 593. Exitlist Routines Are Run If GP Fault Occurs in Main Program

 Exitlist routines are run if a GP fault occurs in the main program. If
 the GP fault occurs in the exitlist routine, the exitlist routine will
 not be run again.

 The following sample program demonstrates that exitlist routines are
 run if a GP fault occurs in the main program:

 /* gp.c - compile "cl gp.c" */

 #define INCL_BASE

 #include <os2.h>
 #include <stdio.h>
 #include <conio.h>
 #include <io.h>

 void pascal far CleanUp(USHORT arg);
 void main(void);

 void main(void)
 {
    char c;

    DosExitList(EXLST_ADD, CleanUp);

    printf("\nstrike a key to continue...");
    getch();
    puts("");

    printf("\n generate a protection violation...\n");
    c = *((char far *)0xb8000);
    printf("\n code after protection violation...\n");

    DosExit(EXIT_PROCESS, 0);
 }

 void pascal far CleanUp(USHORT arg)
 {

    switch (arg) {

       case TC_EXIT:
          VioWrtTTY("\n\rThis process terminated normally...\n\r\n",
                     40, 0);
          break;

       case TC_TRAP:
          VioWrtTTY("\n\rThis process was terminated by a trap...
                     \n\r\n", 45, 0);
          break;

       case TC_HARDERROR:
          VioWrtTTY("\n\rThis process was aborted from a hard error
                    ...\n\r\n", 50, 0);
          break;

       case TC_KILLPROCESS:
          VioWrtTTY("\n\rThis process was killed by a signal...
                    \n\r\n", 43, 0);
          break;
    }

       DosExitList(EXLST_EXIT,0L);         /* Termination complete */
 }


 594. Different Software Methods That Can Be Used to Reboot OS/2

 In the Software/Data Library is an archived file named REBOOT that
 contains two different methods of rebooting a system running OS/2.
 This file can be found in the Software/Data Library by searching on
 the keyword REBOOT, the Q number of this article, or S12362. REBOOT
 was archived using the PKware file-compression utility.

 REBOOT contains the following files:

    BOOTDD
    BOOTDD.ASM
    BOOTDD.DEF
    BOOTDD.SYS
    REBOOT.C
    REBOOT.EXE

    RB8042
    RB8042.ASM
    RB8042.DEF
    RB8042.EXE

 How to Reboot the System Using a Device Driver
 ----------------------------------------------

 You can reboot the system using a device driver, which can call the
 DevHlp GetDOSVar() (Service 24H), using index 05H to retrieve the
 DWORD reboot vector. After obtaining this information, the device
 driver can then reboot the system. Included in REBOOT is a sample
 device driver (named "REBOOT$") that does this. A sample application
 is also included in REBOOT that calls this sample device driver. The
 sample program performs a DosOpen() on the device driver "REBOOT$",
 and then sends it an IOCtl (category 80H, function 41H) via
 DosDevIOCtl(), which causes the system to reboot.

 For more information on writing device drivers, refer to the
 "Microsoft OS/2 Device Driver Reference."

 How to Reboot the System Using the Keyboard Controller
 ------------------------------------------------------

 You can reboot the system using the keyboard controller by having an
 application running at ring 2 (IOPL) that sends the data to the 8042
 Keyboard Controller to pulse the system reset pin. This can be
 accomplished by sending the value 0x00FE to the port address 0x64.
 After you have sent this value, a "cold boot" will occur. Included in
 REBOOT is an application that will accomplish this. Please note that
 this method will NOT work on any system that doesn't use an 8042
 Keyboard Controller. In addition, this method may not work in future
 releases of OS/2. If an OS/2 release specific to the 80386 is ever
 released, the operating system will be able to control access to
 ports, preventing a rogue application from rebooting the system.

 For more information on writing applications, refer to the "Microsoft
 OS/2 Programmer's Reference" manuals (three volumes). For more
 information about hardware (such as the keyboard hardware), refer to
 your system's hardware technical reference.

 Conclusion
 ----------

 In summary, the device driver method is more portable than the 8042
 Keyboard Controller method, since the device driver asks OS/2 for the
 location to jump to in order to reset the system. The Keyboard
 Controller method assumes that particular 8042 hardware exists, and
 may not work in future releases of OS/2 if access to certain I/O ports
 are considered off limits to IOPL applications. If any ports would be
 considered off limits, it would most likely be dangerous ports, such
 as this one, that allow applications to reset the system.

 Of course, you should be aware that rebooting a multitasking operating
 system is not a wise thing to do, because unlike in MS-DOS, your
 application is not the only program running on the system. We do not
 recommend that any normal application reboot the system. We recommend
 that any application that does reboot the system should give you ample
 notice to properly terminate all other active processes running in the
 system.


 595. PS/2 Profiler in OS/2 SDK 1.10 Only Works with PMSHELL

 Under the PS/2 kernel running the pinfo (profiler) utility with a
 dumpfile, will show the name of PMSHELL, (or PMEXEC), instead of the
 test application name. When running pinfo with a dumpfile and a map
 file, the error "Ignored: No segments for module XXX" occurs. Running
 the same series of commands on the AT profile kernel works correctly.

 Microsoft has confirmed this to be a problem with the Profiler
 included with the OS/2 SDK (Software Development Kit) Version 1.10. We
 are researching this problem and will post new information as it
 becomes available.


 596. Translating DosDevIOCtl() OS/2 Calls to MS-DOS Calls

 Question:

 I have some questions about the portability of applications from one
 operating system to another operating system. Specifically, are the
 OS/2 DosDevIOCtl() functions for the COM driver supported by the
 MS-DOS COM driver? If not, then we need to make a MS-DOS driver that
 does support these functions, but where do we pass the parameters
 buffer? Also, please provide us with a full description of the IOCtl
 function supported by the MS-DOS COM driver.

 Response:

 The MS-DOS support for the serial ports is very minimal. Most work
 with the ports (via the Mode command) is done through the BIOS. When
 MS-DOS is reading from the port, it calls the device driver READ
 function and does similar things for WRITE.

 When you use the DosDevIOCtl() calls from OS/2 in a bound program, the
 DevIOCtl calls just turn the call into Interrupt 21, Function 44H
 calls.

 All parameters are passed, including the parameter packet. The
 following is a list of how the parts of the call are transferred from
 OS/2 to MS-DOS via the API.LIB library:

       AH = 44H
       AL = 0CH (handle IOCtls)
       BX = Device handle (hDevice)
       CH = Serial Category (0x0001)
       CL = Function Code
    DS:DX = Pointer to data buffer
    SI:DI = Pointer to parameter packet

 The current device driver does not look for the parameter packet, but
 you can write a device driver to do this.

 When the DosDevIOCtl() is passed through to MS-DOS via the generic
 IOCtl call, no parameters are checked. Therefore, any call that is not
 supported by MS-DOS or the device driver will get passed onto the
 driver. You should make sure that in your driver you have an escape
 clause for all generic IOCtls that are called that you don't support.


 597. Per-Process File Handle Limit Increased in OS/2 SDK 1.10

 Question:

 What is the maximum number of file handles allowed, and how is that
 maximum reached? On page 142 of the "Microsoft Operating System/2
 Programmer's Reference Volume 3 for Version 1.1," it states that
 DosSetMaxFH() limits the maximum number of file handles to 255 that
 can be provided to the calling process. Is this correct for OS/2
 Version 1.10?

 Response:

 No; this is a documentation error in both the "Microsoft Operating
 System/2 Programmer's Reference Volume 3 for Version 1.1" manual, and
 in the version of QuickHelp included with the OS/2 SDK (Software
 Development Kit) Version 1.10. This limit was correct for OS/2 Version
 1.00, but it is not correct for OS/2 Version 1.10. The limit of file
 handles in OS/2 Version 1.10 is 32K of file handles per system, with a
 per-process limit of 32K. Please note that since the per-system limit
 is the same as the per-process limit, and this is a multi-process
 operating system, it is doubtful that a single process will max out on
 all of the file handles, since some of them will be in use by other
 processes. The number of file handles per process by default is 20,
 with three file handles being automatically allocated to stdin,
 stdout, and stderr. For a process to open more than 20 file handles,
 the application must call the OS/2 API DosSetMaxFH().

 In contrast, the limit of file handles in MS-DOS Versions 3.30 and
 later is 64K per process, but with a system limit of 255 (the maximum
 value of the unsigned byte of FILES=nnn). Thus, while a single process
 can open 64K files, there are only 255 for the whole system to work
 with, so that the system can only have 255 unique files open at once
 but a process can open 64K duplicate handles to the same file. When
 SHARE is not loaded, the number of FCBs is limited only by the user's
 memory, which is itself under the 640K system limit. The number of
 file handles per process by default is 20, with five file handles
 being allocated automatically to stdin, stdout, stderr, stdaux, and
 stdprn. For a process to open more than 20 file handles, the
 application must call the MS-DOS service Interrupt 21H, AH=67H, the
 MS-DOS equivalent to the OS/2 DosSetMaxFH() function call.

 We will post new information when the documentation has been updated
 to correct this error.


 598. Coprocessor State of 80x87 Is on a Per-Process Basis

 Question:

 Does each thread in the system maintain its own 80x87 state if a
 coprocessor is present?

 Response:

 No, the coprocessor state of the 80x87 is kept track of on a
 per-process basis by OS/2. The coprocessor can be thought of as a
 resource; threads cannot own resources, only use them.


 599. Path Information of Critical Files Necessary for OS/2 Boot

 Question:

 Can you please provide us with a list of the files that must be on
 specified paths to assure system integrity during boot time? For
 example, does OS/2 look for PMWIN.DLL on DPATH, LIBPATH, or elsewhere?

 Response:

 When OS/2 boots, it needs OS2KRNL, OS2LDR, and the base (keyboard,
 video, disk, etc.) device drivers in the root directory. After that,
 OS/2 uses the LIBPATH variable to find DLLs, and the PATH directory to
 find any executable that it needs to run, if the executable is not
 found in the current directory. Any installable device drivers are
 loaded without any need for environment variables, and the
 command-line editor (usually CMD.EXE) is obtained via the COMSPEC
 environment variable. If the compatibility box is enabled, then the
 COMSPEC variable is set in AUTOEXEC.BAT to the location of
 COMMAND.COM. Otherwise, no other environment variables are used.


 600. 3.x Box Programming Limitations

 Listed below is some general information on the 3.x box of OS/2,
 including programming limitations under the OS/2 compatibility box and
 which BIOS and Interrupt calls are (not) allowed.

 Restrictions
 ------------

  1. The environment is that of MS-DOS Version 3.20 with SHARE installed.

  2. The MS-DOS 3.x network redirector will not work. New functionality
     is provided through the OS/2 LAN Manager.

  3. The 3.x box is frozen in the background (may lose interrupts for
     3.x box).

  4. Only old character device drivers can be used, and these may not
     issue INT 21H calls at initialization time.

  5. INT 13H and INT 26H may not access a hard disk.

  6. INT 2FH, the print spooler interrupt, returns with the error "Print
     spooler not installed, not OK to install." [INT 2F with (AL)= 0,
     Get installed state, returns with (AL)=1.]

  7. No direct calls to ROM services can be made (must use INT 10-1F).

  8. No calls can be made to user code from device drivers.

  9. No 3.x print spooler is allowed.

 10. No application may move the 8259 interrupt vectors.

 Device Drivers
 --------------

 Most device drivers in OS/2 are "new" model device drivers. These
 drivers are loaded as new-EXE modules, and the code is dual-mode so
 that they can handle interrupts in either real mode (RM) or protected
 mode (PTM). The drivers contain some RM code to support/manage the ROM
 Services interrupts that pertain to the device that the driver
 manages.

 The 3.x box has its own console driver (CON), which is separate from
 any PRM support, and thus may be replaced (by ANSI.SYS, for example).

 Please note that RM device drivers cannot issue INT 21H calls.

 The ROM BIOS performs programmed I/O, which is not acceptable in a
 multitasking operating system. Therefore, those ROM BIOS services
 that can take an appreciable amount of time to complete are emulated
 by the OS/2 device driver responsible for the appropriate device.

 The device drivers maintain those areas of the ROM Data Area
 (40:0-...) that relate to the device they service. They do all updates
 that are required at interrupt time, and they do updates for those ROM
 BIOS services that they emulate.

 Interrupt Management
 --------------------

 1. Hardware interrupts

    a. Master 8259 generates interrupts in the 50-57H range (as opposed
       to the default of 8-FH). The handlers at 50-57H route to the
       handlers at 8-FH.

    b. Slave 8259 generates interrupts in the 70-77H range, as usual.

    c. The Interrupt Manager checks for direct editing of interrupt
       vectors. Except for the keyboard interrupt, the 3.x box may only
       set a vector if it is not owned by a new device driver, and vice
       versa.

 2. Software interrupts

    OS/2 hooks the same vectors as in MS-DOS Version 3.20. It does not
    interfere with other software interrupt vectors.

 MS-DOS 3.x API Support
 ----------------------

 1. All INT 21H system calls documented in the references are
    supported. However, the file system acts as if SHARE is installed.

 2. INT 2FH, the print spooler interrupt, returns with the error "Print
    spooler not installed, not OK to install." [INT 2F with (AL)=0, Get
    installed state, returns with (AL)=1.]

 3. INT 24H, the hard error interrupt, is ignored. Real-mode
    applications may set this interrupt, but OS/2 never calls the
    application's handler.

 Interrupt Usage
 ---------------

 Vector   Usage                     Comments
 ------   -----                     --------

  0       Divide error

  1       Single step

  2       NMI

  3       Breakpoint

  4       INTO

  5       PrtSc

  6       Invalid opcode

  7       287 not present

  8-F     IRQ 0-7 jump table        Address of actual handlers.
                                    Master 8259 is moved to 50-57
                                    range so that chip faults can
                                    be differentiated from hardware
                                    interrupts when in protected
                                    mode. Also permits OS/2 to
                                    detect direct editing of these
                                    vectors.

 10       Screen                    OS/2 chains to track EGA
                                    write-only registers.
 11       Equipment

 12       Memory                    ROM Data area value changed by
                                    SysInit.

 13       Disk                      OS/2 chains to interlock disk
                                    access. Writes to hard disks are
                                    not allowed.

 14       Serial                    If the COM driver is loaded, it
                                    emulates to provide interrupt
                                    driven I/O.

 15       Misc

 16       Keyboard                  KBD driver checks for hotkey,
                                    blocks if no characters are
                                    available, else it passes on to
                                    the ROM.

 17       Printer                   PRT driver emulates.

 18       ROM BASIC

 19       Reboot

 1A       Time/date

 1B       CTRL+BREAK                KBD issues this on CTRL+BREAK.

 1C       User Timer                OS/2 IRQ 0 handler issues this.

 1D       Screen data

 1E       Floppy data               Maintained by disk driver code.

 1F       Screen font data

 20       DOS abort

 21       DOS functions

 22       DOS terminate addr

 23       CTRL+C handler

 24       Hard error handler        OS/2 never issues this.

 25       Abs disk read

 26       Abs disk write            Not allowed to hard disks.

 27       TSR

 28-29    DOS reserved - unused

 2A       IBM network

 2B-2E    DOS reserved - unused

 2F       Multiplex channels

 30-31    CALL 5 mechanism

 32       DOS reserved - unused

 33       MOUSE services

 34-38    DOS reserved - unused

 39-3E    BASIC or unused

 3F       Windows thunk loader

 40       BIOS hard/floppy hook

 41       First hard disk data

 42       BIOS INT 10 EGA hook

 43       EGA data

 44       EGA font

 45       Unused

 46       Second hard disk data

 47-4F    Unused

 50       IRQ 0 - timer             OS/2 receives interrupts for IRQ
 51       IRQ 1 - keyboard          0-7 in the 50-57 range. After
 52       IRQ 2 - mouse/NET/...     checking for direct editing of
 53       IRQ 3 - COM2/...          the INT 8-F vectors, it CALLS
 54       IRQ 4 - COM1/...          indirectly through those vectors.
 55       IRQ 5 - mouse/NET/...
 56       IRQ 6 - floppy
 57       IRQ 7 - printer

 58-5B    Unused

 5C       ROM BIOS Network

 5D-66    Unused

 67       EMM device driver

 68-6F    Unused

 70       IRQ 8 - real-time clock

 71       IRQ 9

 72       IRQ A

 73       IRQ B

 74       IRQ C

 75       IRQ D - 80287

 76       IRQ E - hard disk

 77       IRQ F

 78-FF    Unused

 For more information on this topic, please refer to the "Microsoft
 Operating System/2 Programmer's Reference" manuals (3 volumes), and
 the "Microsoft Operating System/2 Device Driver Guide."


 601. DEVINFO_SUBMODEL (Item) Parameter of DosDevConfig()

 Question:

 What is the DEVINFO_SUBMODEL (item) parameter of the DosDevConfig()
 function call defined to be?

 Response:

 Listed below are the particulars concerning the "item" parameter in
 the OS/2 DosDevConfig() function call:

    Item #      Information Returned
    ------      --------------------

    0           Number of attached printer ports

    1           Number of RS232 ports

    2           Number of removable disk (floppy) drives

    3           Math coprocessor presence:
                0 - not present, 1 - present

    4           PC (ROM BIOS) submodel code

    5           PC (ROM BIOS) model code

                Model Code  Submodel Code  Machine Type
                ----------  -------------  ------------

                FCH         0 or 1         PC/AT
                FCH         2              PC/XT-286
                FAH         0              PS/2 model 30
                FCH         4              PS/2 model 50
                FCH         5              PS/2 model 60
                F8H         0 or 1         PS/2 model 80

    6           Primary display adapter type:
                0 - monochrome, 1 - other

 Please note that the PC model/submodel codes come from the machine's
 ROM BIOS and are therefore OEM hardware-dependent. The validity of
 these codes is a hardware compatibility issue, since the codes were
 originated by IBM each time they came out with a new machine (not all
 machines/codes are listed above, since they don't apply to OS/2).


 602. QuickHelp -t Option Broken in Versions 1.06 and 1.10

 When you specify the -t option, QuickHelp does not display its window.
 Instead, it searches for the topic specified on the command line,
 pastes the topic to the current paste file, and then exits.

 You should be able to copy either the entire topic of an OS/2
 function into the paste file, or just the syntax or example sections
 of that topic, depending on what you specify on the command line. For
 example, if you type the following, QuickHelp should find and copy the
 entire DosBeep() topic and paste it into the current paste file:

    qh DosBeep -t all

 Similarly, if you type

    qh DosBeep -t syntax

 or

    qh DosBeep -t example

 QuickHelp should find and copy just the syntax or example section of
 the DosBeep() topic, and then paste it into the current paste file.

 Microsoft has confirmed that in Version 1.39 of QuickHelp that was
 released with Version 1.10 of the OS/2 SDK (Software Development Kit),
 and in Version 1.40 of QuickHelp that was released with Version 1.10
 of the OS/2 Presentation Manager Toolkit, the -t switch does not copy
 and paste just the syntax or example section of a topic. If you
 specify "-t syntax" or "-t example" at the command line, QuickHelp
 responds with a message box that contains either "Syntax section not
 found in <Topicname>" or "Example section not found in <Topicname>."
 We are researching this problem and will post new information as it
 becomes available.


 603. Retrieving Description Information from .EXE Header

 Question:

 If an .EXE file is built using a .DEF file that contains a
 DESCRIPTION directive, is there a way to retrieve that description
 from the .EXE file (e.g. is there a field in the EXE header that
 indicates where the description is stored)?

 Response:

 The description can be found by checking the following location:

 The offset to the nonresident names table is located at offset 2CH
 relative to the start of the file. The first entry in the nonresident
 names table is either the description string (if defined in the .DEF
 file) or the name of the file.

 For more information, see Pages 720-725 in Ray Duncan's "Advanced OS/2
 Programming" book.


 604. Format Incorrectly Works with SUBSTituted Drives

 If you execute "FORMAT A:", after executing "SUBST A: D:\" in the 3.x
 box, Drive D is still formatted. Drive D is an extended MS-DOS
 partition on a hard disk. The FORMAT command should reject the D
 drive, instead of going ahead with the format.

 This is not appropriate behavior for the FORMAT command, it should not
 be used with drives involved in a substitution (SUBST).

 Microsoft has confirmed this to be a problem in the OS/2 SDK (Software
 Development Kit) Version 1.10. We are researching this problem and
 will post new information as it becomes available.


 605. Starting OS/2 in Full-Screen CMD Line Mode from STARTUP.CMD

 Question:

 How do I start the OS/2 full screen CMD line mode from STARTUP.CMD and
 also from under program control? I do not want to start a new session;
 rather, I want OS/2 to be the only icon up, and to then run an
 AUTOEXEC.CMD file.

 Response:

 Use the START command. This command allows you to start new commands.
 It allows you to specify which screen group (SG) to use: a full-screen
 SG for VIO applications, or the Presentation Manager SG for windowable
 VIO, AVIO, or Presentation Manager applications. In addition, you can
 specify whether the application is placed in the foreground or
 background. When running an application in the Presentation Manager
 SG, "foreground" means that this application is the window with the
 focus; when running a full-screen application, "foreground" means that
 this SG is the currently selected SG.

 Thus, you could have one or more START commands in your STARTUP.CMD
 file, starting various applications in various screen groups.

 If you want to start the OS/2 full-screen CMD line mode from
 STARTUP.CMD, you can create the file STARTUP.CMD as follows:

    start /fs
    rem ... other STARTUP.CMD things should be added here ...
    exit

 The first line creates a full-screen CMD session. STARTUP.CMD
 continues to complete its other actions, then exits, leaving only this
 new CMD.EXE running. If you would rather see all the commands in
 STARTUP.CMD running in the full-screen session, rather than hidden in
 the windowed STARTUP.CMD session, you could have a STARTUP.CMD file
 similar to the one listed below:

    start /fs c:\AUTOEXEC.CMD
    exit

 Then, edit your AUTOEXEC.CMD file to contain the following:

    rem ... other STARTUP.CMD things should be added here ...

 Thus, STARTUP.CMD would start a full-screen CMD.EXE session,
 which will then continue to initialize your system (start the network,
 etc.). If you want it to go away when the initialization is done, you
 can specify the appropriate START switch, or you can call EXIT at the
 end of the .CMD file.

 However, there isn't a way to specify that STARTUP.CMD be run full
 screen rather than windowed. There isn't a configuration to change the
 way in which STARTUP.CMD is run. Also, if you don't like windowed CMD
 prompts, you can go into the Start Programs window, select "Windows
 command prompt," then select Program Change. At this point, you can
 change this so that it will start full screen, rather than in a VIO
 window. Better yet, if you don't like windowed CMD.EXE prompts, you
 can select this item, then select the menu item Program Delete,
 removing this from your Start Programs window altogether.

 Please refer to the Microsoft OS/2 Version 1.10 user's documentation
 for more information on the START command and the STARTUP.CMD file.

 Or, if you want to start the OS/2 full-screen CMD line mode under
 program control, write a program that controls the execution of
 sessions. You can do this by using DosStartSession(). The STARTDATA
 data structure used by DosStartSession() should have the parameter
 FbBg set to TRUE, and SessionType should be set to 1, meaning that the
 program should be run full screen. If the PgmName parameter in the
 STARTDATA structure is set to NULL, then CMD.EXE (or whatever the
 default PROTSHELL is) will be run.

 Please refer to the QuickHelp database as well as the "Microsoft
 Operating System/2 Programmer's Reference" (Volumes 1 and 3) for more
 information on DosStartSession() and the STARTDATA data structure.


 606. EXTPROC Incorrectly Duplicates Script Extension to Shell

 There is a problem with the OS/2 Version 1.10 EXTPROC command, which
 is an internal command of CMD.EXE.

 Given a simplified external command processor (an example of a program
 that EXTPROC would be used with) called YASH.EXE, based on the
 following file named YASH.C

    /* yash.exe -- yet another shell (example of an extproc) */

    #include <stdio.h>
    #include <stdlib.h>

    int main(int argc, char *argv[]);

    int main(int argc, char *argv[])
    {
        printf("yash: processing file \"%s\"\n" argv[1]);
    }

 and given a .CMD file called TEST.CMD

    extproc yash.exe
    this is a line of try.cmd

 when at a CMD.EXE prompt, typing the command of

    TEST

 should result in CMD.EXE's EXTPROC reading the file, realizing
 that it is a YASH script and not a CMD script, and then trying to
 internally invoke TEST.CMD with the following command:

    YASH TEST.CMD

 The problem in OS/2 Version 1.10 is that the file extension is
 incorrectly duplicated, so that the external command interpreter
 incorrectly receives a script filename of "TEST.CMD.CMD" rather than
 "TEST.CMD".

 Microsoft has confirmed this to be a problem with EXTPROC in OS/2
 Version 1.10. We are researching this problem and will post new
 information as it becomes available.

 One workaround for ISVs writing command processors is to perform a
 version check. If the OS/2 version is 1.10, remove the extra extension
 from the supplied .CMD filename.

 For more information on the EXTPROC command, please refer to the
 "Microsoft Operating System/2 Version 1.10 User's Guide and Desktop
 Reference."


 607. Files Required to Boot Up and Load PM Version 1.10

 The following information describes the minimum required files to boot
 up and load the OS/2 Version 1.10 Presentation Manager, and the method
 OS/2 uses to find these files.

 The following files must be in the root directory of the boot disk:

    CLOCK01  SYS
    DISK01   SYS
    KBD01    SYS
    PRINT01  SYS
    SCREEN01 SYS
    CONFIG   SYS

 The location of the following files is specified by the PATH= command
 in CONFIG.SYS:

    PMCPL    EXE
    PMEXEC   EXE
    VIOHELP  EXE
    SWAPPER  EXE
    HARDERR  EXE
    OSO001   MSG

 The location of the following files is specified by the PROTSHELL=
 command in CONFIG.SYS:

    CMD      EXE
    PMSHELL  EXE
    OS2      INI

 The location of the following file is specified by the DEVINFO=
 command in CONFIG.SYS:

    VIOTBL   DCP

 The location of the following file is specified by the DEVICE= command
 in CONFIG.SYS:

    PMDD     SYS

 The location of the following file is specified by the COUNTRY=
 command in CONFIG.SYS:

    COUNTRY  SYS

 The location of the following file is specified by the SWAPPATH=
 command in CONFIG.SYS:

    SWAPPER  DAT

 The location of the following files is specified by the LIBPATH=
 command in CONFIG.SYS:

    ANSICALL DLL
    BKSCALLS DLL
    BVSCALLS DLL
    DOSCALL1 DLL
    KBDCALLS DLL
    MOUCALLS DLL
    MSG      DLL
    NLS      DLL
    QUECALLS DLL
    SESMGR   DLL
    VIOCALLS DLL
    OS2SPLFS DLL
    PMGPI    DLL
    PMGRE    DLL
    PMSPL    DLL
    PMTKT    DLL
    PMWIN    DLL
    SPL1B    DLL
    SPLPRMAP DLL
    OS2SM    DLL
    PMSHAPI  DLL
    PMVIOP   DLL
    DISPLAY  DLL

 The preceding list assumes a system configured with no mouse, no
 serial ports, no 3.x BOX, and no print spooler.


 608. Allocating Memory for Use with Multiple Threads

 Question:

 I am working on an OS/2 PM program that uses multiple threads and
 having problems that seem to be caused by my use of large amounts of
 global memory. I am declaring my stack space for my threads as global,
 and which uses from 48-96K (24, 2K stacks or 24, 4K stacks). By also
 trying to allocate space from the global memory to hold a large data
 array, my program cannot start the threads. It seems as if by using a
 large amount of global memory, I have damaged the stack spaces for my
 threads.

 Do I need to dynamically allocate memory for the thread stacks and
 data arrays, or does this also violate some maximum allocatable memory
 bound?

 Response:

 Regarding your C stack, make sure that the stack size of your
 program is large enough for all of the data put on it.

 There are generally three ways to allocate memory for a thread, as
 follows:

 1. The first way is to use C's stack to statically define the thread's
    stackspace. This is useful if you are using only a single thread,
    and the thread never terminates, or the memory never is reused by
    another thread.

 2. The other two ways are to dynamically allocate the thread's stack
    space. Both of these methods are useful if you're creating (and
    terminating) multiple threads (and perhaps the program doesn't know
    how many threads will be created until at runtime). You can
    dynamically allocate memory by using C's run-time library (malloc,
    free, etc.), which takes memory from C's heap. Or you can use the
    OS/2 memory management APIs (DosAllocSeg(), DosFreeSeg(), etc.),
    allocating new segments from the system, each one taking up an
    entry in your LDT (Local Descriptor Table).

 The most common problem with memory and threads is that,  if not
 carefully written, the threads can overwrite each other's stack space.
 Since the threads are in the same process, OS/2 does not protect each
 thread from other threads.

 For this reason alone, we recommend trying to allocate each thread's
 stack as a separate segment using DosAllocSeg(). In this way, when
 you start the thread, you pass the selector of that segment only
 to that thread, and thus no other threads have a valid selector to
 that segment. If another thread tries to access memory outside the
 boundary of its stack, it will GP fault, telling you that you need
 to perform some range checking. And since the threads are in separate
 segments and the selector is given only to the thread when begun, it
 is very unlikely that other threads will disturb other threads'
 memory.

 Thus, the main advantages of dynamically allocating multiple threads'
 stack space in separate segments are that it separates the segments
 and gives your multi-threaded application more security against rogue
 threads overreaching their own space and also invading the space of
 other threads. Another advantage is that the thread stack space won't
 reside on your C stack or heap, giving your program more room to work.


 609. Creating Device Monitor to Cover Multiple Screen Groups

 Question:

 How do I create a global device monitor that covers all screen groups,
 or more than one screen group?

 Response:

 Your character device monitor should loop through each screen group
 and call DosMonReg() for each screen group, changing the screen group
 number in each call.

 Your global device monitor won't work in the DOS screen groups. It
 will work in the PM (Presentation Manager) screen groups in Version
 1.10. Please note that this is subject to change, so do not count on
 this behavior to work in future versions of PM.

 Listed below is some pseudo C code that demonstrates how you could
 implement the functionality described above:

     #define INCL_DOSMONITORS
     #define INCL_BASE
     #include <os2.h>

     #define MAX_SCREEN_GROUPS 16

     BOOL afIsValidScreenGroup[MAX_SCREEN_GROUPS];
     HMONITOR ahmon[MAX_SCREEN_GROUPS];
     int iIndex;
     /* Setup MONIN and MONOUT structures for each screen group...*/
     USHORT usError;

     for (i = 0; i < MAX_SCREEN_GROUPS; i++)
     {
         usError = DosMonReg(
             hmon[iIndex];      /* mon handle to register */
             &bInBuf[iIndex];   /* pointer to structure for input
                                   buffer */
             &bOutBuf[iIndex];  /* pointer to structure for output
                                   buffer */
             MONITOR_DEFAULT;   /* mon position flag */
             iIndex);           /* screen group number */
         afIsValidScreenGroup[iIndex] = usError == NO_ERROR ? TRUE :
                                                   FALSE;
     }

 QuickHelp includes an example of a device monitor that installs itself
 in multiple screen groups. The example allows you to select the number
 of screen groups it installs in. Included below is an excerpt from
 QH.EXE's command-line documentation:

     -sg1-12  Specifies the number of full-screen sessions that
              QuickHelp should monitor. This option is valid only
              when you run QuickHelp as a keyboard monitor. The
              default is to monitor the first six sessions created.


 610. Two Different Function Prototypes for DosCwait() in BSEDOS.H

 Question:

 Why are there two different function prototypes for the DosCwait()
 function in BSEDOS.H?

 On line 112 of c:\pmsdk\include\bsedos.h, it states the following:

    USHORT APIENTRY DosCwait(USHORT, USHORT, PRESULTCODES, PPID, PID);

 On line 104 of c:\include\bsedos.h, it states the following:

    USHORT APIENTRY DosCWait(USHORT, USHORT, PRESULTCODES, PPID, PID);

 Response:

 The proper function declaration for this API is as follows:

    USHORT APIENTRY DosCwait(USHORT, USHORT, PRESULTCODES, PPID, PID);

 where the name is "DosCwait" (lowercase w), defined in BSEDOS.H.

 It was incorrectly named "DosCWait" (capital W) in a previous version
 of BSEDOS.H [such as the OS/2-specific include files included with the
 C Compiler Version 5.10, roughly based on the OS/2 Version 1.00 SDK
 (Software Development Kit)]. However, if you look at the comments of
 the latest BSEDOS.H, you can see a few references to this older name
 in some comments:

     /* DosCWait fScope code values */
     /* DosCWait wait option values */


 611. Swapping between Screen Groups

 If you are running in the detached screen group, there is no way to
 bring the application (or the screen group) to the foreground.
 Instead, the application must use the VioPopup() mechanism to
 communicate with the user.

 If you have created sessions using DosStartSession(), you can use
 DosSelectSession() to bring one of these sessions to the foreground.
 This does not work for sessions that your process did not start.

 For other sessions, there is no API or standard method to switch from
 one session to another. The closest method available is to write a
 character device monitor for the keyboard device driver. Then, you can
 stuff key packets into the buffer to manually switch from one screen
 group to another. This method is filled with dependencies and
 problems. You can't create a keyboard monitor in the MS-DOS screen
 group, detached screen group, or Presentation Manager screen group.
 Also, you have no definite idea of how many screen groups there are,
 and where you are, so without such a firm point of reference it is
 very difficult to accurately navigate through the screen groups.

 In spite of all these difficulties, developers still want to try this.
 There is a sample C program in the Software/Data Library named SWAPSG
 that is a keyboard device monitor that demonstrates how to switch
 between screen groups.

 SWAPSG contains the following files: MONITOR (the makefile),
 MONITOR.C, MONITOR.DEF, MONITOR.LNK, and MONITOR.EXE.

 SWAPSG can be found in the Software/Data Library by searching on the
 keyword SWAPSG, the Q number of this article, or S12364. SWAPSG was
 archived using the PKware file-compression utility.


 612. ERROR_INTERRUPT Is Returned When DosMuxSemWait() Is Used

 Question:

 In an application with multiple threads using DosMuxSemWait() to block
 until queue data is available, we are experiencing the following
 problem. For many calls to DosMuxSemWait(), the result is as expected:
 either an ERROR_SEM_TIMEOUT error message or 0 (zero).

 It appears that one of the calls to DosMuxSemWait() is attempting to
 return ERROR_INTERRUPT (0x57). This causes a protection violation when
 attempting to store the returned value into a local USHORT variable.

 Under what circumstances will this function return ERROR_INTERRUPT?
 What does this return value really indicate? Why are we getting the
 protection violation?

 Response:

 This error/protection violation may be returned because you aren't
 referencing the semaphore correctly, which can cause errors if the
 system cannot properly access the semaphore.

 The ERROR_INTERRUPT error means that the system call was interrupted.
 It is a very general error; there are approximately 45 places in the
 OS/2 kernel where this value is returned. The API DosMuxSemWait()
 never directly returns ERROR_INTERRUPT, nor does there seem to be any
 directly related kernel routine closely tied with DosMuxSemWait()
 returning this ERROR_INTERRUPT.

 In general, the most common place in which a kernel routine returns
 this error is right after the kernel process block function, a
 scheduler routine that puts the current process to "sleep" until
 another process (or an interrupt service routine) issues an
 appropriate process run routine (which "wakes up" the process). If
 this routine is unable to properly block the process, it returns an
 error. Many other areas of the kernel, after calling this routine,
 also will return the error of ERROR_INTERRUPT if this routine returns
 an error.

 The following is a list of some general areas in which this error can
 be returned:

  1. It appears that the closest area this error is used to the
     DosMuxSemWait() semaphore routine is in some kernel functions
     related to the OS/2 kernel semaphore routines. A routine will
     return this error if it has been determined that a bad address has
     been passed to the semaphore routines, and this routine will be
     called to kill off the process, returning this error.

  2. If a device is abnormally interrupted, a DosRead(), DosWrite(), or
     DosDevIOCtl() primitive may return ERROR_INTERRUPT.

  3. The error is returned by the EXEC loader, trying to serialize
     multiple threads that use per-process variables.

  4. The error is returned by the HARDERR.EXE, the hard-error daemon.

  5. The error is returned when the kernel cannot allocate LDT (Local
     Descriptor Table) entries to EXEC an application.

  6. The error is returned when the EXEC loader is in the middle of
     starting a process, when the thread (most likely its entire
     process) that instigated the new process is terminating or
     responding to a kill process signal.

  7. The error is returned when terminating a process and disassociating
     the process from any shared memory segments, and if the kernel
     cannot obtain the semaphore to the shared memory segment(s).

  8. The error is returned when performing various named pipe APIs, such
     as DosConnectNmPipe().

  9. This error occurs in a low-level semaphore waiting routine, if the
     process waiting for the semaphore is interrupted.

 10. This error occurs while using DosPTrace(), tracing through a child
     debugee process, if certain conditions occur in the child.

 11. This error can be returned by the routines that the Presentation
     Manager session manager (PMSHELL.EXE) uses to thaw and freeze
     threads, among other areas it has to dispatch processes.

 12. The error can be returned by DosCWait(), waiting for a child
     process to finish, if the child process was somehow interrupted.

 13. The error can be returned by some memory-management segment
     reallocation routines if the routine is interrupted by a signal.

 14. The error can be returned by some kernel exit list processing
     routines, which coordinate (add, remove, and execute) the various
     exit list user procedures.

 15. When loading a dynlink at run-time via DosLoadModule(), it is
     possible to receive this error if the dynlink loader is
     interrupted by a signal.


 613. OS/2 Magnetic Tape/Optical Disk Device Driver API Information

 Question:

 I am developing a Presentation Manager (PM) application that will
 eventually use magnetic tape devices (cartridges) and I would like
 some information about the application interface to the tape devices.
 I understand that in general, drivers for tapes will not be a part of
 OS/2 but will come as drivers provided by the tape device vendors.
 However, is there a basic application interface (API) pattern to which
 all or most cartridge tape device drivers will conform? I can imagine
 several possibilities:

 1. All drivers for cartridge tape devices provide the same API to
    applications.

 2. Drivers will provide basically the same API, with minor differences
    (e.g. API extensions to take advantage of special device features).

 3. Drivers for cartridge tape devices will not closely follow any
    particular API pattern. Each device will offer its own API.

 My questions are listed below:

 1. Would you please describe as best you can what the API situation
    will be for OS/2 (PM) applications needing to use cartridge
    tape devices?

 2. Does there exist today a good pattern for what the cartridge tape
    device interface API will be?

 3. What can I expect for other types of devices such as (writeable)
    optical disks? That is, will each vendor develop its own API or
    will there be a single strong API for the device type?

 4. How can a developer, like myself, best plan to support a variety
    of cartridge tape devices, or optical storage units?

 Response:

 As a general answer to your questions regarding the API interface to
 tape and optical disk devices, we believe that most vendors of these
 products will implement a block device interface to them. This means
 that accessing them will be similar to accessing a disk drive. There
 will usually be some kind of directory structure and a file system
 associated with the device. Therefore, the OS/2 API DosOpen(),
 DosRead(), DosWrite(), and DosClose() functions will most likely be
 used to perform I/O with these devices. The area of greatest
 variability will be in the utility functions such as reset/initialize,
 seek, rewind, eject, etc. These are usually implemented via
 DosDevIOCtl() functions, where the command and data formats will be
 defined by each individual vendor.

 As for an API pattern for these devices, you should look at the MS-DOS
 implementation of accessing these devices from a program. You can send
 for the user manual and/or the programmer's or technical reference
 guide for several of the popular tape drives to see how they have done
 this under MS-DOS. Probably for at least some time, the API interface
 scheme for OS/2 will be similar. Becoming familiar with the MS-DOS
 scheme is probably the best way to support these devices under OS/2.


 614. Sending Output from Program to Monochrome (Second) Monitor

 Question:

 How can I send output to a monochrome (second) monitor while running a
 Presentation Manager (PM) program? I already know how to set up the
 debugging kernel.

 Under Windows, with OX.SYS, the following statement prints the string
 on the monochrome monitor:

    fprintf(stdaux,"\r\nThis message will output to the monochrome.");

 However, under PM, there is no documentation on how to send
 application data to the monochrome monitor.

 Response:

 There is no equivalent method under PM that allows you to send
 debugging information to a second monitor/terminal, as you can do
 using the fprintf() statements under Windows. However, there is
 something that is similar and quite simple.

 You can add printf() statements to your PM application and take
 advantage of redirection into another utility that actually echoes the
 output. Normally, the printf()s would go into the bit bucket. However,
 if you pipe the output into something else that then prints out the
 output, this produces the desired effect.

 After adding the debugging printf() statements that you want, open a
 windowed command prompt and issue the following command:

    PMappname | megrep ^^?

 If you use this command, you must make MEGREP (it comes as part of the
 M editor with the C Compiler package) windowable, then use MARKEXE on
 it. You can choose any utility you like, as long as it echoes input
 from stdin to stdout in some form, and it can be made to run in a
 window.

 Once your application gets started, any output that is sent to stdout
 [such as printf()] gets piped into MEGREP. The question mark (?) means
 match any character. The second caret (^) means only do this at the
 beginning of the line. The first caret is used to escape the second
 caret, because the caret character (^) has special meaning for OS/2's
 CMD.EXE.

 You now have your debugging statements going to one window, while your
 application runs in another window.

 For more information about additional debugging functions for OS/2
 1.10 and 1.20 that describes another method that makes use of calls
 supported by the debugging version of PMDD.SYS, query on the following
 keywords in this Knowledge Base or in the Software/Data Library:

    PMUTILS and UTILS.C

 These calls work only for OS/2 version 1.10, and since they are
 undocumented, they are subject to change and may or may not work with
 later releases of OS/2.

 PMUTILS can be found in the Software/Data Library by searching on the
 keyword PMUTILS, the Q number of this article, or S12251.


 615. Improving Performance of Data Transfer Speed to Disk Drive

 Question:

 What steps can I take to get the best possible DosWrite() throughput
 on floppy-disk devices? For the moment, I only want to consider
 solutions where a single thread writes to a floppy disk (other threads
 are used to prepare the buffers to be written to the floppy disk).

 The following factors might come into play: size of blocks written to
 floppy disk, priority of thread writing floppy disk relative to that
 of the other threads, and use of "direct disk access" via the "DASD"
 DosOpen() openmode flag. Are there any other factors I need to
 consider?

 I am particularly interested in what performance gains might be
 realized through the use of "direct disk access" (DASD flag on open).

 Are there any other ways to improve floppy-disk write performance?

 Response:

 The use of large blocks to transfer data is a very good way to ensure
 that you get proper performance. You can use DASD opens to speed this
 up even further, but there are a few issues you should be aware of:

 1. When using DASD, you are communicating directly with the device
    driver and are bypassing the file system. This is good for speed,
    but bad for maintaining a file system on the disk. This method is
    good if you don't need things such as a root directory or FAT to
    make the disk readable by anything other than your restore program.
    Image-type backup programs are useful for this strategy.

 2. Have the entire contents of the source information be stored in one
    file on the destination drive. This allows you to use fewer open
    and close calls to the operating system and file system. This is
    the method that the standard OS/2 backup and restore programs use.

 3. Another method to get the data moving faster (although filling an
    entire disk takes the same amount of time) is to compress the data
    before writing it out. You could move a lot more data in the same
    amount of time without having to hurry up the process.

 Although the above information doesn't really recommend a best method
 to use, it does explain some of the tradeoffs you should be aware of
 when using any of the more common approaches to improving data
 transfer speed. The fact that OS/2 is multitasking should allow you to
 be more flexible because the user can be doing other things while the
 backup is going on. This multitasking ability provides a performance
 boost.

 In general, the fewer interfaces (DASD and DevIOCtls versus through
 the kernel) and the larger the buffers that you are writing, the
 better. However, these two objectives are only part of the picture,
 and the saving and restoring of the data must also be taken into
 account.


 616. Obtaining EXE Filename for Current Process

 This article discusses how to obtain the EXE filename of each process.

 The module handle is listed in the local info segment of the current
 process. The following code sample demonstrates how to obtain this
 information:

 #define INCL_BASE

 #include <os2.h>

 #include <stdio.h>
 #include <conio.h>
 #include <stdlib.h>

 void main(void);

 void main(void)
 {

    USHORT usRetCode;

    UCHAR auchName[40];
    SEL selGlobalSeg, selLocalSeg;
    LINFOSEG FAR *pgis;

    usRetCode = DosGetInfoSeg(&selGlobalSeg, &selLocalSeg);
    pgis = MAKEPLINFOSEG(selLocalSeg);

    if (!usRetCode)
       usRetCode = DosGetModName(pgis->hmod, sizeof(auchName),
                                 auchName);
    else {
       printf("\nDosGetInfoSeg failed returning %u\n",usRetCode);
       exit(1);
    }

    printf("\n The module name is %s\n",auchName);
    exit(0);
 }

 This program works for the current process. It also works if an
 unrelated process can discover other processes' module handles [that
 is, as long as a valid module handle is passed to GetModName(), you
 can find out that module's name also].

 You must find out what the other processes' module handles are. You
 can try to obtain this information from the task list.


 617. How to Debug a Detached Process in OS/2

 Question:

 I am trying to debug a detached process and because this program
 monitors the screen memory and keyboard, I can't debug under CodeView.
 How can I debug detached processes?

 Response:

 There are three possible ways to debug detached processes:

 1. A process that is detached should run the same when not detached;
    therefore, you could debug your process first as a foreground
    application and then detach it. You could do this with CVP
    (CodeView) and dual monitors, although the keyboard monitor may be
    troublesome, as you might have to use keys in CVP that would affect
    your monitor.

 2. Use a debugging file. Send debugging information out to a file that
    details what your program is doing as a detached process.

 3. Use VioPopUp() to have your application communicate to you what is
    going on.

 Another useful item is a debugging kernel for OS/2 that does not have
 a CodeView front end, but allows you to debug your application while
 it is in the detached screen group.

 To obtain this debugging kernel, you must purchase the OS/2 DDDK
 (Device Driver Development Kit). For more information on purchasing
 the OS/2 DDDK, please contact Customer Service at (800) 227-4679.


 618. OS/2 General Information

 Question:

 What is OS/2?

 Response:

 Operating System/2 (OS/2) is an operating system designed to meet
 today's and tomorrow's user needs. It exploits the advanced
 capabilities of 80286- and 80386-based personal computers such as the
 IBM PC/AT, COMPAQ DESKPRO 386, and IBM PS/2 models 50 through 80. It
 is the successor to the MS-DOS operating system.

 OS/2 removes the limitations of the DOS environment allowing
 application developers to create much more powerful applications that
 are easier to learn and use than they have been able to in the past.
 More powerful applications can be written because there is more memory
 available to OS/2 applications, and also because there are many more
 features that are built into the operating system that an application
 can take advantage of. Features such as multitasking within an
 application, and facilities for sharing data between applications are
 available. In the past, developers had to design around these
 limitations in MS-DOS (lack of multitasking, large memory usage,
 protected-mode operation). With the standard graphic user interface
 provided by the OS/2 Presentation Manager, the system will also be
 much easier to use.


 619. Memory Available in DOS 3.x Box Environment

 Question:

 How much memory is available to a DOS application running in the DOS
 environment of OS/2?

 Response:

 It varies, depending upon the version of OS/2, how the system is
 configured, and which device drivers are loaded. For OS/2 1.10
 Standard Edition with the standard device drivers loaded, including a
 mouse, there is approximately 500K of memory available to the
 application.

 For comparison, with MS-DOS Version 3.30 there is approximately 576K
 of memory available to a MS-DOS application.


 620. Why You Cannot Go Directly into DOS 3.x Box at Boot Time

 Question:

 Is there any way under OS/2 to go straight into the DOS 3.x box at
 boot time?

 Response:

 No, there is no way to go straight into the DOS box at boot time. OS/2
 was designed primarily to be a protected-mode operating system so as
 to take advantage of the increased capability of the 80286 in
 protected mode. The real mode (DOS) box was provided as a way to
 maintain compatibility with existing applications that were written
 for MS-DOS. A PC with OS/2 installed will boot directly into OS/2.
 From there, you can switch into various OS/2 applications, or you can
 switch directly into the DOS environment.

 However, there is currently available for OS/2 1.10 a "dual boot"
 utility that allows you to choose at boot time whether the PC will
 boot into DOS or into OS/2. If the DOS choice is made at boot time,
 the PC boots only DOS, and does not load either OS/2 or its DOS
 compatibility session. Most OEMs include the dual-boot utility in
 their version of OS/2 1.10.


 621. MS-DOS Applications That Run in the OS/2 DOS Environment

 Question:

 Which MS-DOS applications run in the OS/2 DOS environment?

 Response:

 The following applications were tested and run in the OS/2 DOS
 environment (this is also referred to as the "DOS compatibility box").
 There are many other DOS applications that also run in the OS/2 DOS
 environment. Consult the application supplier for information on a
 specific application.

 IBM Assistance Series 2.0             Multimate Advantage 3.50, 3.60
 Chartmaster 6.1                       PFS Professional File 1.0
 dBaseIII PLUS 1.0 and 1.1             PFS Professional Write 1.0
 Easy 1.0                              Prokey 4.0
 Enable 1.1                            RBase 5000 1.0
 First Choice 1.0                      Sidekick 1.56A and 1.59F
 Framework II 2.0                      Sideways 3.11
 IBM Displaywrite 3 release 1.10       SuperCalc 3 2.0
 IBM Displaywrite 4 release 1.10       Superkey 1.11A
 IBM File 1.0                          Turbo Pascal 3.01A
 IBM Report 1.0                        Volkswriter 2.1
 IBM Writing Assistance 1.0            WordPerfect 4.1
 Lotus 1-2-3 releases 2.0 and 2.1      WordStar 2000
 Lotus HAL 1.0                         WordStar release 3.31
 Lotus Symphony releases 1.1 and 1.2   Microsoft C Compiler 4.0, 5.1
 Microsoft Chart 2.03                  Microsoft COBOL 2.20
 Microsoft FORTRAN 4.00                Microsoft MASM 4.00
 Microsoft Pascal 3.32                 Microsoft Project 3.01
 Microsoft QuickBASIC 2.01             Microsoft Windows 2.00, 2.10
 Microsoft Windows/286 2.10            Microsoft Word 3.11, 4.00, 5.00


 622. Reasons to Purchase OS/2

 Question:

 Why should I purchase OS/2?

 Response:

 OS/2 allows you to write much more powerful applications than you can
 under MS-DOS. This means that you will have much more powerful
 applications that are easier to use. It also allows you to write new
 types of applications.

 OS/2 applications can access up to 16 MB of real memory that may be
 installed in the PC. This frees you from the 640K limitation of
 MS-DOS, allowing you to design applications that could not be
 developed for the MS-DOS environment.

 Another feature of OS/2 is multitasking. OS/2 has two types of
 multitasking: the ability to run more than one application at the same
 time (multi-application multitasking) and multitasking within an
 application. Multi-application multitasking allows you to run more
 than one application at a time. This means that you can be downloading
 data from a mainframe while writing a memo with your word processor.

 Multitasking within an application (multithreading) is an important
 feature of OS/2. It greatly simplifies the development of a complex
 application. For example, an MS-DOS spreadsheet program in which you
 can input more data before the recalculation is complete is
 multitasking within itself. The code to implement this ability is very
 complex since the program has to constantly check for keyboard input
 several times a second during the recalculation. Under OS/2, it is
 fairly easy to implement this capability because it was designed into
 the operating system. MS-DOS has no built-in capability to implement
 this type of functionality.

 All OS/2 applications written for the Presentation Manager interface
 will have the same "look and feel," making it easy to learn new
 applications as they become available. End users will not have to be
 retrained completely for each new application.

 However, only OS/2 applications can take advantage of the new features
 of OS/2. Existing MS-DOS and Windows applications can be run in the
 DOS mode of OS/2, but they cannot take advantage of the larger memory
 available under OS/2.


 623. MODE XON Parameter Does Not Enable RECEIVE_FLOW_CONTROL

 Problem:

 There seems to be a problem with the MODE command with respect to
 setting the communications parameters. The statement listed below sets
 only the TRANSMIT_FLOW_CONTROL for the device driver:

    MODE COM1:9600,N,8,1,XON=ON, ....

 I determined this by doing an IOCTL after opening the device from a
 program. I think that XON=ON should either enable both TRANSMIT and
 RECEIVE_FLOW_CONTROL or there should be separate command-line options.

 RECEIVE_FLOW_CONTROL works correctly as long as I use IOCTL from
 within my program to enable it. However, this is not desirable because
 it makes my program more device dependent.

 Response:

 Microsoft has confirmed the behavior described above; however, we have
 not yet confirmed whether or not this is a documentation error or a
 problem with the actual software. We are researching this problem and
 will post new information as it becomes available.


 624. OS/2 Device Driver Can't Use GDT Selector at Initialization

 Problem:

 I am having a problem with an installable device driver I am
 developing that requires memory mapped I/O.

 At initialization time, I call the DevHelp routines to successfully
 allocate a GDT (global descriptor table) selector and then map the
 selector to the physical address of the ROM (e.g. D4000H). However,
 loading the selector (in protected mode) into the DS register causes a
 protection violation. The selector is a GDT entry with DPL=0 and the
 CS/DS selectors are LDT (local descriptor table) entries with DPL=3.

 Response:

 This is expected behavior. At initialization time, an installable
 device driver is running under single-tasking conditions at ring 3
 with IOPL privilege.

 You can set up and map the GDT selectors, but you do not have the
 privilege to use them until task time, when the device driver is
 running at ring 0. If you need access to your mapped memory at
 initialization time, you must use some of the "phys" calls to give you
 addressability.

 If you want to use the GDT selectors to initialize your device, you
 need to write an application to call down to your device driver with
 an IOCtl after initialization time, and do the device initialization
 the first time you enter your strategy routine.


 625. Time Field in GINFOSEG Is in Greenwich Mean Time

 Question:

 I am using the DosGetInfoSeg() function and the time field of the
 GINFOSEG structure. The time field specifies the time from January 1,
 1970 (in seconds). The return value is different (exactly seven hours)
 from the value that the time() function returns. Why is the return
 value different?

 Response:

 The value contained in the GINFOSEG structure defaults to Greenwich
 Mean Time. The Microsoft C *time() functions default to reporting Daylight
 Savings Time in the Pacific Standard Time zone.

 You can change the default for the *time() functions by setting the TZ
 environment variable to the appropriate time zone and daylight savings
 mode. For further information on this subject, please consult the
 Microsoft C Compiler Version 5.10 documentation for the tzset()
 function.


 626. Using STDIO to Write in Text Window at Windowed Command Prompt

 Question:

 When I bring up an OS/2 windowed command prompt, I'd like to have
 programs that use STDIO to write into the text window, instead of
 flipping to the full screen. Flipping back and forth makes it
 difficult to view the error codes from MAKE, CL, and LINK. I could
 work up something for the "Start Program" box, but it seems that I
 would have to make a separate entry for each makefile.

 I would prefer to type "make makefile" in the appropriate directory
 from the windowed command prompt. Can I do this?

 Response:

 The proper way to do this is to add a "NAME" statement to your .DEF
 file and add the keyword "WINDOWCOMPAT", as in the following example:

          NAME windowableapp WINDOWCOMPAT
          PROTMODE
          .
          .
          .

 This procedure sets a byte in the EXEHDR that tells the loader it can
 be run in a window. The default put in the header is NOTWINDOWCOMPAT,
 which tells the loader to run the program in a full-screen group. If
 you don't have a .DEF file already, you can create one with only the
 NAME statement in it for this purpose.

 The NAME statement and other .DEF file commands are discussed in the
 Utilities update sections of the Microsoft OS/2 compatible languages
 (i.e., C Compiler, MASM, etc.) and also in the linker section of the
 Presentation Manager (PM) Softset manual.

 Another way to do this is to use the MARKEXE tool that comes with the
 OS/2 SDK (Software Development Kit), OS/2 Programmer's Toolkit, or the
 PM Softset. MARKEXE allows you to set the byte in the EXEHDR of an
 already existing .EXE file. This procedure also is documented in the
 PM Softset. You could also use MARKEXE to mark the C compiler, linker,
 and other binaries so that they run in a window without flipping to a
 full screen; in fact, many already have done this. Later releases of
 Microsoft OS/2 compatible tools already have the WINDOWCOMPAT byte
 set for operation in a window (when appropriate).


 627. OS/2 Scheduler Is Not Run upon Completion of Interrupt Handler

 Question:

 If a device driver interrupt handler does not execute the Run()
 DevHlp, is the scheduler run upon completion of the interrupt handler?
 I have a device driver that does not perform I/O in the standard OS/2
 manner (i.e., request, program device, block thread, wait for
 interrupt, run thread). Is there any scheduler overhead on completion
 of the driver interrupt handler, and is there any way I can avoid such
 overhead?

 Response:

 The OS/2 scheduler is not run automatically upon completion of a
 device driver interrupt handler. Execution just returns to the point
 where the interrupt occurred, assuming that there are no other pending
 interrupts waiting.


 628. CMD.EXE GP Faults If First Character of File Is Binary Byte 26

 Problem:

 I have a file in the default directory that has a binary byte 26 as
 its first character. If I issue either of the following commands in a
 batch file, CMD.EXE will GP fault when it encounters this file:

    copy *.* nul

 or the equivalent command:

    copy . nul

 Response:

 Microsoft has confirmed that this problem occurs in Version 1.10. It
 only occurs when using the "*.*" or "." copy syntax. We are
 researching this problem and will post new information as it becomes
 available.

 In the meantime, substituting the following lines for the "copy *.*
 nul" command in your batch file will give you the same results:

    del foo
    for %%f in (*.*) do echo %%f >> foo


 629. Multiple Sessions Printing to LPT1: Is Incorrectly Allowed

 Problem:

 We are designing an application with multiple session parallel/serial
 print capability. When attempting to open a serial output port (e.g.
 COM1:) using DosOpen() with the following characteristics, we receive
 the expected failure on a concurrent second session invocation:

    deny all
    write only
    fail on creation
    open on existence

 However, when we attempt to open a parallel port (e.g. LPT1:), access
 is granted to BOTH sessions with catastrophic results. This was tested
 with the print spooler deactivated.

 Response:

 Microsoft has confirmed this to be a problem with the printer device
 driver included with Version 1.10. We are researching this problem and
 will post new information as it becomes available.

 In the meantime, use one of the following workarounds:

 1. Create a system semaphore that will alert your applications when
    they can have access to the printer (this only works for your
    application).

 2. Always use the spooler.


 630. Size of DISK01.SYS or DISK02.SYS Cannot Exceed 64K

 Question:

 When our disk device driver has a size of 64,980 bytes, OS/2 does not
 recognize it as a valid device driver. I know that DISK01.SYS has a
 size limitation of 64K. Does DISK02.SYS have an even smaller size
 limitation?

 Response:

 Both DISK01.SYS and DISK02.SYS have the 64K size limitation. This
 limitation applies to the combined sum of the code plus data segments
 after they are loaded into memory. This is not necessarily equal to
 the file size (in fact, it rarely is), due to factors such as
 uninitialized data storage, which consumes DS space but is not
 reflected in the size of the .SYS file.


 631. Reading in Files Larger Than 64K

 Question:

 Can the function DosRead() read in files larger than 65,535 bytes?

 Response:

 The functions DosRead(), DosWrite(), and some of the other related I/O
 APIs are currently limited to an unsigned WORD in their amount of data
 to read. Therefore, passing an unsigned DWORD to DosRead() causes it
 to work improperly.

 To work around this situation, write a higher level function such as
 the following:

    USHORT DosReadLots(HFILE hf, PVOID pvBuf, ULONG ulBuf,
                       PULONG pulRead);

 This function loops through the appropriate number of times, each time
 calling DosRead() with an unsigned WORD's worth of data to read, and
 in the last iteration of the loop it reads in the remainder of the
 data.


 632. OS/2 Does Not Interpret ALT Key Correctly in 3.x Box

 Problem:

 My application uses KbdSetStatus() to turn on raw mode and shift
 reporting, and then calls KbdCharIn() with IO_WAIT. When I perform the
 following steps, the ALT key is not interpreted correctly:

 1. Press ALT+ESC to switch to the DOS session.

 2. Release the ALT key.

 3. Press ALT+ESC to get to the session running my application.

 4. Without releasing the ALT key, press F1.

 KbdCharIn() sends the scan code/character code for F1, not ALT+F1. The
 correct scan code/character code (i.e., ALT+F1) is returned if I don't
 release the ALT key between the time I start switching sessions to
 when I get back to the original session and press F1 in addition to
 the ALT key.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.10. This
 appears to be a minor problem with the 3.x box, where the system
 remembers an ALT key release, but not an ALT key press. We are
 researching this problem and will post new information as it becomes
 available.


 633. Expanding a CS-Aliased Segment

 Question:

 Can you do a DosReallocSeg() on a segment that has been CS aliased?
 For example, I do a DosAllocSeg() to get a segment of 16K and then I
 do a DosCreateCSAlias() on that segment. I am generating code in that
 segment that will later be executed. I now find that 16K isn't enough,
 so I want to expand that segment. How should I do this? I have tried
 using DosReallocSeg() on the DS selector; however, I seem to randomly
 get error number 5 back from the call, even if I am later just trying
 to expand a plain data segment.

 Response:

 As the documentation states, the segment used by DosCreateCSAlias()
 cannot be a "huge" segment [thus you cannot use DosAllocHuge() to
 create it] and it must be exclusively available only to your process,
 not shared by any other processes [thus DosAllocShrSeg() cannot be
 used to create it]. Therefore, the segment must be ring 2 or ring 3
 data, and it cannot be huge, shared, or discardable.

 However, this issue apparently is not documented in the DosAllocSeg(),
 DosReallocSeg(), or DosCreateCSAlias() sections of the "Microsoft
 Operating System/2 Programmer's Reference Volume 3" for Version 1.10.

 DosReallocSeg() does not reallocate CS-aliased or huge segments. It
 can be used only with unshared and shared segments. We will post new
 information when the documentation has been updated.

 One way to work around this problem is to use a normal segment [i.e.,
 not the segment created for DosCreateCSAlias()] using DosAllocSeg(),
 and put the dynamically-created code into this segment. As the code is
 being generated, you could resize the segment via DosReallocSeg().
 When you are done generating your code dynamically, you could then
 call DosAllocSeg() to create a segment of the proper size. You would
 then call DosCreateCSAlias() using the final size of this normal data
 segment, and then copy the contents of the data segment into the code
 segment. This is of course an added step, but it is required if you
 don't know the final size of the segment which will become the
 CS-aliased segment.


 634. Comparison between OS/2 and Microsoft Windows

 The information below compares OS/2 and Windows/386 in the areas of
 multitasking, memory requirements, and the graphical user interface.
 Interprocess communication and hardware requirements are also covered.

 Multitasking
 ------------

 There are distinct differences between the multitasking methods that
 are used by Windows/386 and OS/2.

 Windows/386 employs two different types of multitasking, depending on
 whether the applications are Windows programs or standard MS-DOS
 programs running in virtual 8086 mode. Preemptive time-slicing is used
 to allocate CPU time between the various virtual MS-DOS machines that
 may be running and the Windows applications session. However, within
 the graphical Windows applications session, Windows/386 uses
 event-driven multitasking, just like Windows/286. That is, the
 currently executing Windows program must finish an operation and
 voluntarily yield control of the CPU before another Windows
 application can start or continue executing. When this doesn't happen,
 a condition known as "CPU starvation" can set in, and an application
 slows down or can temporarily stop running because it can't get enough
 CPU time. If the program that's running crashes, the entire system
 stops.

 OS/2 employs time-slicing multitasking, rather than event-driven
 multitasking. OS/2 has the ability to switch the CPU's attention from
 activity to activity very rapidly, up to hundreds of times a second.

 Moreover, OS/2 implements time-slicing using a preemptive,
 priority-based task scheduler. This provides a smoother multitasking
 behavior for the user: one application doesn't have to wait until
 another application relinquishes control of the CPU before it gets
 some processor time. Under preemptive scheduling, the OS/2 scheduler
 preempts or takes the CPU away from an application and assigns it to
 another application according to a dynamic, multilevel priority scheme
 that's designed to provide maximum responsiveness to the user.

 In addition to scheduling the execution of multiple, concurrent
 processes, OS/2 provides an additional layer of multitasking that's
 not available under any other major personal computer operating
 system. That is, OS/2 allows multiple, simultaneous "threads of
 execution" within a single application. In other words, a program can
 execute in two or more places in its code at the same time. This
 allows an individual application to perform a number of foreground and
 background tasks all at the same time.

 For example, most PC-based spreadsheets process keyboard input and
 recalculation sequentially. Some are designed to check for input at
 predetermined intervals. This is extremely inefficient because the
 system must waste time checking for input even when there is none
 available. Under OS/2, a spreadsheet could approach this situation by
 using two threads of execution. One thread is used to prompt the user,
 wait for and then read the user's input, and then execute the user's
 commands (for example, entering a value in a cell). The other thread
 is used to recalculate the spreadsheet. When the user requests a
 recalculation, the second thread starts calculating in the background
 while the first thread prompts the user for the next command, without
 having to wait for the calculation to finish. In this manner, separate
 concurrent threads allow multiple operations to overlap, making the
 program faster, more responsive, and more efficient.

 In addition, OS/2 multitasking is protected at the hardware level.
 Memory is protected between processes; one process cannot
 inadvertently overwrite the code or data of another process. This
 provides the same level of reliability and integrity as found on
 mainframe computers.

 Memory Requirements
 -------------------

 The current version of Windows uses expanded memory (EMS) to get
 around the 640K limit of MS-DOS running in the real mode of the Intel
 8086/8088. While this greatly extends the amount of memory available
 to Windows applications, there are still some problems involved.
 Switching banks of memory in and out of expanded memory takes time,
 noticeably degrading performance.

 OS/2 was designed from the ground up to take advantage of the
 protected mode of the 80286/80386 processors. Moreover, OS/2 employs a
 virtual memory manager to extend accessible memory up to 1 gigabyte.

 Virtual 8086 Real Mode
 ----------------------

 Currently in Windows/386, protection faults are not as robust as they
 are in OS/2. Windows/386 recommends that you reboot your system if an
 application fails in one of the virtual machines.

 Graphical User Interface
 ------------------------

 The Graphical User Interface (GUI) employed by the OS/2 Presentation
 Manager (PM) and Microsoft Windows look and feel almost entirely the
 same. Any apparent differences are short-lived and are mostly due to
 differences in their respective production schedules. Even though
 these environments are implemented on two different operating systems,
 it is Microsoft's goal to eliminate any differences in their operation
 so that users of Microsoft Windows will not face any hurdles when
 upgrading to the OS/2 Presentation Manager.

 Interprocess Communication
 --------------------------

 OS/2 provides a complete system for interprocess communication (IPC)
 that lets concurrently executing programs (and threads within a
 program) share data and exchange messages. A variety of IPC mechanisms
 are available for different situations, including shared memory, named
 pipes, queues, and the Dynamic Data Exchange (DDE). For developers,
 this means much greater flexibility and power in selecting and using
 IPC techniques in their applications. Windows only supports DDE at
 this time.

 Who Should Use OS/2?
 --------------------

 OS/2 is the ideal operating system for intermediate to power users
 in business and engineering fields who need sophisticated
 multitasking, extensive graphics, advanced networking, or complex
 data-exchange capabilities.

 It's the operating system of choice for users who need the maximum
 functionality that can be delivered by today's personal computer
 systems. Typical applications range from business applications, such
 as accounting, human resources, and relational database systems to
 CAD, desktop publishing, or complex "mission-critical" applications.
 Mission-critical applications are designed to handle strategic
 business operations that are oriented to "the business of the
 business." Mission-critical applications usually deal with real-time
 or time-critical events. They are update intensive, involve many
 users, and usually include distributed functions. In Version 1.20 of
 OS/2, new enhancements will include a High Performance File System
 (HPFS) and extended file attributes.

 Typical Machine Configuration
 -----------------------------

 The hardware requirements for OS/2 and Windows/386 are essentially the
 same. The actual amount of memory you will require depends on the type
 of applications you are running, and whether or not you will be on a
 network (networks tend to use a lot of RAM). The hardware requirements
 are as follows:

 1. Fast Intel 80286-based or 80386-based personal computer

 2. Two to four MB memory

 3. IBM EGA or higher (or compatible) video adapter and monitor

 4. Microsoft Mouse or compatible


 635. RIPS Occur When WinDdePostMsg() Is Used in PM

 Problem:

 I have modified the sample DDE server code named PMSERVER in the
 Software Library. I put a DosSemRequest() and DosSemClear() around the
 code that handles the WM_DDE_ADVISE message (the semaphore doesn't
 protect anything, it just illustrates the problem). I also added more
 stocks and created an Excel spreadsheet that created 16 hot links (one
 for each stock). When you start the server and run the spreadsheet
 (under Excel for PM), the system hangs, even if you are using
 CodeView. If WinDdePostMsg() is removed from the semaphore, the system
 does not hang. The following sequence of events appears to occur:

 1. Excel posts a WM_DDE_ADVISE message.

 2. The server callback function gets the semaphore.

 3. The server tries to post an acknowledgment (still holding the
    semaphore).

 4. Excel posts another WM_DDE_ADVISE message.

 5. The server callback function is re-entered. The semaphore is not
    available, so something else blocks.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem and will post new information as it becomes
 available.

 Running the server and Excel does generate several unusual huge RIPs
 and 10 to 20 "cannot post msg, queue full" messages. The system is
 also left in an inconsistent state, although several display driver
 errors follow the "graceful" exit.

 The first RIPs seem to be generated from Excel code, i.e., they may be
 the ones causing the segmentation failure, although many RIPs from PM
 were quick to follow. Therefore, this problem appears to be a side
 effect of the way PM handles WinDdePostMsg().

 The workaround is to ensure that WinDdePostMsg() is not surrounded by
 DosSem*() functions that could potentially (easily) result in
 deadlock or other unexpected results in client applications not ready
 to be "delayed," or handle the effects of modal message loops.

 Additional reference words: softlib PMSERVER.ARC S12267.EXE


 636. CodeView Dotted Line Problem Occurs on VGA and EGA Systems

 The problem listed below appears to occur on most EGA and VGA systems.
 The following steps can be used to reproduce this problem:

 1. Start up CodeView on one monitor.

 2. Trace through an application until the initial border appears.

 3. Quit CodeView.

 4. At this point, you will be back to a full-screen prompt.

 5. Switch back to the task manager.

 6. A dotted line will be displayed on the screen.

 Microsoft has confirmed that this problem occurs in Version 1.10. We
 are researching this problem and will post new information as it
 becomes available.


 637. Sample Device Driver in C

 Question:

 Is there a sample device driver for OS/2 written in C?

 Response:

 There is a sample program in the Software Library that demonstrates
 the development of an OS/2 device driver written in C. This file can
 be found in the Software/Data Library by searching on the keyword
 SAMPDD, the Q number of this article, or S12374. SAMPDD was archived
 using the PKware file-compression utility.

 This archived library contains the following files:

    Filename             Contents
    --------             --------

    SAMPDD               Make file for the device driver
    ACRTUSED.ASM         Replacement main routine
    SAMPDD.C             C source for the device driver
    SEGENDS.ASM          Segment end routines
    STDDD.H              Device driver definition header
    SAMPDD.DEF           Linker definition file


 638. Non-PM Program Cannot Determine Window Size

 Question:

 How can a non-Presentation Manager (PM) program determine the size of
 the window that it is running in?

 Response:

 A VIO application running in a window of the PM screen group does not
 realize that it is running in this environment, and not in a
 full-screen screen group.

 PM runs a "shield layer" to control the PM window that the VIO
 application is running in. This shield layer bridges the normal
 application interface with PM (similar to the PM method of I/O, such
 as message-based keyboard and mouse I/O) with the base interface that
 the VIO application is used to. This shield layer is conceptually
 similar to the WINOLDAP interface that Microsoft Windows uses to run
 non-Windows applications under Windows.

 PM and AVIO applications can use the PM APIs to manipulate their
 environment. VIO applications don't have a window size when in full
 screen, so there are no VIO APIs to manipulate window size (since this
 is not a concern). And VIO applications do not have any system
 services to manipulate their window in this hybrid environment. The
 user can change the size of the window by using the size bars and the
 system menu of the window (controlled by this shield layer).

 Only executables that can be used properly in a PM window should be
 marked as being able to run in this environment (setting the
 WINDOWCOMPAT bit in the EXE header via the .DEF file or the MARKEXE
 utility).


 639. Change Directory Drive Problem in Version 1.10

 The command "CD DIR_NAME D:" (where "DIR_NAME" is the name of a
 directory and "D:" designates a drive letter) incorrectly causes the
 command processor to access the designated drive. This behavior occurs
 under both the real-mode and the protected-mode command processors.

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem and will post new information as it becomes
 available.


 640. Deciding Whether to Enable or Disable Spooler

 Question:

 With OS/2 Version 1.10, the Spooler Queue Manager is automatically
 loaded upon bootup. What factors should we take into consideration
 when we are deciding whether to enable or disable the spooler?

 Response:

 The decision on whether or not to use the spooler depends greatly on
 your own needs and system configuration.

 One factor you should consider is whether or not you need to run the
 LAN Manager Server Spooler (a different spooler than the PM Spooler).
 In Version 1.10 of Microsoft OS/2, these two spoolers are
 incompatible.

 If you are using LAN Manager Version 1.00 or 1.10 under OS/2 Version
 1.10, you should use the LAN spooler and disable the PM spooler. The
 spoolers are unaware of each other, and this causes conflicts in
 accessing the output device when both are enabled.

 Another factor to consider is that the PM Spooler is very resource
 intensive. It consumes a large chunk of low memory, and needs
 approximately 50 threads of its own. Consequently, the use of so many
 threads lowers the amount of threads available for other applications,
 and tends to take up a lot of CPU time (although the spooler threads
 will likely be low-priority threads).

 One final factor you should consider is whether you are running PM
 applications that have installable printer drivers. In Version 1.10 of
 Microsoft OS/2, these PM printer drivers depend on the presence of a
 spooler.

 Beyond these general guidelines, you will probably have to
 experiment with printing, with the spooler enabled or disabled to
 find out which configuration works best for you.


 641. Date Is Set Incorrectly When Time Command Is Used

 The following problems occur in Version 1.10 of OS/2:

 1. At a full-screen command prompt, if the current date is 6-30-89 and
    I execute the following command

       TIME 23:59:59.99

    the date incorrectly changes to 6-31-89, even though June only has
    30 days in it. If I then execute "TIME 23:59:59.99" again, the date
    changes to 7-2-89.

 2. At a windowed command prompt, if the current date is 6-30-89 and I
    execute the following command:

       TIME 23:59:59.99

    the date incorrectly changes to 6-31-89, even though June only has
    30 days in it. If I then execute "TIME 23:59:59.99" again, an error
    code of SYS1044 is returned. This problem also occurs with the
    dates of 4/30 and 9/30.

 Microsoft has confirmed these to be problems in Version 1.10 of OS/2.
 We are researching these problems and will post new information as it
 becomes available.


 642. XCOPY with /S Option Incorrectly Copies Empty Subdirectories

 When I run XCOPY when using the /s option, XCOPY copies all of the
 subdirectories, even if they are empty.

 Microsoft has confirmed this to be a problem in Version 1.10 of MS
 OS/2. We are researching this problem and will post new information as
 it becomes available.


 643. DIR Command Fails with Trap D Error in OS/2 Version 1.10

 When you run the following DIR command, a TRAP D error occurs:

    DIR aaaa.....a  (until input area is full)

 Microsoft has confirmed this to be a problem in Version 1.10 of OS/2.
 We are researching this problem and will post new information as it
 becomes available.


 644. Resizing Segments with DosRealloc()

 Question:

 Can I reallocate a block of memory that I used DosSubAlloc() on?

 Response:

 You can only increase the size of a local heap created with
 DosSubSet(); you cannot decrease it.

 Segments that are resized with DosReallocSeg() must be resized with
 DosSubSet(). If not, the manipulation of the suballocations within the
 segment is undefined. For example:

    DosReallocSeg(tbytes,pGRFCB.sel); /* Reallocates fine when Adding,
                                         but returns an error of 5L when
                                         the memory size is decreased */

 To do this correctly (with shared segments only), you must set up your
 segment and OR it with 0x0008 for the attribute. For example:

    SEG_GETTABLE | 0x0008


 645. STATUSDATA "BindInd" Field Name Documentation Error

 Microsoft has confirmed the following to be a problem in the version
 of QuickHelp included with the Version 1.10 OS/2 SDK (Software
 Development Kit), and on Page 365 of the "Microsoft Operating System/2
 Programmer's Reference Volume 3" for Version 1.10. The STATUSDATA
 entry incorrectly lists a field called "BindInd". However, in the
 include file named BSEDEF.H, the actual name is "BondInd".

 We are researching this problem and will post new information when the
 documentation has been updated to correct this problem.


 646. DosStartSession() "Related" Field Documentation Error

 Microsoft has confirmed that the information for the "Related" field
 of the STARTDATA structure listed in the DosStartSession()
 documentation is incorrect on Page 153 of the "Microsoft Operating
 System/2 Programmer's Reference Volume 3" for Version 1.10, and in the
 version of QuickHelp included with the Version 1.10 OS/2 SDK (Software
 Development Kit).

 The documentation incorrectly states the following:

    An independent session is created when the Related field of the
    STARTDATA structure is set to TRUE.

 Instead, it should state the following:

    If the related field is FALSE, the new session is an independent
    session (not related).

 We are researching this problem and will post new information when
 the documentation has been updated to correct this error.


 647. "See Also" Section of WM_QUERYTRACKINFO Documentation Error

 The "See Also" section of the WM_QUERYTRACKINFO documentation
 incorrectly lists WM_QUERYTRACKINFO again as a reference.

 Microsoft has confirmed this to be a problem in the version of
 QuickHelp included with the Version 1.10 OS/2 SDK (Software
 Development Kit), and on Page 452 of the "Microsoft Operating System/2
 Programmer's Reference Volume 2" for Version 1.10. We are researching
 this problem and will post new information when the documentation has
 been updated to correct this error.


 648. NLSINFO: National Language Support Sample Program

 There is a file in the Software/Data Library named NLSINFO that
 displays most of the NLS (National Language Support) features of
 OS/2. NLSINFO can be found in the Software/Data Library by searching
 on the keyword NLSINFO, the Q number of this article, or S12409.
 NLSINFO was archived with the PKware file-compression utility.

 NLSINFO uses the Family API functions DosGetCntryInfo(),
 DosGetCollate(), and DosGetCp() to obtain various local-dependent
 information. In addition to the information returned by these three
 FAPI functions, NLSINFO also creates a table of information based on
 the MS-DOS and OS/2 user documentation to provide more information
 about the localized environment. For example, see the COUNTRYNAME
 table. This table can easily become outdated because it is not part of
 the operating system. Please refer to the MS-DOS and OS/2 user
 documentation for the most recent information on this table.

 The compile instructions for NLSINFO are as follows:

    cl /Lp /Fb /W3 NLSINFO.C

 After compiling NLSINFO.C, a dual-mode NLSINFO.EXE file will be
 created that can be run in MS-DOS (Version 3.30 or later) real mode or
 in OS/2 protected mode.

 The run-time command-line usage of NLSINFO is as follows, where
 <countrycode> is a valid country code and <codepage> is a valid
 codepage:

    NLSINFO <countrycode> <codepage>

 If these values are both omitted, the program uses the default values
 of 0 (zero) for each parameter, and also uses the current country and
 codepage information for the current process. See the batch files
 NLSTEST.CMD and NLSTEST.BAT for examples of how to invoke NLSINFO.EXE.

 Remember, when using MS-DOS, the program NLSFUNC must be running if
 you want to obtain NLS-related information for any country but the
 current (default) country. No similar precaution is required when
 running OS/2.


 649. CSALIAS.C: Dynamic Creation of CS-Aliased Code Segment

 Listed below is the program CSALIAS.C, which dynamically creates a
 CS-aliased code segment and executes some code from within this
 segment. CSALIAS.C demonstrates how to use the following OS/2 APIs:

    DosCreateCSAlias()
    DosAllocSeg()
    DosFreeSeg()

 A data segment is allocated by calling DosAllocSeg(). A small
 assembly-language routine is created in this data segment. An
 alias-code selector for this data segment is obtained by calling
 DosCreateCSAlias(). Using the alias-code selector, the routine in the
 data segment is called. After returning from the routine, the
 alias-code selector and the data segment are freed by calling
 DosFreeSeg().

 CSALIAS.C illustrates the use of DosCreateCSAlias(); it does not do
 anything useful. A more likely use of aliasing code to data is where
 the code is actually generated at run time, rather than statically
 declared in this example.

 If DEBUG is #defined, then the program will display more verbose
 output about the success or failure of an API call.

 CSALIAS.C uses only Family API functions and thus can be linked and
 bound to work in either the MS-DOS or OS/2 environments.

 CSALIAS.C should be compiled with the following options:

    cl /AL /G2 /Lp /Fb /W3 CSALIAS.C

 This software is provided for demonstration purposes only. Microsoft
 makes no warranty, implied or otherwise, regarding its performance or
 reliability in any situation.

 Copyright (C) Microsoft Corp. 1986, 1989

 /* include files */

 #define INCL_DOS
 #define INCL_DOSMEMMGR
 #include <os2.h>

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

 /* -------------------------------------------------------------- */

 /* constants */

 #define TEST_VALUE  3  /* To be squared by procedure in CSAliased
                           segment */

 /* A routine that computes the square of an integer */
 UCHAR aucOpCodes[] =
 {
     0x55,                                 /* push  bp        */
     0x8B, 0xEC,                           /* mov   bp,sp     */
     0x8B, 0x46, 0x06,                     /* mov   ax,[bp+6] */
     0xF7, 0xE0,                           /* mul   ax        */
     0x8B, 0xE5,                           /* mov   sp,bp     */
     0x5D,                                 /* pop   bp        */
     0xCB                                  /* retf            */
 };

 /* -------------------------------------------------------------- */

 /* Function prototypes */

 int main(int argc, char *argv[]);
 void TestError(USHORT usError, PSZ pszApiName);

 /* -------------------------------------------------------------- */

 /* Main program */

 int main(int argc, char *argv[])
 {

     USHORT usError;                 /* API return code */
     SEL selDataSegment;             /* Selector to data segment */
     SEL selCodeSegment;             /* Alias code segment selector */
     PCH pchDataSegment;             /* Pointer to data segment */
     LONG lSquareOfInt;              /* Holds square of an integer */
     PVOID pvResult;                   /* result of memcpy() */
     LONG (*pfnIntSquareRoot)(USHORT); /* Pointer to a procedure */

     /* Allocate a segment */
     usError = DosAllocSeg(sizeof(aucOpCodes), &selDataSegment,
                           SEG_NONSHARED);
     TestError(usError, "DosAllocSeg");

     /* Construct a far pointer to the data segment */
     pchDataSegment = MAKEP(selDataSegment, 0);

     /* Copy an assembly language procedure into the data segment */
     printf("fyi: sizeof(aucOpCodes) = %d\n", sizeof(aucOpCodes));
     pvResult = memcpy(pchDataSegment, aucOpCodes,
                       sizeof(aucOpCodes));

     /* Get a CSAlias selector for the data segment */
     usError = DosCreateCSAlias(selDataSegment, &selCodeSegment);
     TestError(usError, "DosCreateCSAlias");

     /* Construct the address to the procedure in the CSAliased
        segment */
     pfnIntSquareRoot = MAKEP(selCodeSegment, 0);

     /* Execute the code in the CSAliased data segment */
     lSquareOfInt = (*pfnIntSquareRoot)(TEST_VALUE);
     if (lSquareOfInt != (TEST_VALUE * TEST_VALUE))
     {
         printf("Failure: procedure in CSAliased segment failed\n");
     }
     else
     {
         printf("Success: procedure in CSAliased segment worked\n");
     }

     /* Free the alias code selector */
     usError = DosFreeSeg(selCodeSegment);
     TestError(usError, "DosFreeSeg");

     /* Free the data segment */
     usError = DosFreeSeg(selDataSegment);
     TestError(usError, "DosFreeSeg");

     /* End the program */
     exit(0);

 } /* main */

 /* -------------------------------------------------------------- */

 /* Test an OS/2 API return code; choke and die if unsuccessful */

 void TestError(USHORT usError, PSZ pszApi)
 {

     if (usError)
     {
         printf("Error: %s API returned %u!\n", pszApi, usError);
         exit(1);
     }
 #ifdef DEBUG
     else
     {
         printf("debug: %s API worked successfully\n", pszApi);
     }
 #endif /* DEBUG */

 } /* TestError */

 /* ------------------------------------------------------------ */


 650. Using DosOpen() File Size Option

 Question:

 I have a question concerning the file-size option in the DosOpen()
 function, and the cbFilealloc parameter of the DosQFileInfo()
 function. Does the file-size parameter of DosOpen() specify the size
 of the file, or the amount of data that is going to be written to it?

 If I specify a file size of 200 and then use the DosQFileInfo()
 function, it shows the end of data to be 200 when in actuality I have
 only written 13 bytes to the file. DosQFileInfo() also shows the
 cbFilealloc parameter to be 2048 (2K) when I would expect it to be
 200, or 2K, or some other kind of default value.

 Response:

 The DosOpen() file-size parameter is used to pre-allocate space for
 your file when you create a new file. If you open an existing file,
 this parameter is ignored. Usually, when you create a new file with
 DosOpen(), you will specify a size of 0 (zero) since DosWrite() gets
 space as it needs it. You would use a file size other than 0 if you
 were concerned that a file would not fit on the disk and you needed to
 know this information before you started writing to the file (e.g.
 if you were running a real-time application).

 The size of the file and the space allocated the file on the disk are
 actually two different things. The smallest amount of space that can
 be allocated to a file is a cluster. A cluster is some fixed number of
 sectors (1 sector = 512 bytes). On your hard disk, 1 cluster = 4
 sectors (2K bytes). Space is allocated one whole cluster at a time.

 Thus, for every file, up to 2K bytes (1 cluster) of space on your hard
 disk may be wasted. This is necessary because otherwise performance on
 your hard disk would be unbearably slow. If you are interested in more
 details about how files are stored, you can find this information in
 one of Peter Norton's books, or in one of the many other books on
 MS-DOS (the system hasn't changed from MS-DOS in this respect).


 651. Using DosOpen() to Open and Write to a COM: Port

 Problem:

 I am trying to write a debug utility for Presentation Manager (PM)
 that writes the output of a passed parameter to a debug terminal
 connected to COM1:. When I try to open COM1: for writing using the
 DosOpen() API function, it returns an error 12, ERROR_INVALIDACCESS.
 In Chapter 46, on Page 626 of the "Microsoft Operating System/2
 Programmer's Reference Volume 1" for Version 1.10, it states that
 DosOpen() can be used to open COM1: and then DosWrite() can be used to
 write to the device.

 Response:

 To avoid receiving this error, you need to use the OPEN_SHARE_*
 attribute in addition to the OPEN_ACCESS_* flag in the DosOpen() API.
 Listed below is a sample program that demonstrates how to use these
 attributes correctly:

 #include <stdio.h>
 #include <stdlib.h>
 #define INCL_BASE
 #include <os2.h>

 int main(void);

 int main(void)
 {

    CHAR   szbuffer[10];
    HFILE  hf;
    USHORT usBytesWritten;
    USHORT usRes;
    USHORT usAction = FILE_EXISTED;

    usRes = DosOpen("com1", &hf, &usAction, 0L, FILE_NORMAL,
                     FILE_OPEN,OPEN_ACCESS_READWRITE |
                     OPEN_SHARE_DENYREADWRITE, 0L);
    if (usRes != 0)
    {
        itoa(usRes, szbuffer, 10);
        puts("Error opening file");
    }
    else
    {
        puts("opened COM1, writing to it...");
        DosWrite(hf, "Hey you guys!!!/n/r", 18, &usBytesWritten);
        if (usBytesWritten < 15)
        {
            puts("bytes written != string sent");
        }
        else
        {
            puts("DosWrite to COM1 worked");
        }

        DosClose(hf);
    }
    exit(0);
    return (0);

 } /* main */


 652. Spooler Queue Manager Problems in OS/2 SDK Version 1.10

 Microsoft has confirmed that the following problems exist with the
 Spooler Queue Manager included with the Version 1.10 OS/2 SDK
 (Software Development Kit):

 1. The Spooler Queue Manager does not delete the files that have
    already been sent to the printer. These files remain in the
    \SPOOL subdirectory and their file length is zero bytes.

 2. The Spooler Queue Manager cannot delete a print job directed to a
    device that is not currently available, e.g. if no printer is
    installed on LPT1:. Sometimes even a reboot does not help the job
    to disappear from the print queue.

 We are researching these problems and will post new information as
 it becomes available.


 653. Programmatically Querying LIBPATH Information in CONFIG.SYS

 Question:

 Is there a way to query the LIBPATH information in the CONFIG.SYS file
 programmatically?

 Response:

 Unfortunately, LIBPATH is one piece of system information that is not
 directly available from an API. LIBPATH is not an environment variable
 and its value is not as easy to determine as some of the other system
 configuration parameters set in the CONFIG.SYS file.

 Given the present constraints, one workaround is to set a LIBPATH
 environment variable in your CONFIG.SYS file.

 An alternative is to take the same approach as the LIBWHERE utility.
 Generally speaking, this utility first calls DosGetInfoSeg() to
 retrieve the boot drive from the GINFOSEG structure. Next, it opens
 the file CONFIG.SYS (or CONFIG.OS2, as appropriate to the
 circumstances) and performs a DosExecPgm() on WHERE.EXE, directing the
 WHERE utility to traverse the LIBPATH string and look for what the
 user has specified.


 654. Use of CTRL+P in DOS 3.x Box Doesn't Echo Output to Printer

 In the DOS 3.x box, the use of CTRL+P does not echo output to the
 printer as it should.

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem and will post new information as it becomes
 available.


 655. JOIN Command Doesn't Work Correctly in OS/2 1.10

 Using the following operations in the DOS 3.x box causes OS/2 to crash
 with a Trap 000D error:

 1. JOIN A: JOINDIR

 2. MD \JOINDIR\ABC

 3. RD \JOINDIR\ABC

 Also, deleting a JOINed subdirectory is incorrectly allowed in Step 6
 of the following operations:

 1. Change to DOS 3.x box

 2. C:\> JOIN A: JOINDIR

 3. C:\> MD \JOINDIR\ABC

 4. C:\> CD \JOINDIR\ABC

 5. Change to protected mode

 6. (C:\) RD A:\ABC

 Microsoft has confirmed these to be problems in Version 1.10. We are
 researching these problems and will post new information here as it
 becomes available.


 656. Using Access and Share Modes with DosOpen()

 When setting the parameter fsOpenMode to assign the access and share
 modes for a DosOpen() call, a share mode MUST be specified. An access
 mode may be bitwise ORed with the share mode, as well as one or more
 miscellaneous open flags.

 Refer to the "DosOpen" section of the "Microsoft Operating System/2
 Programmer's Reference Volume 3," Pages 95-98, for more information on
 DosOpen().

 Share modes specify what operations other processes can perform on the
 opened file. Every DosOpen() call must have a share mode specified.
 The following are the share modes available for DosOpen() in OS/2
 Version 1.10:

      Constant                      Value
      --------                      ------
      OPEN_SHARE_DENYREADWRITE      0x0010
      OPEN_SHARE_DENYWRITE          0x0020
      OPEN_SHARE_DENYREAD           0x0030
      OPEN_SHARE_DENYNONE           Ox0040

 An access mode may be bitwise ORed with the share mode. Access modes
 specify the operations the opening process may perform on the opened
 file. The access modes for DosOpen() in OS/2 1.10 are as follows:

      Constant                      Value
      --------                      ------
      OPEN_ACCESS_READONLY          0x0000
      OPEN_ACCESS_WRITEONLY         0x0001
      OPEN_ACCESS_READWRITE         0x0002

 There are four other flags that may be ORed with the share mode in
 OS/2 1.10. These are:

      Constant                      Value
      --------                      ------
      OPEN_FLAGS_NO_INHERIT         0x0080
      OPEN_FLAGS_FAIL_ON_ERROR      0x2000
      OPEN_FLAGS_WRITE_THROUGH      0x4000
      OPEN_FLAGS_DASD               0x8000

 When using DosOpen() to open a drive with OPEN_FLAGS_DASD (0x8000), an
 access mode of 10H is also required.

 The following is a sample program using DosOpen():

 #include<os2def.h>
 #include<bsedos.h>
 #include<stdio.h>

 void main(void)
 {
     USHORT ret = 0;                /* return code */
     USHORT Action;                 /* DosOpen returns action taken */
     HFILE Handle;                  /* file handle variable */

     ret = DosOpen("direct.c",&Handle, &Action, 0L, FILE_NORMAL,
                FILE_OPEN, OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYNONE,
                0L);

     printf("Return value = %hu, action = %hu\n", ret, Action);
 }


 657. How to Correctly Install DUALBOOT Option

 Problem:

 I cannot install the DUALBOOT option on my machine when using MS-DOS
 Version 3.30 and OS/2 Version 1.10. I first made a MS-DOS partition,
 then installed OS/2 Version 1.10 and the DUALBOOT option. During the
 installation of the DUALBOOT option, I received the following error
 message:

    Dual boot cannot be installed because DOS could not be installed
    on Drive C.

 Response:

 This error occurs because the SYS command on the MS-DOS disk failed;
 there is not enough room for the system files (MS-DOS), or the first
 two entries in the root directory are not available.

 To work around this problem, do the following:

 1. Use FDISK on the drive with either OS/2 or MS-DOS (using MS-DOS
    guarantees the correct partition size for the MS-DOS system files).

 2. Format the drive using the MS-DOS FORMAT.COM program with the /s
    parameter. This will give you the first two slots for MS-DOS. You
    should be careful that there are no clashes with the MS-DOS utility
    names; therefore, you should copy the MS-DOS utilities into a
    separate subdirectory.

 3. Install OS/2. During the install process, when it asks if you want
    to install the DUALBOOT option, answer yes. When the system is
    running, enter "boot /dos" and CTRL+ALT+DEL, and you will boot
    automatically into MS-DOS.


 658. DIR > PRN Printer Redirection Error Handling Problem in 1.10

 Microsoft has confirmed that the following printer error handling
 problem occurs in Version 1.10. We are researching this problem and
 will post new information here as it becomes available.

 The following steps reproduce this problem:

 1. Disable the print spooler.

 2. Start the OS/2 command prompt.

 3. Enter "DIR > PRN".

 4. Turn off the printer before the DIR command completes.

 5. Wait until the error box is generated.

 6. Select "END PROGRAM".

 7. Turn on the printer; note that the printer does not reset itself.

 8. Enter "DIR > PRN".

 Once this error occurs, the printer will not work until it is
 reinitialized.


 659. Sending Printer Output to COM1 in OS/2 Versions 1.10, 1.20

 Problem:

 I can't get the OS/2 PRINT command to send output to the COM1 port
 under OS/2 Version 1.10. Under Version 1.00, I only have to do the
 following:

    MODE COM1: 9600,N,8,1,XON=ON
    SPOOL c:\spool /D:lpt1 /O:com1

 I then enter "PRINT <filename>" to send output to COM1.

 Under OS/2 Version 1.10, the /D and /O options to SPOOL don't seem to
 do the same thing as they did in Version 1.00. If I use the same
 commands (above) under Version 1.10 (ensuring that the Control Panel
 does not start the spooler first), I can copy a file to COM1 with no
 problems; however, the use of PRINT or COPY to LPT1 or to PRN causes
 an error of "SYS0047" (can't write to LPT1 device) to occur.

 Response:

 Currently, there are some problems with OS/2 Version 1.10 trying to
 redirect printer output from LPTn to a COM port. We suggest you use
 the following steps to redirect printer output from LPTn to a COM
 port:

 1. Make sure that the Control Panel printer connection is not on the
    COM port you want.

 2. From the command line, issue the MODE command to set the baud rate,
    etc., for the COM port. For example:

       MODE COM2:96,n,8,1

 3. From the command line, issue the SPOOL command to redirect printing
    from LPTn to a COM port. For example:

       SPOOL /D:LPT1 /O:COM2

 4. Go back to the Control Panel and set the printer connection to the
    COM2 port, then set the COM2 parameters to the same parameters as
    specified in the MODE command.

 5. Direct OS/2 to print your file. For example:

       PRINT /D:LPT1 FILENAME.EXT

 You now should be able to print to COM2. However, you will not be
 able to use the SPOOL command a second time for redirection. If you
 try to do this, the following message is displayed:

    SYS1793 The Presentation Manager input device specified by
    the spool command is busy and cannot be used by the spooler

 Currently, you must go through these steps every time you boot up your
 machine.

 Microsoft has confirmed that the workaround listed above does not work
 in Version 1.20. In Version 1.20, the SPOOL command accepts the
 redirection of the printer output; however, it doesn't really redirect
 the printer output. We are researching this problem and will post new
 information here as it becomes available.


 660. Named Pipes Can Be Redirected Like Files

 Question:

 Can named pipes be used in redirection the same way files are? For
 example, assuming that I have a named pipe server that made or
 connected a named pipe called /PIPE/MARK in byte mode, can I do the
 following?

    C> dir >/PIPE/MARK

    C> copy  x.dat  /PIPE/MARK

    C> echo "This is a string" > /PIPE/MARK

 Just how far are named pipes embedded in the file system?

 Response:

 The commands listed above will work as long as the named pipes are
 manipulated at the server end with the DosRead() function instead of
 transacts. In other words, as long as the named pipe is set up
 correctly, it will work. However, this does mean that the named pipes
 are not seamlessly embedded into the file system. You cannot find a
 named pipe on your system and use it in the above fashion and expect
 it to work every time.


 661. How to Detect When End of Pipe Has Been Reached

 Question:

 How can we detect when we have reached the end of a pipe?

 Response:

 For anonymous pipes, there is no way to tell when you have reached the
 end of the pipe (at least, there is no system-defined method). When
 you have no bytes in a pipe (whether at the end or there has been no
 write), a DosRead() will block until something is written. If the pipe
 has been closed, a DosRead() will return with an error. At this point,
 you know that you have reached the end of the pipe. You can also set
 up some sort of communication between processes so that you can send a
 string of bytes that represents the end of transmission or something
 similar to this.


 662. Moving Subdirectory Entries under OS/2

 Question:

 We are trying to move a subdirectory entry. We would like to use
 DosMove(); however, this doesn't work unless we use both DosMkDir()
 and DosMove() on each of the individual files and subdirectory entry.
 Is there an easier way to do this?

 Response:

 Unfortunately, there is no better way under OS/2 Version 1.10 to move
 entire subdirectories.


 663. PRTYC_FOREGROUND Priority Class Is Undocumented in 1.10

 Microsoft OS/2 has a priority class of 4 and it is called
 PRTYC_FOREGROUND. It works the same as IBM's "Fixed High" priority
 class. PRTYC_FOREGROUND became available in OS/2 Version 1.10, but was
 not documented in either the "Microsoft Operating System/2
 Programmer's Reference Volume 3 for Version 1.10" (Page 145) or the
 version of QuickHelp included with the Version 1.10 OS/2 SDK (Software
 Development Kit. The following is the correct description for
 PRTYC_FOREGROUND and the other priority classes:

    Parameter   Description
    ---------   -----------
    fPrtyClass  Specifies the priority class of a process or thread.
                This can be one of the following values:

                Value               Meaning
                -----               -------
                PRTYC_IDLETIME      Idle time.
                PRTYC_NOCHANGE      No change; leave as is.
                PRTYC_REGULAR       Regular.
                PRTYC_FOREGROUND    Foreground server.
                PRTYC_TIMECRITICAL  Time-critical.

 Comments
 --------

 The PRTYC_FOREGROUND priority is higher than PRTYC_REGULAR, but lower
 than PRTYC_TIMECRITICAL. PRTYC_FOREGROUND is a static priority that is
 not changed by the system. This allows a thread or process in a
 background screen group to service requests of a foreground process in
 a timely manner. Because the priority level is static, this priority
 should be used only when absolutely necessary. Indiscriminate use
 degrades system performance.


 664. DosSetMaxFH() usHandles Parameter Maximum Value Is 32,768

 Microsoft has confirmed that there is a documentation error on Page
 142 of the "Microsoft Operating System/2 Programmer's Reference Volume
 3" for Version 1.10 and in the Version of QuickHelp included with the
 Version 1.10 OS/2 SDK (Software Development Kit). The documentation
 incorrectly states that the maximum value for the "usHandles"
 parameter is 255. The maximum value has been changed to 32,768.

 We will post new information when the documentation has been updated
 to correct this error.


 665. DosPeekNmPipe() "pcbAvail" Parameter Documentation Error

 The documentation for the DosPeekNmPipe() "pcbAvail" parameter is
 incorrect on Page 100 of the "Microsoft Operating System/2
 Programmer's Reference Volume 3" for Version 1.10 and in the Version
 of QuickHelp included with the Version 1.10 OS/2 SDK (Software
 Development Kit). This problem was corrected in the version of
 QuickHelp included in the version of the Presentation Manager Toolkit
 for Version 1.20.

 The correct documentation for this parameter is listed below, along
 with the rest of the documentation for the DosPeekNmPipe() function
 and the AVAILDATA structure. Please note that a new structure,
 AVAILDATA, has been defined. This structure definition should be
 placed in your BSEDOS.H file, along with a corrected function
 prototype for DosPeekNmPipe().

 #define INCL_DOSNMPIPES

 USHORT DosPeekNmPipe(hp, pbBuf, cbBuf, pcbRead, pcbAvail, pfsState)
 HPIPE hp;             /* pipe handle                               */
 PBYTE pbBuf;          /* pointer to buffer for data                */
 USHORT cbBuf;         /* length of buffer for data                 */
 PUSHORT pcbRead;      /* pointer to variable for number bytes read */
 PAVAILDATA pAvail;    /* pointer to variable for number bytes
                          available                                 */
 PUSHORT pfsState;     /* pointer to variable for pipe state        */

 The DosPeekNmPipe function copies a pipe's data into a buffer.

    Parameter  Description
    ---------  -----------
    hp         Identifies the pipe to read from.

    pbBuf      Points to a buffer that receives the data from the pipe.

    cbBuf      Specifies the length (in bytes) of the buffer that
               receives the data from the pipe.

    pcbRead    Points to the variable that receives a value specifying
               the number of bytes read from the pipe.

    pAvail     Points to the AVAILDATA structure that the receives a
               value specifying the number of bytes that were available
               to be read.

    pfsState   Points to the variable that receives the state of the
               pipe. The state may be one of the following values:

               Value                    Meaning
               -----                    -------
               PIPE_STATE_CLOSING       The pipe is closed and can no
                                        longer be used.

               PIPE_STATE_CONNECTED     The pipe has been opened and is
                                        available for reading and
                                        writing.

               PIPE_STATE_DISCONNECTED  The serving end must call the
                                        DosConnectNmPipe function to put
                                        the pipe into a listening state
                                        before a call to the DosOpen
                                        function will be accepted. A pipe
                                        is in a disconnected state between
                                        a call to the DosMakeNmPipe
                                        function and a call to the
                                        DosConnectNmPipe function.

               PIPE_STATE_LISTENING     The pipe will accept a call to
                                        the DosOpen function.

 Return Value
 ------------

 The return value is zero if the function is successful. Otherwise,
 it is an error value, which may be one of the following:

    ERROR_BAD_PIPE
    ERROR_PIPE_NOT_CONNECTED

 Comments
 --------

 The DosPeekNmPipe function never blocks, regardless of the blocking
 mode of the pipe.

 If the DosDisConnectNmPipe function has been called, the pipe will
 remain disconnected until a call is made to the DosConnectNmPipe
 function.

 #define INCL_DOSNMPIPES

 typedef struct _AVAILDATA {    /* avldt */
     USHORT  cbpipe;
     USHORT  cbmessage;
 } AVAILDATA;

 The AVAILDATA structure contains information about the bytes in a
 named pipe.

    Field      Description
    -----      -----------
    cbpipe     Specifies the number of bytes left in the pipe.

    cbmessage  Specifies the number of bytes left in the current
               message.


 666. Documentation Incorrect for UNPACK "/v" Switch

 Microsoft has confirmed that the documentation for the "/v" option of
 the UNPACK program on Page 142 of the "Microsoft Operating System/2
 Desktop Reference" for Version 1.10 is incorrect.

 The documentation should state that when the "/v" option is specified,
 it enables disk write verification. This means that it has the same
 meaning and effect as the "/v" switch used with the COPY command.

 We will post new information when this error has been corrected in the
 documentation.


 667. DCBINFO Structure Fields Not Documented Correctly

 The DCBINFO structure is defined on Pages 263, 270, and 336 in the
 "Microsoft Operating System/2 Programmer's Reference Volume 3" for
 Version 1.10. Listed below are the definitions for this structure that
 demonstrate that three of the fields are named differently on the
 various pages of the documentation:

     Pages 263 and 270                 Page 336 and BSEDEV.H
     -----------------                 ----------------------

    typedef struct _DCBINFO {          typedef struct _DCBINFO {
        USHORT usWriteTimeout;             USHORT usWriteTimeout;
        USHORT usReadTimeout;              USHORT usReadTimeout;
        BYTE   fbFlages1;                  BYTE   fbCtlHndShake;
        BYTE   fbFlages2;                  BYTE   fbFlowReplace;
        BYTE   fbFlages3;                  BYTE   fbTimeout;
        BYTE   bErrorReplacementChar;      BYTE   bErrorReplacementChar;
        BYTE   bBreakReplacementChar;      BYTE   bBreakReplacementChar;
        BYTE   bXONChar;                   BYTE   bXONChar;
        BYTE   bXOFFChar;                  BYTE   bXOFFChar;
    } DCBINFO;                         } DCBINFO;

 The field names for the DCBINFO structure were changed in the Version
 1.10 OS/2 Software Development Kit (SDK) so that they more clearly
 documented their intended purpose. The physical definition and use of
 the DCBINFO structure have not changed.

 The documentation of the DCBINFO structure as it appears on Page 263
 and 270 is in error. To be consistent, these pages should be changed
 to agree with the documentation of the DCBINFO structure as it appears
 in the header file BSEDEV.H, and as it appears on Page 336.


 668. Detached QuickHelp Session Hangs If ALT+Q Is Pressed

 When you issue the command DETACH QH from a full-screen session and
 hold down the ALT+Q keystroke sequence until the QuickHelp logo screen
 is displayed, the session appears to hang until you switch to another
 session, then bring up and terminate the detached QuickHelp session.
 This problem seems to occur because the ALT+Q keystroke sequence is
 being held down at the wrong time (i.e., before QuickHelp has finished
 initializing itself).

 Microsoft has confirmed this to be a problem in the Version 1.10 OS/2
 SDK (Software Development Kit). We are researching this problem and
 will post new information as it becomes available.


 669. TABLE Referenced But Not Documented in QuickHelp

 Microsoft has confirmed that in the version of QuickHelp included with
 the Version 1.10 OS/2 Software Development Kit (SDK) the ACCEL entry
 lists TABLE as a reference; however, there isn't any further
 documentation included for TABLE in QuickHelp.

 We are researching this problem and will post new information as it
 becomes available.


 670. KbdClose() Is Not Flushing Keyboard Buffer in OS/2 1.10

 In OS/2 Version 1.10, KbdClose() does not flush the keyboard buffer
 before closing the logical keyboard. The following code can be used to
 duplicate this problem:

 #define INCL_DOS
 #define INCL_KBD
 #include <os2.h>
 #include <stdio.h>
 #include <stdlib.h>

 #ifndef NO_DEBUG
     #define EXIT_ON_ERROR( szAPI, usErr )                       \
         {                                                       \
         if( (usErr) )                                           \
             {                                                   \
             printf( "\n%s error %d at line %d in file %s\n",    \
                     (szAPI), (usErr), __LINE__, __FILE__ );     \
             exit( (usErr) );                                    \
             }                                                   \
         }
 #else
     #define EXIT_ON_ERROR( szAPI, usErr )     ;
 #endif

 VOID main( VOID )
     {
     HKBD    hkbd;
     USHORT  usError;

     usError = KbdOpen( &hkbd );
     EXIT_ON_ERROR( "KbdOpen", usError );

     usError = KbdGetFocus( 0, hkbd );
     EXIT_ON_ERROR( "KbdGetFocus", usError );

     usError = DosSleep( 5000L );
     EXIT_ON_ERROR( "KbdGetFocus", usError );

     /*
     ** usError = KbdFlushBuffer( hkbd );
     ** EXIT_ON_ERROR( "KbdFlushBuffer", usError );
     */

     usError = KbdClose( hkbd );
     EXIT_ON_ERROR( "KbdClose", usError );

     } /* End main() */

 Microsoft has confirmed that if you run the code listed above in
 either a full-screen group or a VIO text window under PM in Version
 1.10, either a GP fault occurs or the system crashes. This problem
 does not occur in Version 1.10 if you call KbdFlushBuffer() before
 KbdClose() and run the code in a full screen group. However, calling
 KbdFlushBuffer() before KbdClose() does not help the situation when
 running the sample code in a VIO window under PM in Version 1.10.

 We are researching this problem and will post new information as it
 becomes available.


 671. When to Use DosExecPgm() and/or DosStartSession()

 Question:

 If I make a Presentation Manager (PM) program a detached child
 process, a protection violation occurs when the parent process starts
 the child process. Why does this protection violation occur?

 Response:

 A protection violation occurs if you execute the child application
 incorrectly. Listed below is the method that CMD.EXE uses to execute
 applications. It has to execute full-screen and windowable VIO
 applications, AVIO applications, and PM applications, from either a
 full-screen group or the PM screen group. CMD.EXE will use either
 DosExecPgm() or DosStartSession() to execute a program, based on the
 type of executable the program to execute is [this is done by reading
 the EXE header or by using DosQAppType()] and what kind of screen
 group is currently being run [a field in DosGetInfoSeg()'s
 LINFOSEG.typeProcess].

 In summary, DosStartSession() is used to execute PM and AVIO
 applications. DosStartSession() is also used when CMD is running in
 the PM screen group and trying to execute a full-screen application,
 and DosExecPgm() is used when executing VIO applications. The
 following table shows these relationships:

    Executable              VIO-Windowable      Full-Screen
    Type File               Screen Group        Screen Group
    ----------              ------------        ------------

    VIO-Full Screen         DosStartSession()   DosExecPgm()
    VIO-Windowable          DosExecPgm()        DosExecPgm()
    Advanced VIO            DosStartSession()   DosStartSession()
    Presentation Manager    DosStartSession()   DosStartSession()


 672. Interpreting Trap Information in OS/2

 The following is information on how to interpret and use the
 information the system provides in an OS/2 trap message.

 There are two kinds of traps. These traps are described below,
 followed by a discussion of the information contained in traps and how
 that information is used:

 RING 3 TRAPS
 ------------

 Ring 3 traps occur at the application level and are usually
 distinguished by the harderr pop-up that gives you a choice of ending
 the program. This usually is a protection fault (Trap D) or a stack
 fault (Trap C). When you get either of these traps, the process has
 already been killed and has been cleaned up.

 RING 0 TRAPS
 ------------

 Ring 0 traps are a more serious error that occurs in kernel or device
 driver code. These traps are usually accompanied by the phrases
 "internal system error" and "the system is stopped." They are serious
 problems with the kernel and/or your configuration that are not
 necessarily caused by any one program you might be running.

 Another issue is the type of OS/2 kernel being used. The different
 types of kernels are listed below:

 Retail Kernel
 -------------

 The Retail kernel is the kernel that is most likely in use out in the
 field by most application users, and it is also most likely the
 development kernel for most application developers. This kernel is
 somewhat faster and smaller than the debug kernel.

 Debug Kernel
 ------------

 The Debug kernel is used by device driver developers, OS/2 developers,
 and PM systems developers. Theoretically, it is functionally
 equivalent to the Retail kernel (it is a superset of the Retail
 kernel). This kernel has an additional built-in debugging interface,
 similar to SYMDEB or CodeView in line-sequential mode. It connects to
 a serial terminal and allows the user to "break" into the system and
 examine the registers, selectors, privilege levels, etc.

 The Debug kernel is a must for developing ring 0 code. This kernel is
 available through the purchase of the OS/2 Device Driver Development
 Kit (DDDK).

 Note: OS/2 knows very little about an application or device driver,
 except its register set and context. OS/2 cannot make guesses about
 what the application is doing or is attempting to do; it only knows
 what instruction to execute and the privileges associated with that
 particular instruction.

 INFORMATION CONTAINED IN TRAPS
 ------------------------------

 With this information in mind, let's return to what is displayed when
 a trap error occurs. The term "trap" is Intel nomenclature for an
 exception or error condition that is generated when executing an
 instruction on the chip. Depending on the sophistication of the
 operating system, this condition may be made known to the user.

 Under MS-DOS, these conditions normally result in a system hang,
 which is not considered user-friendly behavior. However, under OS/2,
 these conditions take two forms, each of which is associated with
 the first discussion on ring level traps.

 At ring 3, the protection layer where applications execute, a trap
 condition results in the operating system being notified (since the
 system executive runs at ring 0 and all applications are technically
 children of the executive) and the system then notifies the user. This
 notification is in the form of a VioPopUp generated by the harderr
 mechanism. The VioPopUp will contain the OS/2 session and/or process
 ID, and the register set context of the process at the time the
 exception occurred. Granted, this notification is usually accompanied
 by only one choice for the user, which is termination. However, in
 most cases, this choice is a better option than having the entire
 system hang.

 If a trap occurs at ring 0 in the kernel or a device driver, the
 problem is more serious. The information displayed is essentially the
 same as a ring 3 trap, but it is the result of a "panic write." This
 is a mechanism in the OS/2 kernel that is activated any time the
 kernel gets out of sync, and finally realizes that it is out of sync.
 At this point, the system traps and issues a message that means that
 it is stopping because it is too dangerous to go on, and that the
 system doesn't know how it got there. The message also tells you where
 the system is quitting, and the register set and context at the time
 it stops.

 Most of the information from this trap dump is a raw dump of the Intel
 80286 register set. Since OS/2 needs to run on 286 machines as well as
 386 platforms, it must restrict itself to 286 functionality for the
 most part. Chapter 9 ("Interrupts and Exceptions") in the "Intel 80286
 Software Reference" manual is the best reference for interpreting the
 286 register set.

 HOW TRAP INFORMATION IS USED
 ----------------------------

 Now that we have covered how OS/2 traps are generated and what
 information they contain, we can move on to how that information might
 be used.

 Ring 0 trap information is of no immediate use to an average user or
 application writer running the retail kernel. About all the user can
 do is report the trap information and the duplication scenario to the
 application developer and/or the OS/2 original equipment manufacturer
 (OEM).

 However, if you are using the debug kernel, you can (if you know how
 and choose to do it) break into the system and determine the
 instruction causing the problem and perhaps the context of how the
 trap occurs. This will not only help the person experiencing this
 problem to avoid it, but it will also provide extra information when
 other people report these types of problems.

 Ring 0 trap information helps device driver, PM, and OS/2 base
 developers improve their systems. With the ring 0 trap information and
 version number of the system being run, a system developer can use the
 map file and the debugging kernel to determine in which routine the
 system trapped, and sometimes why it trapped.

 Ring 3 traps under the retail kernel can be of limited use to the
 average user. However, although it is an inexact science, an
 application developer who uses CodeView can break into his application
 and figure out which segments map to the elements of his load image
 (programs often load into the same segments on different runs of the
 program). With the CS:IP values, the information listed above, and a
 map file, you can determine the routine that trapped out.

 If the application developer also happens to have a debugging kernel,
 the application developer then can more easily access the information
 regarding the state of the application at the time of the trap.

 As you can see, OS/2 trap messages are the most basic form of OS/2
 system error reporting. They are fundamentally related to the Intel
 286/386 chips and the error/exception handling these chips provide.
 The traps are not very fancy and provide minimal information toward
 understanding where an application might be failing.

 This information is worth considerably more to you if you are using
 the OS/2 debug kernel. If not, you must use other means or tools to
 help make use of this information such as by using CodeView, linker
 map files, and other debugging aids that may be available.

 The following information contains a list of things you might want
 to look for in the register dump, if you need to try to interpret
 a dump in the process of writing an application:

 1. Check the ring level. Bits 5 and 6 of the CSACC byte contain the
    DPL (descriptor privilege level), also known as the ring level.
    For more information on DPL, refer to Figure 6-7 of the "Intel
    80286 Programmer's Reference" manual. If the ring is 3, the
    trap most likely came from an application. If the ring is 0,
    the trap probably came from a device driver or the OS/2 kernel.

 2. Check to see if the LDT (local descriptor table) or GDT (global
    descriptor table) is being referenced.

 3. Check to see if the segment registers are nonzero, which they
    should be.

 4. Check to see if the SP is beyond the SS.

 5. Check to see if ES or DS contain an "*" (asterisk), which could
    means it's pointing to an invalid selector.

 6. Check the CS:IP value. Depending on the number of code segments
    and your ability to determine which code segment is in use, the
    IP will tell you what instruction is failing.

 Once again, Chapter 9 of the "Intel 80286 Programmer's Reference"
 manual describes the many 80286 traps and exceptions that could
 possibly cause a dump to occur.


 673. THREADS: Using DosSemSetWait() with RAM Semaphores

 There is a file in the Software/Data Library named THREADS that
 demonstrates the use of DosSemSetWait() in conjunction with RAM
 semaphores. THREADS demonstrates how to create, set, and clear a RAM
 semaphore.

 THREADS can be found in the Software/Data Library by searching on the
 keyword THREADS, the Q number of this article, or S12444. THREADS was
 archived using the PKware file-compression utility.


 674. CHKDSK On-Line Command Reference Documentation Error

 In the on-line command reference, under the CHKDSK entry it
 incorrectly suggests that to repair Drive C, you should boot with the
 install disk, press ESC to get a command prompt, and then type the
 following command:

    CHKDSK C: /F

 This command doesn't work because CHKDSK.COM is not on the install
 disk. The following command also doesn't work because you get the
 message that Drive C is in use by another process:

    C:\OS2\CHKDSK C: /F

 To repair Drive C, you should instead do the following:

 1. Boot with the install disk.

 2. Press the ESC key to get a command prompt.

 3. Enter the following command:

       COPY C:\OS2\CHKDSK.COM D:

 4. Run CHKDSK with the following command:

       D:CHKDSK C: /F

 This works properly because the install disk creates a small virtual
 Drive D.


 675. Using DevDone() to Reopen Device

 Question:

 I blocked a device by calling ProcBlock() in a strategy routine of a
 device driver. I then reopened it with the interrupt routine,
 DevDone(). Is this the correct way to use DevDone()? The parameter of
 DevDone() is the pointer to a request packet processed when
 ProcBlock() is called.

 Response:

 Yes, you can use DevDone() in this manner. However, it only works if
 you follow the convention of using the request packet's address as the
 block ID. DevDone() assumes that is what was used in the block call.

 DevDone() takes the request packet address and uses it to issue a run
 to restart the thread. It then uses the address to release the request
 packet.

 If you use any other type of convention to generate the block ID, you
 need to issue a run call yourself to restart the thread.


 676. OS/2 SDK: CREATEDD Memory Dump Format

 Question:

 We want to use the system dump facility [CTRL+ALT+NUM LOCK+NUM LOCK
 (press NUM LOCK twice)] and CREATEDD to help us debug device drivers
 we are developing. What is the format of the dump file
 (DUMPDATA.XXX)?

 Response:

 OS/2 currently has a command called CREATEDD that formats a disk for
 receiving a complete memory dump if you hold down CTRL+ALT and then
 press the NUM LOCK key twice. However, the output from CREATEDD is
 generally not useful to anyone but OS/2 system developers -- that is,
 the developers who are creating OS/2 itself. To make use of the output
 from CREATEDD, you need to know various internal data structures of
 OS/2, plus the specific software and hardware configuration of the
 machine used at the time of the memory dump. IBM does provide a
 service where under the direction of an IBM service representative,
 the dump can be sent to IBM for analysis. The tools that IBM uses to
 perform this analysis are the property of IBM, and Microsoft does not
 have access to whatever proprietary tools IBM may be using.

 At this time, Microsoft does not provide any kind of service or
 documentation (we don't even have any internal documentation) to
 assist the analysis of this memory dump. Microsoft does supply an
 OS/2 DDDK (Device Driver Development Kit), which contains a debugging
 kernel. The debugging kernel should give you the debugging
 information you need in an understandable format on the screen. If
 you do not already have the OS/2 DDDK, you can obtain the kit by
 contacting Microsoft Sales Support at (800) 227-4679 7 AM - 5 PM PST,
 or contact Microsoft International Customer Service at (206) 882-8661.


 677. Using C-Stream Function with DosMakePipe() Handle

 The following program demonstrates the use of C-stream I/O functions
 with read/write file handles returned by DosMakePipe():

 /* MKPIPE.C
  *
  * Description:
  *
  * This program demonstrates the usage of read/write file handles
  * returned by DosMakePipe() with C stream I/O functions, fputs()
  * and fgets().
  *
  * Compile and link instructions:
  *
  *    cl -c -Zi -Od - W3 mkpipe.c
  *    link /CO mkpipe,,,;
  *
  * Execution instructions:
  *
  *    mkpipe   (press the ENTER key)
  *
  *    MKPIPE prints "hello world" on the screen.
  *
  * This software is provided for demonstration purposes only.
  * Microsoft makes no warranty, either express or implied
  * as to its usability in any given situation.
  */

 #define  INCL_DOSQUEUES
 #define  INCL_DOSFILEMGR

 #include <os2.h>
 #include <stdio.h>
 #include <fcntl.h>
   main ()

     {

      int rc;

      HFILE hfRead;        /* pointer to variable for read handle  */
      HFILE hfWrite;       /* pointer to variable for write handle */
      USHORT cbPipe = 512; /* number of bytes reserved for pipe    */
      CHAR  chzBuf[20], *prc;
      FILE  *fRead, *fWrite ;
      USHORT cbRead;
      static CHAR  Message[] = "Hello World\n";

      rc = DosMakePipe(&hfRead, &hfWrite, cbPipe);

      if (rc){
             printf("Error DosMakePipe %i\n", rc);
             return rc; }
      else {                                       /* get a FILE pointer */
             fWrite = fdopen( (int) hfWrite, "w");
             if (fWrite == NULL)
                 {
                  printf("Error fdopen fWrite\n");
                  return -1; }

             rc = fputs(Message,fWrite);          /* write to pipe */
             if (rc ) {
                  printf("Error fwrite %i\n", rc);
                  return rc; }
                                                 /* flush: VERY IMPORTANT */
             rc = fflush(fWrite);
             if (rc ) {
                  printf("Error fflush %i\n", rc);
                  return rc; }

             fRead = fdopen( (int) hfRead, "r"); /* get a FILE pointer */
             if (fRead == NULL)
                 {
                  printf("Error fdopen fRead\n");
                  return -1; }
                                                        /* read the pipe */
             prc = fgets(chzBuf, sizeof(chzBuf), fRead);
             if (prc==NULL) {
                  printf("Error fgets %i\n", rc);
                  return rc; }
             printf("%s\n", chzBuf);
      }
                             /* close the read handle of pipe*/
      rc =  DosClose(hfRead);

                             /* close the write handle of pipe*/
      rc =  DosClose(hfWrite);
  }


 678. Using Multithreaded DLL with a Device Driver

 Question:

 I am trying to design a group of interrelated applications and DLLs
 (dynamic linked libraries). The following components are involved:

 1. A character-based device driver interacting with a memory board
    (real time)

 2. A DLL buffering request to and from a device driver

 3. Several applications interacting with the DLL

 I have the following questions regarding the designing of the
 interaction between these components:

 1. Is there any way for the device driver to call the DLL? I would
    like to have an in and out queue in the DLL. Incoming information
    has to be queued in as little time as possible, and I am worried
    that setting a semaphore and waiting for the DLL to unblock and
    ask for the data would be too slow.

 2. How can I design a hybrid of an application and a DLL? I need a
    single executable that can have two active threads at all times
    (one waiting for information from the device driver and one
    waiting for application requests to be passed to the device
    driver). In addition, the executable must export about ten
    functions to be called by the applications. In other words, is it
    possible for a DLL to always be active (perhaps started with RUN=
    in CONFIG.SYS), contain active threads, and still be called by
    other applications?

 3. How can I ensure that the data segment of a DLL is never discarded
    after it has been initialized? After using DosOpen() to get access
    to the device driver, the DLL must stay in memory. If the DLL is
    discarded, I need to at least issue a DosClose() call to stop the
    device driver from buffering data coming from the board.

 Response:

 The answers to the above questions are as follows:

 1. No, the device driver can't call the DLL. You can use a
    multithreaded DLL to handle requests to the device driver. One
    thread in the DLL will be used just for this purpose. The device
    driver can block this thread until the request is complete.

 2. The RUN command can be used only with a process. However, that
    process can call a routine or routines in a DLL. You could also
    start this process with the DETACH command. All application
    programs are run at ring 3. This means that they are swappable (not
    the same as discardable). There isn't a method to make them
    unswappable. For this reason, we suggest a different approach to
    your problem, explained in the answer to Question 3 listed below.

 3. You need to use a slightly different approach. You should allocate
    and lock the memory you need in the device driver. This way the
    memory will not be swapped out or discarded.


 679. Limiting Access to Global Variables

 Question:

 Our existing product runs under MS-DOS and makes heavy use of global
 variables. We want to start multiple instances of this program under
 OS/2, and we want to use threads instead of processes to do this.
 Since global variables can be seen by any thread, using threads to
 start multiple instances of the program (as written currently) will
 not work (all threads would be accessing the same global variables).
 Local variables can't be used to pass data between functions.

 Is there a way to get a new set of variables for each thread
 (variables that could be seen by any functions called within the
 thread but not by functions in another thread) using C and OS/2?

 Response:

 One way to do this is to start with the segregation of your global
 data into the following types of data:

 1. Read-only data

 2. Read/write data

 For read-only data, each thread can go ahead and read the global data
 without any problem. For read/write data, you need to create a large
 global area. You then can use semaphores to protect/serialize the
 access of this data. You can use DosSemSet() and DosSemClear()
 semaphore API calls to serialize the access.

 There are also the DosEnterCritSec() and DosExitCritSec() API calls
 that can be used so that you can encapsulate the piece of code that
 manipulates global data. Thus, instead of every thread changing a set
 of global variables, you can have one routine that has a critical
 section, and it will be the only routine that can change this data.
 However, for efficiency, you should keep this piece of code to a
 minimum. Also, threads should be run at the highest priority in the
 critical section of the code so that you don't starve other threads of
 CPU time.

 Another possible solution is to have a global data manager that
 resumes/suspends threads when they need to access global data by using
 the DosResumeThread() and DosSuspendThread() function calls.

 Also, you can explicitly name allocated memory segments as
 \SHAREMEM\NAME, or use DosAllocSeg() for shareable segments. You then
 can pass the selector of the global segments to only those threads
 that need to see this information. This way, one thread can see part
 of the global data and another thread can see another part (or none)
 of the global segment.

 You can use any or all of these ideas. You can also dynamically
 allocate a copy of the "global" data segment to each thread and
 implement your own "write-through" for each thread's personal copy of
 the "global" data area.

 We recommend that you use semaphores to serialize data access, since
 it is the simplest way to accomplish this functionality. Further
 information on this topic can be found in "Advanced OS/2 Programming"
 by Ray Duncan.


 680. LABEL.COM Ignores Parameter Passed by DosExecPgm()

 Question:

 If I call the LABEL.COM utility with the DosExecPgm() function, it
 seems to ignore the drive letter argument (with or without a colon).
 LABEL.COM always reports just the current drive, yet CMD.EXE seems to
 have no problem invoking it. LABEL.COM is the only text application
 I've had any problem executing with arguments. You can work around
 this problem by invoking CMD.EXE with a "/C LABEL A:" style argument
 instead.

 Response:

 The OS/2 LABEL.COM command seems to require that its command line
 argument be padded in the following format

    <ProgramName><Null><Space><arg1><Null><Null>

 for example

    LABEL.COM\0 B:\0\0

 instead of the following (more commonly used) format

    <ProgramName><Null><arg1><Null><Null>

 for example

    LABEL.COM\0B:\0\0

 In both of the above examples, the argument option to DosExecPgm() is
 set up to execute LABEL.COM with the option "B:", such as in the
 following example:

    LABEL.COM B:

 However, only the version with the command line built with the space
 preceding the first command-line argument (after the null that follows
 the program name) works with LABEL.COM.

 Microsoft has confirmed that the command-line parsing in LABEL.COM in
 Version 1.10 is incorrect. We are researching this problem and will
 post new information here as it becomes available.

 Sample Programs
 ---------------

 Listed below are two sample C programs named FOO.C and BAR.C. FOO.EXE
 uses DosExecPgm() to execute BAR.EXE, and BAR simply displays its
 command line. FOO uses both methods listed above to show the
 difference the space character makes.

 To test FOO with LABEL.COM, either modify FOO.C to call LABEL.COM
 instead of FOO.EXE, or copy LABEL.COM to FOO.EXE. When you use the
 child program of BAR.EXE, both command lines work properly. When you
 use the child program of LABEL.COM, LABEL works properly only with a
 space preceding what C programmers call argv[1], the first
 command-line option.

 With the method that has NO space in this location, LABEL.COM
 incorrectly parses the command line and does not find the first
 command-line argument, thus defaulting to the current drive. For this
 reason, we recommend using the command-line building method with the
 space, for compatibility with LABEL.COM.

 /* -------------------------------------------------------------- */

 /* FOO.C -- Calls BAR.EXE with various arguments */

 #include <stdio.h>
 #include <stdlib.h>
 #define INCL_DOSPROCESS
 #include <os2.h>

 int main(int argc, char *argv[]);

 int main(int argc, char *argv[])
 {

     USHORT usError;
     char szszBuf[128];
     RESULTCODES rescResults;

     printf("Test 1: <ProgramName><Null><arg1><Null><Null>\n");
     usError = DosExecPgm(szszBuf, sizeof(szszBuf), EXEC_SYNC,
         "bar.exe\0b:\0\0", 0, &rescResults, "bar.exe\0\0");
     if (usError)
         printf("Error %u in DosExecPgm()!\n", usError);

     printf("Test 2: <ProgramName><Null><Space><arg1><Null><Null>\n");
     usError = DosExecPgm(szszBuf, sizeof(szszBuf), EXEC_SYNC,
         "bar.exe\0 b:\0\0", 0, &rescResults, "bar.exe\0\0");
     if (usError)
         printf("Error %u in DosExecPgm()!\n", usError);

     exit(0);

 } /* main */

 /* -------------------------------------------------------------- */

 /* BAR.C -- Displays its arguments as invoked by FOO.EXE */

 #include <stdio.h>
 #include <stdlib.h>

 void main(int argc, char *argv[]);

 void main(int argc, char *argv[])
 {

     printf("%s: %s (argc = %d)\n", argv[0], argv[1], argc);
     exit(0);

 }
 /* -------------------------------------------------------------- */


 681. KEYB Doesn't Work As a Windowed Application

 KEYB does not work as a windowed application.

 To reproduce this problem, enter a window and type "KEYB". The screen
 clears and then returns to the window.

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem to see if KEYB was originally designed to
 only work as a full screen application, because of problems that may
 occur at the windowed prompt. We will post new information here as it
 becomes available.


 682. Input Parameters to VioSetCurType() Not Treated Correctly

 VioSetCurType() does not treat the input parameters as unsigned
 integers, as described on Page 240 in the "Microsoft Operating
 System/2 Programmer's Reference Volume 3" for Version 1.10. If you
 give VioSetCurType() the following parameters, a 421 error should
 occur, but it does not:

    VioHandle(0)
    startline(256)
    endline(0)
    cursorwidth(0)
    attrib(0)

 Instead, VioSetCurType() is valid and treats the startline(256) as
 zero, which infers that the unsigned integer is being treated like a
 byte and not a 2-byte unsigned integer value as specified. This also
 applies to endline. This same problem also occurs with the
 VioGetCurType() function.

 Microsoft has confirmed this to be a problem in Version 1.10. This
 problem has been corrected in Version 1.20.


 683. Using DosError() to Trap Hard Errors

 Question:

 How do you check if a floppy disk is available without getting the
 black screen (abort, retry, ignore) message? Also, is there a way to
 trap these type of errors from a program?

 Response:

 You can trap all hard errors by calling DosError(). However, if you do
 trap the errors you need to check for them after every call. It is
 easier to intercept them when you think you may be getting one of
 these errors (e.g. when you are going to the floppy disk); otherwise,
 let the system handle them. See the sample code listed below for more
 information. Please note that this same mechanism works for all hard
 errors.

 The following example calls the DosError() function to turn off
 hard-error processing, calls the DosErrClass() function to process any
 error that is received, and then turns hard-error processing back on:

 USHORT usAttribute, usError, usClass, fsAction, usLocus;
 DosError(HARDERROR_DISABLE);     /* turn off hard-error processing */
 usError = DosQFileMode("a:\\abc.ext", &usAttribute, 0L);
 if (usError) {
     DosErrClass(usError, &usClass, &fsAction, &usLocus);
     if (usClass == ERRCLASS_HRDFAIL)
         DosExit(EXIT_PROCESS, 1);
 DosError(HARDERROR_ENABLE);        /* turn on hard-error processing */


 684. INT21H Fails with Certain CODEPAGE and COUNTRY Settings

 The problem listed below occurs when the following settings are used
 in CONFIG.SYS:

    CODEPAGE = 437,850
    COUNTRY  = 001,C\OS2\SYSEM\COUNTRY.SYS

 The program included below does not control and stop within the "INT
 21H" routine when it is executed by SYMDEB in the DOS compatibility
 box:

    MOV  AX,6501H
    MOV  BX,1B5H
    MOV  DX,2CH        ; (Specify a country number except US)
    MOV  CX,2AH
    MOV  DI,200H
    INT  21H
    INT  3H

 Microsoft has confirmed this to be a problem in Version 1.10. This
 problem has been corrected in Version 1.20.


 685. Identifying Missing DLLs

 Question:

 If a dynamic linked library (DLL) that is required by a program is not
 found when the program is started, OS/2 gives one of two or three
 error messages, none of which identifies the missing DLL. Is there a
 way to force OS/2 to consistently identify which DLL is missing?

 Response:

 It depends on the type of DLL that is missing and the type of program
 calling the DLL. If one of the base DLLs from C:\OS2\DLL is missing,
 you may get an error at boot time and sometimes the system will hang,
 depending on the DLL.

 An error message usually is generated for less critical DLLs.

 For all DLLs requested by an application program or OS/2 utility, it
 is up to the application to generate the appropriate error message.
 You can use DosLoadModule() to specifically load a DLL. If the DLL is
 in a directory defined in the LIBPATH= statement in CONFIG.SYS,
 DosLoadModule() will load the DLL. You can also use DosGetModHandle()
 to determine if the DLL is currently loaded. If it isn't loaded, you
 can load it at run time by using DosLoadModule().

 Another way to identify the name of a missing DLL is to detach the
 program that won't load. You will be informed of exactly which DLL was
 not found.

 The .EXE file doesn't have to be able to run detached, because it
 never actually gets to start executing. For example, if you try to run
 CUE.EXE without its DLL, CUESUBS.DLL, you get the following message:

    C:\> CUE

    SYS1804: The system cannot find the file.

 If you try and detach CUE, you get the following message:

    C:\> DETACH CUE

    SYS1804: The system cannot find the file CUESUBS.


 686. Refresh Command Returns Error If Floppy Disk Is Changed

 Microsoft has confirmed that the following problem occurs in OS/2
 Version 1.10 and Version 1.20 with the Refresh command in the File
 System menu. The following steps can be used to reproduce this
 problem:

 1. Open the File System.

 2. Insert a disk into the floppy disk drive.

 3. Change the drive to use a floppy drive.

 4. Open some directory windows.

 5. Remove the floppy disk and insert another floppy disk that does not
    have the same pathnames as those of the first floppy disk.

 6. Choose Refresh from the Window menu.

 A [PMV1010] error message is displayed. The error message refers to a
 number of opened files, which are actually the directory windows. The
 number will be one less than that of the opened directory windows.

 We are researching this problem and will post new information here as
 it becomes available.


 687. DosSetMaxFH() Returns Error If File Handles Are 32768

 If you use DosSetMaxFH() and set the number of file handles to 32,768,
 an error is returned if you then issue a DosOpen() call.

 Microsoft has confirmed this to be a problem in OS/2 Version 1.10.
 This problem was corrected in Version 1.20.


 688. TRSEL.EXE Information

 Question:

 TRSEL.EXE is a dynamic trace selector program. It is used internally
 by the system and is not meant to be run by a user. It basically uses
 the same type of filenames as the trace command, and follows the same
 rules.


 689. Refresh Doesn't Work Properly If Floppy Disk Is Changed

 The problem listed below occurs when using the Refresh command on the
 File System menu. The following steps can be used to reproduce this
 problem:

 1. Open the File System menu.

 2. Change the Drive selection to use a floppy disk.

 3. Insert a floppy disk containing some subdirectories into the floppy
    disk drive.

 4. Open some directory windows.

 5. Remove the floppy disk and insert another floppy disk that does not
    have the same subdirectories as the first floppy disk.

 6. Choose Refresh from the Window menu.

 At this time, a [PMV1010] error message should be displayed in
 proportion to the number of opened files (that is, directory windows)
 because the floppy disk was changed to a different disk before the
 Refresh command took place. However, the number of [PMV1010] error
 messages displayed is less than that of the opened directory windows.

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem and will post new information here as it
 becomes available.


 690. German Keyboard Support Doesn't Work with ANSI.SYS

 If ANSI.SYS for the DOS 3.x box is loaded, the German-keyboard support
 in the 3.x box is not available. If you execute the following command

    CHCP 850 (or 437)

 the German-keyboard support is available.

 The CONFIG.SYS entries are as follows:

    COUNTRY=049,C:\OS2\SYSTEM\COUNTRY.SYS
    DEVINFO=KBD,GR,C:\OS2\KEYBOARD.DCP
    DEVICE=C:\OS2\ANSI.SYS
    CODEPAGE=850,437

 Microsoft has confirmed this to be a problem with the ANSI.SYS file
 included with Version 1.20. We are researching this problem and will
 post new information here as it becomes available.

 The only workaround is to put a "CHCP 850" (or 437) command in the
 AUTOEXEC.BAT file.


 691. Scheduler Doesn't Preempt Execution of DD at Task Time

 Question:

 Will the OS/2 system scheduler ever preempt execution of task time
 code in an installable device driver? In other words, will more than
 one process ever be allowed to enter the task time section of a device
 driver at any one time?

 Response:

 The scheduler will not preempt the execution of a device driver at
 task time. If you disable interrupts, you could run forever. If you
 want to allow other threads to run, you can use the DevHelp() function
 YIELD or TCYIELD.


 692. .TYPE Extended Attribute Information

 Question:

 The documentation describes the .TYPE EA (Extended Attribute) as
 "similar to the earlier use of filename extensions" on Page 25 of the
 "Microsoft Operating System/2 Programmer's Reference Volume 4" for
 Version 1.20. Does this literally mean that OS/2 will be moving away
 from using file extensions of .EXE, .CMD, etc., for recognizing
 executable files? Also, we didn't find any .EXE files with a .TYPE EA
 in the files included with Version 1.20. Is there a reason for this?

 Response:

 We are moving toward using the .TYPE fields rather than file
 extensions. This transition will take quite a while since most or all
 current applications aren't yet aware of the .TYPE field or EAs in
 general. As you noticed, the .EXE files shipped with Version 1.20
 don't contain .TYPE EAs. This is an example of the fact that it will
 take a while for more applications to become EA aware.

 In the case of our .EXE files, the linker would need to be EA aware to
 write the .TYPE field of the .EXE file when it created the file. Since
 the linker isn't aware of EAs yet, it didn't add those EAs.


 693. DosFindFirst() Returns Incorrect Results on HPFS

 Problem:

 We are using DosFindFirst() to scan for files that we can open. We are
 seeing a different type of behavior, depending upon the file system
 type. In a search for normal files (attributes == 0), using the search
 specification of ".", we get the following results:

    Current Directory   FAT File System  HPFS File System
    -----------------   ---------------  ----------------
    \pm3                no_more_files    no_more_files
    \                   no_more_files    success

 Because DosFindFirst() returns success on an HPFS root directory, we
 end up doing the scan twice.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.

 As a possible workaround, you could choose a different filename
 specification for your search.


 694. Calculating HEAPSIZE and STACKSIZE

 Question:

 How do I calculate the HEAPSIZE and STACKSIZE needed for a given
 .DEF file? So far, I have just guessed and used 4096 byte jumps.

 Response:

 Actually, guessing is a reasonable approach. The HEAPSIZE is not
 critical, since it is dynamically expanded, as necessary, by the
 system at run time. An application's stack requirements depend on
 which OS/2 services it uses. A good estimate for the stack size is
 double the internal "application" stack requirements.

 A careful examination of the .MAP file generated by LINK will help you
 to get a finer perspective on your stack requirements. For more
 information on .MAP files, please consult your documentation for the
 Microsoft Macro Assembler and the Microsoft C Compiler. In addition,
 there is an article in the Knowledge Base on this topic. Please query
 on the following words:

    dgroup and origin and map and 20 and text and description

 Finally, listed below is some general information relating to
 HEAPSIZE and STACKSIZE:

 1. The local heap is located in DGROUP along with the near data and
    default stack. Memory can be allocated from the heap with
    malloc(), related Microsoft C Compiler run-time functions, and
    some Presentation Manager (PM) functions that let you allocate
    memory from the heap.

    Regardless of the heap's initial size, it is expanded at run time
    whenever necessary until DGROUP has reached its maximum size of
    65,536 bytes. If HEAPSIZE is absent, the default initial heap size
    is 0 bytes.

 2. STACKSIZE defines the size of the application's default stack
    (that is, the stack that is used by the application's primary
    thread when it is first entered from OS/2).

    The recommended general size is 2K for base API OS/2 applications
    and 8K for PM applications that create a window. Increase this as
    necessary.

    If the STACKSIZE directive is present, it overrides any stack
    segment declared in the application source code, or with the linker
    /STACK switch.


 695. PRINT /C Command Doesn't Cancel Printing in OS/2 SDK 1.10

 Printing cannot be canceled with the PRINT /C command after some files
 are queued up to be printed with the PRINT command at the OS/2
 full-screen command prompt. The following steps can be used to
 reproduce this problem:

 1. Queue up some files to be printed with the PRINT command at the
    OS/2 full-screen command prompt.

 2. Enter a PRINT /C command to cancel the printing of the files.

 3. Open the Print Queue Manager. The files that are waiting to be
    printed are all printed, with "printing" displayed next to them.

 Microsoft has confirmed this to be a problem in Version 1.10. We are
 researching this problem and will post new information here as it
 becomes available.


 696. OS/2 Physical Interrupt Utilization

 Question:

 I am building some hardware to run under OS/2 and would like to know
 which physical interrupts I can use. Also, which interrupts does OS/2
 use?

 Response:

 The following is a list of the interrupts OS/2 uses:

    IRQ 0 is the 8254 timer
    IRQ 1 is the keyboard
    IRQ 2 is used to connect to the second PIC
    IRQ 8 is the MC146818 RTC
    IRQ 13 is the 80287

 The following interrupts are not set by OS/2 but by the device drivers
 when they are loaded:

    IRQ3  - COM2
    IRQ4  - COM1
    IRQ5  - LPT2
    IRQ6  - Floppy
    IRQ7  - LPT1
    IRQ9  - EGA may use this, but not all EGAs do.
    IRQ14 - Hard disk

 If a mouse is installed, it will generally use IRQ3 or IRQ5. Thus, the
 following interrupts are generally available:

    IRQ10, IRQ11, IRQ12, and IRQ15


 697. Death of Thread 1 and Continuation of Other Threads

 Question:

 In OS/2 Version 1.00, if thread 1 exits with the following statement

    DosExit(EXIT_THREAD,0)

 and there are still some other threads alive, the process remains
 active until the last thread dies. When I run this same statement with
 OS/2 Version 1.10, I find that if thread 1 exits in this manner, the
 process terminates. Was the DosExit() function changed in OS/2 Version
 1.10?

 Response:

 Yes, there was a change to OS/2 Version 1.10. When thread 1 exits, the
 process should terminate: that is, all threads in that process are
 terminated. This was incorrect behavior in OS/2 Versions 1.0x;
 however, it was corrected in OS/2 Version 1.10. See Chapters 5 and 12
 of Gordon Letwin's "Inside OS/2" book for a discussion on this topic.
 Thread 1 is the thread that receives signals from the operating
 system. If thread 1 (the thread that receives the signals from the
 outside world) is killed, there should be no way for the application
 to receive signals.


 698. Message Mode Pipe Versus Byte Mode Pipe Operation

 Question:

 What is the difference in operations of reading and writing to message
 mode pipes, as opposed to byte mode pipes?

 Response:

 Message mode pipes have a header attached to each message as opposed
 to a byte mode pipe, which is just a byte stream. When a DosRead()
 call is done on a message pipe, and the message is larger than the
 (read) buffer, you get part of the message in the (read) buffer, and
 an error code of ERROR_MORE_DATA. When using message pipes, you can do
 a DosPeekNmPipe() call to determine the size of the remaining data,
 and then do a DosRead() call on the second part of the message. In
 byte mode, this type of error code (ERROR_MORE_DATA) is not returned.

 In byte mode, a unit of information is a byte, whereas in message mode
 the unit of information is a message, no matter what size the message
 may be. The best way to test the difference is to write/read messages
 that are larger than the (read) buffer as explained above.

 More specifically, a byte mode pipe behaves like an anonymous pipe,
 where all data that is written is transferred without any special
 processing performed on it. In message mode, a named pipe can
 distinguish between different messages and the size of each message.


 699. DosWrite() Write Behind Bit Information

 Question:

 What does the write behind bit do when set?

 Response:

 The write behind bit applies to DosWrite(). If this bit is set,
 DosWrite() returns before the buffer has been written to the remote
 device. A corresponding parameter is bit 2 in server heuristic, in
 LANMAN.INI of the server. If this bit is set, it tells the client that
 a write is complete before actually performing the write. If the write
 generates an error, the error code is returned in the subsequent
 write.


 700. Debugging Process Under CVP with DosPTrace()

 Listed below is an example of the DosPTrace() function. The following
 code will allow you to single step through a process that is indicated
 by argv[1] on the command line:

 #define INCL_BASE
 #define INCL_DOSTRACE
 #include <os2.h>
 #include <stdio.h>

 /***** Definitions *****/

 /* Ptrace command numbers */

 #define TRC_C_Null         0   // Null
 #define TRC_C_ReadMem      1   // Read Word
 #define TRC_C_ReadMem_I    1   // Read Word (instruction)
 #define TRC_C_ReadMem_D    2   // Read Word (data)
 #define TRC_C_ReadReg      3   // Read Registers
 #define TRC_C_WriteMem     4   // Write Word
 #define TRC_C_WriteMem_I   4   // Write Word (instruction)
 #define TRC_C_WriteMem_D   5   // Write Word (data)
 #define TRC_C_WriteReg     6   // Write Registers
 #define TRC_C_Go           7   // Go
 #define TRC_C_Term         8   // Terminate
 #define TRC_C_SStep        9   // Single Step
 #define TRC_C_Stop         10  // Stop
 #define TRC_C_Freeze       11  // Freeze Thread
 #define TRC_C_Resume       12  // Resume Thread
 #define TRC_C_NumtoSel     13  // Segment Number to Selector
 #define TRC_C_GetFPRegs    14  // Get 80287 Registers
 #define TRC_C_SetFPRegs    15  // Set 80287 Registers
 #define TRC_C_GetLibName   16  // Get Library Name
 #define TRC_C_ThrdStat     17  // Thread Status
 #define TRC_C_MapROAlias   18  // Map Read-Only Memory Alias
 #define TRC_C_MapRWAlias   19  // Map Read-Write Memory Alias
 #define TRC_C_UnMapAlias   20  // UnMap Memory Alias

 /* Notification Numbers */

 #define TRC_C_SUC_ret           0   // Success
 #define TRC_C_ERR_ret          -1   // Error
 #define TRC_C_SIG_ret          -2   // Signal
 #define TRC_C_TBT_ret          -3   // Single-Step
 #define TRC_C_BPT_ret          -4   // Breakpoint
 #define TRC_C_NMI_ret          -5   // NMI (NOT USED)
 #define TRC_C_KIL_ret          -6   // Process Termination
 #define TRC_C_GPF_ret          -7   // GP Fault
 #define TRC_C_LIB_ret          -8   // DLL Library Attachment
 #define TRC_C_FPE_ret          -9   // Floating Point Error
 #define TRC_C_THD_ret          -10  // Thread Termination
 #define TRC_C_STP_ret          -11  // Asynchronous Stop
 #define TRC_C_NEW_ret          -12  // New Process
 #define TRC_C_AFR_ret          -13  // Alias Free

 /* Error numbers with TRC_C_ERR_ret */

 #define trace_bad_command       1   // command failed
 #define trace_child_not_found   2   // process not found
 #define trace_child_untraceable 5   // cannot debug this process

 /***** Function Prototypes *****/

 int main(int argc, char *argv[]);

 int main(int argc, char *argv[])
 {

     CHAR  pchFailBuf[128];
     RESULTCODES result;
     PTRACEBUF  ptrbuf;

     printf("Result of execing %s is %u\n",
          argv[1],
          DosExecPgm(pchFailBuf,128,EXEC_ASYNC | EXEC_TRACE,
                  0,0,&result,argv[1]));

     /* Debug the direct child until notified of child executed */

     printf("Debugging %s...\n",argv[1]);

     ptrbuf.pid = result.codeTerminate;
     ptrbuf.cmd = TRC_C_SStep;

     while(1)
     {
      DosPTrace((PVOID)&ptrbuf);
      printf("Result of trace = %d\n",ptrbuf.value);
     }

     return(0);
     argc;
 }


 701. Creating Session That Is Invisible to Task Manager

 Question:

 Is it possible to create a session using DosStartSession() that does
 not appear as a selectable/destroyable item in the Task Manager shell?

 Response:

 After creating a session with DosStartSession(), you can use the
 DosSetSession() API to accomplish what you are trying to do. The
 DosSetSession() function allows a parent session to use the
 "SelectInd" and "BondInd" fields of the STATUSDATA structure to
 specify whether the child session can be selected by the user, and
 whether or not the child session will be brought to the foreground
 when the user selects the parent session.


 702. OS/2 and LAN Manager Installation Problem Causes Hang

 Problem:

 When I modify my CONFIG.SYS file to work with OS/2 LAN Manager
 Version 2.00, the system hangs after painting the screen and the
 mouse pointer, but before the MS-DOS icon is painted on the screen.
 The mouse moves, but none of the keystrokes appear to work.

 Response:

 This problem is due to a basic antagonism between the OS/2 LAN Manager
 spooler and the PM spooler. If you wish to run OS/2 LAN Manager and
 the OS/2 LAN Manager spooler, you must copy \LANMAN\NETLIB\PMPRINT.QPR
 to \OS2\DLL and place the \LANMAN\NETLIB at the beginning of the
 LIBPATH statement, which is set in your CONFIG.SYS file. You must also
 delete the \SPOOL subdirectory.

 To go back to the PM spooler, delete the \SPOOL subdirectory, remove
 \LANMAN\NETLIB from the LIBPATH statement, or at least move it to the
 end of the path, and copy the PM spooler back into the \OS2\DLL
 subdirectory.


 703. Internal Consistency Error Occurs When Starting Spooler

 Question:

 I receive an "internal consistency error" when I start the spooler.
 What causes this error to occur?

 Response:

 The C:\LANMAN\NETLIB subdirectory must be listed as the first
 subdirectory in the LIBPATH= statement in your CONFIG.SYS file. If
 \OS2\DLL is listed as the first subdirectory in your LIBPATH=
 statement, then the OS/2 LAN Manager will get some Hursley spooler
 components and will refuse to work properly.


 704. DosExecPgm() "fExecFlags" Documentation Error

 Question:

 I am having a problem in which I am not getting notified when my child
 spawns a process while using DosPtrace().

 The documentation for DosExecPgm() states that a value of EXEC_TRACE
 (3) in the "fExecFlags" parameter causes a child to be traced. This is
 true, but it only applies to the direct child. If the direct child
 spawns children, the PTRACE'er is not notified. I have found by
 experimenting that using a value of 6 for "fExecFlags" causes other
 child to be traced and notification of all spawns to be sent to the
 PTRACE'er. This is not documented in either QuickHelp or in the
 Microsoft OS/2 programmer's reference manuals, but it seems to work.

 Is this the correct value to use to trace spawned children and be
 notified of all spawns?

 Response:

 Yes, this value for the "fExecFlags" works as stated above. Microsoft
 has confirmed that this information was inadvertently left out of the
 "Microsoft Operating System/2 Programmer's Reference Volume 3" for
 Version 1.10 on Page 45, and in QuickHelp. We will post new
 information here once the documentation is updated to correct this
 error.


 705. OS/2 SDK: DosDevIOCtl() and Track Layout Table

 Question:

 I am building an application that collects data from an interface and
 stores the data on a floppy disk. I would like to maximize the
 transfer rate to the floppy disk. A file system is not required. I
 want to use the DosDevIOCtl() function to read/write data to the
 floppy disk. The track layout table is confusing to me, and I cannot
 figure out how to use it. The questions I have are as follows:

 1. What is meant by "usFirstSector"?

 2. How do you know what track you are using when a read or write is
    issued?

 3. Which tracks correspond to which logical head?

 4. Can you format a floppy disk using DosDevIOCtl() commands?

 5. To use DosDevIOCtl(), must I "open" a file to get a handle?

 6. What is Microsoft's recommendation on how to maximize disk
    performance?

 Response:

 The answers to the above questions are as follows:

 1. "usFirstSector" is the index into the track table that you wish
    to start the readtrack from. This is a value of 0-n, where n
    represents the number of sectors per track, minus 1.

 2. You specify the track with the cylinder/head combination.

 3. Track 0 starts at cylinder 0, head 0. Track 1 at cylinder 0, head
    1, etc.

 4. Yes, you can. Included below is some sample code that shows the
    basic methods of how to perform this functionality.

 5. Yes, you must open the device (such as "a:").

 6. The fastest method to write to a disk is with the IOCtls, so you
    are already using the preferred method. We suggest that you buffer
    the reads and writes, and deal with track size reads and writes to
    make sure you write as much as you can every time.

 Format Code
 -----------

 Compile with /Zp /W3 /Lp

 #define INCL_BASE
 #define INCL_DOSDEVIOCTL
 #include <os2.h>

 #include <stdio.h>

 #define  FORMAT_TABLE_SIZE  0x0004

 int main(int argc, char *argv[]);

 int main(int argc, char *argv[])
 {
     /* Variables for DosOpen */

     HFILE      hfile;
     USHORT     usAction;
     ULONG      ulFileSize  = 0L;
     USHORT     usAttrs     = FILE_NORMAL;
     USHORT     usOpenFlags = FILE_OPEN;
     USHORT     usOpenMode  = OPEN_SHARE_DENYNONE | OPEN_FLAGS_DASD;
     ULONG      ulReserved  = 0L;

     /* Variables for DosDevIOCtl() */

     USHO\023\021RT          usCommand   = 0;

     TRACKFORMAT FAR    *tf;
     BIOSPARAMETERBLOCK   bpb;
     USHORT          getcommand  = 0x0000;
     USHORT          setcommand  = REPLACE_BPB_FOR_MEDIUM;

     /* Variable for DosAllocSeg */
     SEL        sel;

     /* Variables for looping through the tracks on the disk */

     BYTE       bIndex;
     USHORT     usTotalCylinders;

     USHORT     usRetCode;

     /* Open the disk specified in argv[1], get the device parameters
        for the drive, and set the parameters for the medium to those
        of the drive. */

     usRetCode = DosOpen(argv[1],&hfile,&usAction,ulFileSize,usAttrs,
                usOpenFlags,usOpenMode,ulReserved);

     if(usRetCode == 0)
      usRetCode = DosDevIOCtl(&bpb,&getcommand,DSK_GETDEVICEPARAMS,
                     0x0008,hfile);

     if(usRetCode == 0)
      usRetCode = DosDevIOCtl(&bpb,&setcommand,DSK_SETDEVICEPARAMS,
                     0x0008,hfile);

     /* Allocate memory to hold the TRACKFORMAT structure */

     if(usRetCode == 0)
      usRetCode = DosAllocSeg(sizeof(TRACKFORMAT) +
                     (FORMAT_TABLE_SIZE * bpb.usSectorsPerTrack),
                     &sel, SEG_NONSHARED);

     if(usRetCode == 0)
     {

      tf = (TRACKFORMAT FAR *) MAKEP(sel,0);

      tf->bCommand   = 0x0001;
      tf->usReserved = 0;
      tf->cSectors   = bpb.usSectorsPerTrack;

      usTotalCylinders = (bpb.cSectors / bpb.usSectorsPerTrack)
                         / bpb.cHeads;

      for(bIndex = 0; bIndex < (BYTE) bpb.usSectorsPerTrack; bIndex++)
      {
         tf->FormatTable[bIndex].idSector = bIndex + 1;
         tf->FormatTable[bIndex].bBytesSector = 2;
      }

      for(tf->usCylinder = 0; tf->usCylinder < usTotalCylinders;
          tf->usCylinder++)
      {
          tf->FormatTable[bIndex].bCylinder = (BYTE) tf->usCylinder;

          for(tf->usHead = 0; tf->usHead < bpb.cHeads; tf->usHead++)
          {
           tf->FormatTable[bIndex].bHead      = (BYTE) tf->usHead;
           usRetCode = DosDevIOCtl(&usCommand,(PBYTE)tf,
                          DSK_FORMATVERIFY,0x0008,hfile);
           printf("Cylinder %03u, Head %u formatted\r",tf->usCylinder,
                tf->usHead);
          }
      }
     }

     if(usRetCode != 0)
      printf("An error occurred while formatting the disk.");

     return(usRetCode);

     /* The following variable does not get accessed and is here to
        avoid a /W3 compiler warning message. */

     argc;
  }


 706. SET Returns Error Incorrectly at Full Screen Prompt

 When OS/2 executes the SET command from the command prompt, the
 results are not consistent with the results arising when OS/2 executes
 the SET command during processing of the CONFIG.SYS file at boot time.

 If you use the following command at the OS/2 full screen or screen
 command prompt, a "SYS1003: The syntax of the command is incorrect"
 error message is returned:

    SET a=b=c=d

 However, if you insert the same SET statement into your CONFIG.SYS
 file and then reboot your system, no error message is returned.
 Setting PAUSEONERROR=YES in your CONFIG.SYS file does not change this
 behavior.

 Microsoft has confirmed that this inconsistency occurs in Version
 1.20. We are researching this problem and will post new information
 here as it becomes available.


 707. PRINT /C and /T Options Don't Cancel Print Jobs Correctly

 Microsoft has confirmed that the following problems occur with the /C
 and /T options of the PRINT command in Microsoft OS/2 Versions 1.10
 and 1.20. This is true for both the PM spooler and the OS/2 LAN
 Manager spooler, although the behavior is slightly different,
 depending on which spooler you are using. Please note that you can
 work around these problems by canceling the print jobs from the Print
 Manager program. We are researching these problems and will post new
 information here as it becomes available.

 The following information describes these problems in more detail.
 Before performing the steps below, you need to save either one or
 several files in the queue by using the "hold queue" option in the
 Print Manager. Release the "hold queue" after opening an OS/2 window
 to type the commands listed below.

 The following problem occurs when only one file has been saved in the
 queue:

 If you enter PRINT/C or PRINT/T, the file is still printed out. If you
 press CTRL+C just after entering PRINT/C, the following error message
 is displayed:

    SYS1780: The PRINT command has detected an unexpected Presentation
             Manager error.

 The following problem occurs when several files have been saved in the
 queue:

 If you enter PRINT/C, the files are still printed out. However, if you
 enter PRINT/T, printing ceases and the files are not printed out.

 If you enter PRINT/T while the first file is being printed, only
 the first file will be printed (all other files will not).

 If you press CTRL+C right after entering PRINT/C or PRINT/T, these
 commands do not take effect and the following error message is
 displayed:

    SYS1780: The PRINT command has detected an unexpected Presentation
             Manager error.


 708. Getting/Setting Extended Attribute Information

 The following are questions about EAs (extended attributes):

 1. Is there a way to obtain all of the EAs for a file by using the
    DosQFileInfo() function? It appears that you have to fill in the
    GEALIST with the name of each attribute that you want information
    about. The only way that I've been able to do this is to use the
    DosEnumAttribute() function.

    You need to fill in the GEALIST with values. This is required. One
    good reason for this is so you can calculate the total space you
    need to hold the FEALIST. The DosEnumAttribute() function provides
    this functionality. For OS/2 Version 1.20, this call is
    unnecessary if you always use a 64K segment for the FEALIST.
    However, this limitation will be raised in future versions of
    OS/2; therefore, you will have to go through this process in the
    future.

 2. In the case of existing files that I don't want to truncate, can I
    get the EAs when I open the file or must I use the DosQFileInfo()
    function?

    You must use DosQFileInfo(). When opening a file, you can only set
    attributes, not get them.

 3. Do I have to use the DosSetFileInfo() function or can I set the
    attributes when the file is being opened?

    You can set the attributes when opening the file, only for files
    that are being created, replaced, or truncated. Otherwise, you will
    have to set the attributes with the DosSetFileInfo() function.


 709. XON/XOFF Flow Control in COM1 Driver

 The following are questions about the XON/XOFF flow control in the
 COM1 driver:

 1. What is the size of the default receive buffer in the OS/2
    Version 1.10 COM1 driver?

    The default receive buffer size is 1025 bytes. This number is
    subject to change, as any original equipment manufacturer (OEM) can
    change this value (they have the source to the COM1 driver).

 2. If we are controlling the flow of incoming characters by sending
    XON/XOFF characters, what are the "trigger" points for the XON and
    XOFF transmissions? Can these "trigger" points be changed?

    The "trigger" points are 850 bytes and 400 bytes. These numbers are
    from the OS/2 Version 1.10 Device Driver Developer's Kit (DDDK).
    These values cannot be changed on the fly, since there is no
    DosDevIOCtl() command to do this. If you write your own COM1
    driver, you can use different values. These numbers are also
    subject to change, as an OEM can change these values.

 3. When an XOFF character is transmitted based upon reaching a
    certain buffer filled state, is there a second "trigger" if
    characters continue to be received beyond a second point? For
    example, if the first XOFF character gets sent when the receive
    buffer is 80 percent full, does another XOFF character get
    transmitted again when the receive buffer is 95 percent full, or
    some other such point (in case the first XOFF character was
    missed)?

    No, the COM1 driver does not use this method because many COM
    drivers assume the next character after a XOFF character is an XON
    character. At certain times, the input buffer can be overrun and
    an RX_QUE_OVERRUN error will be returned. If this is a problem for
    you, then you need to use DTR/RTS handshaking.


 710. Named Pipes Constants in BSEDOS.H Changed in 1.20

 Question:

 In OS/2 Version 1.10, the following named-pipe constants were defined
 in the BSEDOS.H file:

    #define PIPE_READMODE_BYTE        0x0000
    #define PIPE_READMODE_MESSAGE     0x0100
    #define PIPE_TYPE_BYTE            0x0000
    #define PIPE_TYPE_MESSAGE         0x0400
    #define PIPE_END_CLIENT           0x0000
    #define PIPE_END_SERVER           0x4000
    #define PIPE_WAIT                 0x0000
    #define PIPE_NOWAIT               0x8000
    #define PIPE_UNLIMITED_INSTANCES  0x00FF

 In OS/2 1.20, these constants are no longer defined in BSEDOS.H. Where
 are these constants defined in Version 1.20?

 Response:

 In the OS/2 Version 1.20 Programmer's Toolkit, these constants have
 been replaced with the following:

    Define in Version 1.10             New Define in Version 1.20
    ----------------------             --------------------------

    PIPE_READMODE_BYTE        0x0000   NP_READMODE_BYTE        0x0000
    PIPE_READMODE_MESSAGE     0x0100   NP_READMODE_MESSAGE     0x0100
    PIPE_TYPE_BYTE            0x0000   NP_TYPE_BYTE            0x0000
    PIPE_TYPE_MESSAGE         0x0400   NP_TYPE_MESSAGE         0x0400
    PIPE_END_CLIENT           0x0000   NP_END_CLIENT           0x0000
    PIPE_END_SERVER           0x4000   NP_END_SERVER           0x4000
    PIPE_WAIT                 0x0000   NP_WAIT                 0x0000
    PIPE_NOWAIT               0x8000   NP_NOWAIT               0x8000
    PIPE_UNLIMITED_INSTANCES  0x00FF   NP_UNLIMITED_INSTANCES  0x00FF

 These new constants are defined in BSEDOS.H.


 711. Maximum Number of Semaphore Handles Available

 Question:

 What is the maximum number of semaphore handles [addition of all
 semaphore handles passed in each DosSemMuxWait() call] available?
 Also, what is meaning of the ERROR_TOO_MANY_MUXWAITERS error message?

 Response:

 To keep track of a clear on a semaphore for DosMuxSemWait(), OS/2
 needs to maintain a list of the semaphores being muxwaited upon. This
 list is implemented as a chain of data structures, where each
 structure identifies a waiting semaphore.

 When a semaphore ID structure is added to the linked list, it is
 allocated from a limited pool of structures. Under Versions 1.10 and
 1.20 of OS/2, the maximum number of semaphore ID structures available
 is 255.

 If DosMuxSemWait() attempts to allocate more structures then there are
 available, you will receive the error message of
 ERROR_TOO_MANY_MUXWAITERS.


 712. usConfigId VioGetConfig() Parameter Values Not Defined

 The #defines for the new "usConfigId" parameter of the VioGetConfig()
 function were mistakenly left out of the .H files. The values should
 be defined as follows:

    #define VIO_CONFIG_CURRENT    0
    #define VIO_CONFIG_PRIMARY    1
    #define VIO_CONFIG_SECONDARY  2

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 713. Format of OS/2 Version 1.20 EXE Header

 In the Software/Data Library is a file named NEWEXE12 that describes
 the format of the OS/2 Version 1.20 EXE header. NEWEXE12 can be found
 in the Software/Data Library by searching on the keyword NEWEXE12, the
 Q number of this article, or S12532. NEWEXE12 was archived using the
 PKware file-compression utility.


 714. IMPLIB, DLL, LIB, and LIBPATH Information

 Question:

 What is the connection between IMPLIB's .LIB files and the location of
 a DLL (dynamic linked library)?

 My application uses a DLL with no problem as long as the DLL stays in
 a particular subdirectory. When the LINK (of the DLL) refers to
 another subdirectory (in this case, the application's own
 subdirectory), the application fails to find the DLL.

 When I put the DLL back where it used to be, the application works
 correctly.

 However, CodeView then can't use the DLL because it needs the DLL in
 the application's executable subdirectory. Having two copies of the
 DLL works in both cases, but this seems less than ideal (I do tell
 CodeView about the DLL by using the /L LIB.DLL switch).

 My LIB environment variable points to the subdirectory that contains
 the .LIB file produced by IMPLIB and not to where the DLL is stored.

 Both .LIB files and the two DLLs are produced in the same MAKE file.

 Response:

 A process that is trying to locate a DLL does not know or care about
 the import library that was used to link the DLL. All that is
 important is that the DLL in question be located in a subdirectory
 that is listed in your LIBPATH system setting.

 Please note that the LIBPATH system setting and the LIB environment
 variable have separate and distinct purposes. LINK uses the LIB
 environment variable to locate .LIB files that it uses when building
 an executable file, or DLL. The LIBPATH system setting is used by OS/2
 when it tries to locate DLLs.

 If your application is able to locate your .DLL only when the .DLL is
 located in the same subdirectory as the .EXE file, your current
 directory probably is located in your LIBPATH system setting. This is
 a common way for developers to set up the LIBPATH system setting. For
 example, you might have a LIBPATH such as the following:

    LIBPATH=.;C:\OS2\DLL;C:\;C:\BINP\DLL

 So that your application can locate your .DLL from subdirectories
 other than the current working directory (the . directory), put your
 DLL in a subdirectory listed in your LIBPATH system setting. For
 example, in the LIBPATH example above, you could put your DLL in
 either C:\OS2\DLL or in C:\BINP\DLL (assuming, of course, that you
 have a subdirectory called C:\OS2\DLL or C:\BINP\DLL).

 If you change your LIBPATH system setting in your CONFIG.SYS file, you
 will need to reboot for the change to be recognized by OS/2.


 715. OS/2 Equivalent of MS-DOS CTTY Command

 Question:

 Is there a CTTY command in OS/2 like the one in MS-DOS that will let
 me use a terminal to prompt a command such as "CTTY > COM1"?

 Response:

 You can assign standard input and output to a different keyboard and
 terminal using the redirection operators. For example, to assign
 standard input and standard output to the keyboard and terminal
 attached to COM1, type the following:

    cmd < com1 > com1

 This would allow you to run CMD on your computer from a remote
 terminal. This is equivalent to the CTTY command in MS-DOS.


 716. Keyboard Monitors Not Allowed in PM Screen Group

 Question:

 Why can we no longer monitor keys in the Presentation Manager (PM)
 screen group? This worked properly in previous releases such as
 Version 1.10, yet it appears that this functionality has been
 disabled.

 Response:

 Keyboard monitors, mouse monitors, and any other character input
 device monitors are no longer allowed in the PM screen group.

 The monitors that cannot be registered for the PM screen group are
 those monitors that are screen group dependent. Input devices such as
 the keyboard, the mouse, a light pen, etc., are virtualized for each
 screen group. Devices such as the printer are system-wide devices that
 have no relationship to the screen group model. Only one process can
 own the printer at a time, while many processes can own the keyboard
 or mouse, but only one process per screen group.

 There are such things in PM called journal hooks that will help you to
 accomplish what you are trying to do. However, your application must
 have some or all of the properties of a PM program to perform this
 type of functionality.

 What you are doing in Version 1.10 with monitors was not intended to
 work with Version 1.10. It works because the original design goals
 were not enforced. It is a coincidence that monitors could be
 registered to work with the PM desktop in Version 1.10.

 The PM philosophy forces all applications to be well-behaved and work
 within the message model. In past releases of OS/2, this was not
 strictly enforced, although it was our intent make this enforcement
 all along. This enforcement was put into place in OS/2 Version 1.20.


 717. Setting Serial Port Time-out Parameters

 Question:

 We are trying to run an external serial display over an RS232 port
 under OS/2 Versions 1.10 and 1.20. We are having problems with the
 time-out values. The device times out and is unavailable.

 What are the various time-out parameters, and which parameters should
 we be using?

 Response:

 To change the device time-out values in the serial port driver, you
 need to use the DosDevIOCtl() calls ASYNC_GETDCBINFO and
 ASYNC_SETDCBINFO. These calls are documented on Pages 39, 263, 270,
 and 336 of the "Microsoft Operating System/2 Programmer's Reference
 Volume 3" for Version 1.10.

 The "usReadTimeout" field of the DCBINFO structure specifies the
 time-out value in one-hundredths of a second. If the field is set to
 zero, the time-out is 0.01 seconds; if it is set to 1, the time-out is
 0.02 seconds, and so on.

 The "fbTimeout" field of the DCBINFO structure specifies the time-out
 processing for the device. It can be a combination of the following
 values:

    Value                     Meaning
    -----                     -------

    MODE_NO_WRITE_TIMEOUT     Enable write infinite
                              time-out processing.

    MODE_READ_TIMEOUT         Enable normal read time-out
                              processing.

    MODE_WAIT_READ_TIMEOUT    Enable wait-for-something
                              read time-out processing.

    MODE_NOWAIT_READ_TIMEOUT  Enable no-wait read
                              time-out processing.

 If you want to adjust the amount of time that the COM driver waits
 until it performs a time-out, set "fbTimeout" to MODE_READ_TIMEOUT (if
 it is not already set to that) and set the "usReadTimeout" field of
 the DCBINFO structure to the desired value (see below). The default is
 60 seconds.

 If you want to force the COM driver to wait for data and prevent it
 from timing out on a read, set "fbTimeout" to MODE_WAIT_READ_TIMEOUT.

 For some sample code that demonstrates how to set the read time-out
 and other COM port parameters, please see the COMTALK sample program
 included with Versions 1.10 and 1.20 of the Microsoft Operating
 System/2 Programmer's Toolkit.

 If you are still having difficulty receiving data after examining the
 COMTALK sample application, the problem you are experiencing may lie
 in your hardware setup, that is, your serial cable, serial port, or
 dumb terminal. For example, be sure to match up the serial
 communication parameters of your serial port with that of your
 terminal.

 An excellent general reference on data communications is a book named
 the "C Programmer's Guide to Serial Communications" by Joe Campbell,
 Howard W. Sams & Company 1988. While this book does not specifically
 address the OS/2 API, it is very helpful in describing how to set the
 various parameters of a serial port device driver.


 718. Querying Country Information

 Question:

 When using the DosGetCountryInfo() function, where does the
 information come from? For instance, when I change the currency symbol
 via the Control Panel, it does not seem to make any difference;
 DosGetCountryInfo() still returns the default values.

 Response:

 The recommended way to query the country information is to first use
 the PRF functions (these calls were added to Version 1.20) to query
 the OS2*.INI file for the PM_NATIONAL key name country information. If
 these calls fail, use the default information from DosGetCntryInfo().

 DosGetCountryInfo() gets data from COUNTRY.SYS. The Control Panel does
 not modify this file; it instead changes the file OS2.INI. You need to
 use WinQueryProfileString() to get information from the OS2.INI file.
 Use the application name PM_NATIONAL and the keyname sCurrency.


 719. Country PM_NATIONAL Key Name Information

 The list of PM_NATIONAL key names can be found by either looking at
 the OS2.INI file with INIEDIT, or by referring to the following list.
 These key names are not documented in any of the OS/2 or Presentation
 Manager (PM) printed documentation.

    Key         Meaning
    ---         -------

    iCountry    Country code
    iDate       Date format
    iCurrency   Whether the currency symbol precedes the amount
    iDigits     Number of digits following decimal point
    iTime       Whether time is 12 or 24 hour clock
    iLzero      Whether leading zeros should be displayed
    s1159       NLS string describing AM
    s2359       NLS string describing PM
    sCurrency   Currency symbol
    sThousand   Thousands separator
    sDecimal    Decimal marker
    sDate       Date separator
    sTime       Time separator
    sList       List separator


 720. Process Block Timeout Queue Update Causes Hang to Occur

 Microsoft has confirmed that there is a problem with OS/2 Version 1.10
 involving the update of the process block timeout queue. The problem
 seems to reside in the removal of process entries from the OS/2 kernel
 process block timeout queue data structure.

 This problem has been observed on OS/2 Version 1.10 machines that are
 heavily loaded with applications that cause a high rate of blocking
 activity to occur (such as communication related programs).

 This problem has been isolated to a problem with the timeout queue.
 The link list structure gets corrupted and loses the trailing dummy
 entry (thread 0), causing a subsequent entry into a procedure to insert
 the process into the ProcBlock timeout queue, which in turn hangs the
 system. This procedure is executed when the ProcBlock procedure is
 called and a timeout value is specified in DI:CX.

 This problem has been corrected in Version 1.20.

 The timeout queue consists of a circular list of entries that is based
 on the thread number. The procedure adds an entry into the timeout
 queue. The code loop "hang" occurs while it is trying to locate the
 end of the timeout queue (to add a new entry), but is unable to. This
 problem could occur if the thread number to be added to the timeout
 queue by ProcBlock is already in the queue.

 Because interrupts are disabled while the code is looping, you cannot
 get control using the kernel debugger by pressing CTRL+C.

 The code fragment where the hang occurs is listed below:

     0090:71A7  MOV  BL,[BX,SI]
     0090:71A9  AND  BX,0FFH
     0090:71AD  JL   $+01EH
     0090:71AF  ADD  BX,BX
     0090:71B1  MOV  DI,BX
     0090:71B3  ADD  BX,BX
     0090:71B5  ADD  BX,DI
     0090:71B7  CMP  DX,[BX+SI+4]  SI=4FC8 BX=00F6 DX=0000
     0090:71BA  JB   $+011H
     0090:71BC  JA   $+7
     0090:71BE  CMP  CX,[BX+SI+2]  SI=4FC8 BX=00F6 CX=0A07
     0090:71C1  JB   $+0AH
     0090:71C3  SUB  CX,[BX+SI+2]
     0090:71C6  SBB  DX,[BX+SI+4]
     0090:71C9  JMP  $-022H

 Turning the interrupt flag back ON gets the code out of the hang.

 IOPL = 2 when the hang occurs.


 721. OS/2 Programmer's Reference Volume 4 Documentation Errors

 Microsoft has confirmed that the following documentation errors occur
 on Page 31 in the "Microsoft Operating System/2 Programmer's Reference
 Volume 4" for Version 1.20. The following problems have been found
 with the example on Page 31:

 1. On line 3, "pprogde" should be changed to "progde".

 2. On lines 9 and 10, all backslashes should be escaped (doubled). For
    example, "c:\os2" should instead be "c:\\os2".

 3. On line 12, it states that it is okay to set pszEnvironment to ""
    (one null character). When no environment strings are provided, one
    null character will work correctly. However, you need to have two
    null characters when there are environment strings. For
    consistency, two null characters should be used in this example.


 722. DosError() Deals Only with Critical Errors

 Problem:

 I have a system with one floppy disk drive. When executing
 DosQFSInfo() in the DOS compatibility box, the hard-error screen pops
 up even though I am using the DosError(0) function. In protected mode,
 the DosError(0) function works correctly, and the hard-error screen
 does pop up. What else can I do to suppress the hard-error screen in
 the DOS compatibility box?

 Response:

 You are running into a restriction on the DosError() function. The
 restriction on DosError() concerning real mode programming is that the
 DosError() call deals only with INT 24H (critical errors). Since the
 prompt to change disks from Drive A to Drive B is not a critical
 error, this will not work as it does under OS/2 protected mode. The
 only way to disable the prompt under MS-DOS and the pop-up under the
 OS/2 compatibility box is to set the logical drive map. For
 protected-mode OS/2, the screen is a "pop-up" and is already disabled.

 You can work around this restriction by using the code included below.
 If you are on a one-drive machine and in real mode, you should set the
 logical drive map yourself. Otherwise, the system can handle the
 change (if necessary).

 To perform this functionality, you must make a call to DosDevConfig()
 and a call to DosGetMachineMode(). To get access to the MS-DOS call
 for setting the logical drive map, you must make a call into an
 assembly language routine. This is because the protected-mode C
 run-time libraries that you have do not have the int86(x) or intdos
 functions in them.

 Listed below is SETMAP.ASM, the assembly language routine you will
 need along with the C code necessary to perform this functionality.

 Use the following commands to compile and link the sample code:

 cl /c /W3 error.c
 masm setmap.asm;
 link error+setmap /nod,error.exe,nul.map,os2 slibcep;
 bind error.exe \lib\doscalls.lib \lib\api.lib

 Sample Code
 -----------

 #define INCL_SUB
 #define INCL_BASE
 #define INCL_DOSDEVICE
 #include <os2.h>

 int main(void);
 extern void setmap(USHORT drivenum);

 int main(void)
 {
     struct  {
       FDATE fdateCreation;
       FTIME ftimeCreation;
       CHAR cchName;
       CHAR achVolumeName[14];
     } FSInfoBuf;

     BYTE    bMachineMode;
     USHORT  usDevInfo;

     BOOL    bSpecial = FALSE;

     DosDevConfig((PVOID)&usDevInfo,DEVINFO_FLOPPY,0);

     DosGetMachineMode(&bMachineMode);

     if((usDevInfo < 2)   && (bMachineMode == MODE_REAL))
      bSpecial = TRUE;

     DosError(0);

     if(bSpecial)
      setmap(1);

       DosQFSInfo(1,
            2,
            (PBYTE) &FSInfoBuf,
            sizeof(FSInfoBuf));

     /* The calls to setmap are done just prior to accessing the drive.
        This could be improved by keeping a current disk variable and
        then not doing the setmap call if not needed. For this small
        example, the extra variable is unnecessary. */

     if(bSpecial)
      setmap(2);

     DosQFSInfo(2,
             2,
             (PBYTE) &FSInfoBuf,
             sizeof(FSInfoBuf));
     return(0);
 }

 .MODEL SMALL
 .CODE
 public _setmap
 _setmap PROC

     push    bp
     mov     bp,sp

     mov     ax,440FH     ; Set Map call.
     mov     bx,[bp+4]    ; Pass in drive number parameter.
     int     21H         ; Set the logical drive.

     pop     bp
     ret
 _setmap endp
 END


 723. Monitor Chain Notification Information

 Question:

 Is it possible to send an error back through the monitor chain? Also,
 can I block a thread in my Monitor Notify routine? What are the
 repercussions? What happens to the chain? Do other monitors block
 trying to write to the chain?

 Response:

 The data stream in a monitor chain runs in one direction only. A
 monitor can send information down the chain, but not back up from
 where it came.

 Whether or not you can block a thread in your monitor notification
 routine depends on what the context of your thread is. It is possible
 for your monitor notification routine to be called at interrupt time
 (for example, if your monitor chain is empty; that is, no monitors
 have registered). In that case, you cannot call the Block DevHlp. If
 you can guarantee that you will never have an empty monitor chain, you
 are probably safe to block. You shouldn't have to worry about monitors
 in the chain; the notification routine doesn't get called until data
 comes out of the last monitor in the chain in question.

 For more information on this topic, please refer to IBM's technical
 reference manuals, or to "Writing OS/2 Device Drivers" by Raymond
 Westwater, Addison-Wesley, 1989.


 724. KBDINFO Flags Undefined in Version 1.20

 Question:

 I have Version 1.20 of the Presentation Manager (PM) Toolkit and am
 using the KbdSetStatus() function. Within this function, I use the
 KBDINFO structure. I pass the fsMask parameter to the KBDINFO
 structure. The flag set for fsMask is KEYBOARD_ECHO_ON. When I
 compile my application I receive the error message "C2029 error,
 KEYBOARD_ECHO_ON; undefined." This same function worked correctly with
 Version 1.10 of the PM Toolkit. Why doesn't it work with Version 1.20?

 Response:

 The KEYBOARD_*_* flags (KEYBOARD_ECHO_ON, etc.) are undefined in the
 Version 1.20 header files. You can use the hexadecimal values,
 assigned to these in the Version 1.10 header files, in your
 application. For example:

    KbdSetStatus(&kbdinfo, 0);
    Kbdinfo.fsMask = 0x0001;        // KEYBOARD_ECHO_ON

 The value 0x0001 corresponds to the flag KEYBOARD_ECHO_ON in the
 Version 1.10 BSESUB.H header file. The corresponding flags are as
 follows:

    KEYBOARD_ECHO_ON                0x0001
    KEYBOARD_ECHO_OFF               0x0002
    KEYBOARD_BINARY_MODE            0x0004
    KEYBOARD_ASCII_MODE             0x0008
    KEYBOARD_MODIFY_STATE           0x0010
    KEYBOARD_MODIFY_INTERIM         0x0020
    KEYBOARD_MODIFY_TURNAROUND      0x0040
    KEYBOARD_2B_TURNAROUND          0x0080
    KEYBOARD_SHIFT_REPORT           0x0100


 725. Invalid Value Listed for DosSetSigHandler() usSigNumber

 On Page 147 of the "Microsoft Operating System/2 Programmer's
 Reference Volume 3" for Version 1.10, it states that a valid value for
 the DosSetSigHandler() usSigNumber parameter is SIG_BROKENPIPE.
 However, a signal of this type does not exist. It is defined in
 BSEDOS.H as having a value of 2; however, this value is invalid.

 The SIG_BROKENPIPE is defined as a broken connection to a pipe. We do
 not plan to implement this functionality in the future.

 Microsoft has confirmed that this error occurs in the "Microsoft
 Operating System/2 Programmer's Reference Volume 3" for Version 1.10,
 and also in QuickHelp. We will post new information here when the
 documentation and QuickHelp has been updated to correct this error.


 726. DLL Version of gets() Not Working with OS/2 1.10

 Microsoft has confirmed that the DLL version of gets() does not work
 correctly under OS/2 Version 1.10. We are researching this problem and
 will post new information here as it becomes available.

 As a workaround, you can either use one of calls in the scanf()
 family, or write your own gets() call, using the getc() or getchar()
 functions.


 727. Accessing Addresses Above 16 MB in OS/2 Version 1.20

 Question:

 I have the following questions about accessing physical addresses
 above 16 MB:

 1. Does OS/2 support physical addresses outside of the 80286 address
    space (that is, above 16 MB)?

 2. Will the PhysToVirt() DevHlp work with physical addresses above
    16 MB (01000000H)?

 3. Can RAM above 16 MB be used by OS/2 Version 1.20 in general?

 Response:

 The following are the answers to the above questions:

 1. Actually, OS/2 (that is, the OS/2 kernel) does NOT support physical
    addresses outside of the 80286 address space. The Version 1.20
    kernel operates on virtual addresses, and the Version 1.20 virtual
    memory manager only understands addresses that lie within the 80286
    physical address space.

    A device driver, on the other hand, can DIRECTLY address physical
    memory without first going through OS/2's virtual memory manager.
    Therefore, you could (on an 80386) write a device driver to
    directly address memory above the 16 MB line.

 2. The PhysToVirt() DevHlp will not accept physical addresses outside
    the 16 MB address space of the 80286. There is a check in the
    PhysToVirt() code to prevent this from happening.

    However, as stated above, this does not prevent you from writing a
    device driver to access 80386 memory above the 16 MB boundary.

 3. No, you cannot use RAM above 16 MB because the OS/2 Version 1.20
    kernel cannot address physical memory outside the 16 MB address
    space of the 80286. When adapting OS/2 for your hardware, you should
    not specify arena boundaries (i.e. physical memory addresses) beyond
    16 MB.


 728. INT 1AH Function 02H Returns Incorrect Value in 3.x Box

 Microsoft has confirmed that the following problem occurs in OS/2
 Version 1.20. The interrupt 1AH function 02H, read real time clock,
 does not return the correct values. When the following is typed in
 under SYMDEB in the 3.x compatibility box

    a
    mov ah,2
    int 1a
    int 3

    g 100

 the CX and DX registers are set to 0 and the carry flag is incorrectly
 set.

 We are researching this problem and will post new information here as
 it becomes available.


 729. Incorrect Error Code Returned by VioSetFont() in Version 1.20

 Issuing a VioSetFont() call with the following parameters

    (cb=14,type=0,cxCell=0,cyCell=10,pbData,cbData=2560,VioHandle=0)

 returns ERROR_VIO_USER_FONT(468).

 This return code (468) represents a warning. It indicates that
 although the font could not be loaded into the video adapter using the
 current mode, the font was saved as part of a special user code page
 for use with VioSetMode().

 Since the specified column (cxCell) and row (cyCell) values are
 invalid for a valid mode setting (column = 0, row = 10), the
 ERROR_VIO_INVALID_PARMS error should instead be returned.

 Microsoft has confirmed that this problem occurs in Version 1.20. The
 parameters should be checked and the appropriate error code should be
 returned.

 We are researching this problem and will post new information here as
 it becomes available.


 730. Wrong Error Returned If VioSetFont() cbData Is Invalid

 Issuing a VioSetFont() call with the following parameters

    (cb=14,type=0,cxCell=8,cyCell=16,pbData,cbData=2048,VioHandle=0)

 incorrectly returns ERROR_VIO_INVALID_LENGTH(438) instead of the
 correct error of ERROR_VIO_INVALID_PARMS(421).

 The ERROR_VIO_INVALID_LENGTH(438) error is normally returned when it
 has been determined that the structure is an incorrect size. The
 ERROR_VIO_INVALID_PARMS(421) error is normally returned when it has
 been determined that one of the parameters is incorrect. In this case,
 "cbData=2048" should have been used instead of "cbData=4096", which
 means that the error involved an incorrect parameter.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 731. MEMMAN MOVE and NOMOVE Option Syntax Problem in 1.20

 According to Page 83 of the "Microsoft Operating System/2 Desktop
 Reference" for Version 1.10, if you are just specifying the MOVE or
 NOMOVE options of the MEMMAN command, you should be able to use the
 following syntax:

      MEMMAN=,MOVE  or  MEMMAN=,NOMOVE

 However, if you use either of these commands, the following error
 message is returned when you reboot your system:

    SYS1196: The parameter "," on Line<n> of the config.sys file is
    not acceptable for the MEMMAN command. Line<n> is ignored.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 732. VioPopup() "pfWait" Parameter Value Not Checked Correctly

 The VioPopUp() "pfWait" parameter is not being checked correctly. If
 you use a value greater than 3 and less than 0x8000 for this
 parameter, an incorrect error message of "ERROR_VIO_NO_POPUP" is
 returned. Instead, the correct error message of
 "ERROR_VIO_INVALID_PARMS" should be returned. Also, if you use a value
 from 0x8000 to 0xFFFF, no error message is returned at all.

 Microsoft has confirmed this to be a problem in OS/2 Version 1.10. We
 are researching this problem and will post new information here as it
 becomes available.


 733. CACHE Parameter Values Displayed Incorrectly

 The values for the HPFS286 CACHE parameters MAXAGE, BUFFERIDLE, and
 DISKIDLE are not displayed correctly.

 If a value N (greater than 65,535) is entered, the above parameters
 display N as N modulo 65536. For example:

    CACHE /MAXAGE:65536
    CACHE                 Displays a maxage of 0.

    CACHE /MAXAGE:65537
    CACHE                 Displays a maxage of 1.

    CACHE /MAXAGE:600000
    CACHE                 Displays a maxage of 10176.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 734. Memory Segment Allocated by VioGetFont() Must Be Freed

 Problem:

 The documentation for VioGetFont() does not state that the user must
 free up any memory segment that VioGetFont() has allocated. I did not
 know I was supposed to free the memory used by VioGetFont() and ran
 out of memory. This resulted in VioGetFont() returning an error code
 of 8. If you call VioGetFont() enough times with no memory available,
 OS/2 will lock up. I thought VioGetFont() would use the same piece of
 memory every time it was invoked, since the documentation does not
 state that you must free it back up.

 Response:

 OS/2 can't use the same piece of memory. If you called VioGetFont()
 and then set the font to something different, the original buffer
 wouldn't change. Therefore, OS/2 must create a new buffer each time
 and put a copy of the font table into the buffer. This is how most of
 OS/2 works. Any time you request information from the system, you are
 given a copy of the information, not the information itself. This
 allows you to manipulate the data without affecting the system until
 you actually want to [VioSetFont()].

 We have suggested that a reminder be included in the comments section
 in the documentation to inform users that they must free the memory
 buffer with a DosFreeSeg() call.

 This feature is being reviewed and will be considered for inclusion in
 a future release of the documentation.


 735. Memory Management Swapping Information

 Question:

 I have the following questions about memory management under OS/2 with
 Presentation Manager (PM):

 1. How large a virtual address space can be supported given a hard
    disk for swapping of finite size (but smaller than that of the full
    virtual address space)? Also, how much hard disk space will OS/2
    ensure is free when swapping, or will the swap file allocate all
    available disk space if required?

 2. Does the memory manager use an algorithm to determine what portions
    of a block of memory must be swapped? Also, does the memory manager
    reload the entire block when swapping back into memory, or only the
    section required? How large is the smallest section?

 3. Is PM swappable? In an OS/2 PM environment where the only active
    application is an OS/2 Kernel program (uses "OS/2 base system
    function calls" only), how much of PM must reside in memory? How
    much would be swapped out if sufficient memory requests occurred?

 Response:

 The answers to the above questions are as follows:

 1. When you set up a SWAPPATH, you indicate the number of kilobytes of
    memory to leave free on the disk. This allows the swap file to grow
    until there are only x kilobytes of space left on the hard disk
    (where x is the number of kilobytes indicated in the SWAPPATH
    CONFIG.SYS file command). The swap file will not grow beyond this
    size.

 2. Memory is swapped out on a per-segment basis. No partial segments
    are swapped out. Therefore, the largest segment to be swapped is
    64K, and the smallest is 1 byte (zero-length segments are not
    allowed).

 3. Basically, everything is swappable with a few exceptions: for the
    most part, the operating system kernel is not swappable, nor are
    the device drivers.

    Along with that, any data that is brought in as nonswappable will
    not be swapped. PM may have some nonswappable data in it, but for
    the most part it is swappable.


 736. BIOSPARAMETERBLOCK "fsDeviceAttr" Documentation Error

 Question:

 I am unsure how to use the "fsDeviceAttr" of the BIOSPARAMETERBLOCK
 structure. QuickHelp and Page 332 in the "Microsoft Operating System/2
 Programmer's Reference Volume 3" for Version 1.10 define
 "fsDeviceAttr" to be the following:

 fsDeviceAttr   Specifies information about the drive. If this value is
                0x0001, the media are not removable. If it is 0x0002,
                the media can detect changes. This field can be one or
                both of these values.

 Are there only three states: not removable, aware of change, and aware
 of change and not removable? It seems illogical that a device could be
 aware of change and nonremovable.

 Response:

 Microsoft has confirmed that the documentation is incomplete for this
 parameter. The last value, which is aware of change and nonremovable,
 does not make much sense, but it could be reported. However, the 00
 (no change and removable) case is a valid value, but the documentation
 does not indicate that it is a possible return value.

 We will post new information here once the documentation has been
 updated to correct this error.


 737. OS/2 DosOpen() Return Code Error Information

 The following return codes are returned by the DosOpen() function call
 under the following circumstances:

 1. The file already exists.

       DosOpen() error == 110 (ERROR_OPEN_FAILED).

 2. The path provided does not exist.

       DosOpen() error == 3 (ERROR_PATH_NOT_FOUND).

 3. The disk is full.

       DosOpen() error == 112 (ERROR_DISK_FULL).

 4. The directory is full.

       DosOpen() error == 82 (ERROR_CANNOT_MAKE).

 5. The filename provided is not a valid filename, or the pathname
    provided is not valid.

       DosOpen() error == 2 (ERROR_FILE_NOT_FOUND). This means you
                            included a wild card in the filename, which
                            is not allowed.

    or

       DosOpen() error == 3 (ERROR_PATH_NOT_FOUND). This means you
                            included a wild card in the filename, which
                            is not allowed.
    or

       DosOpen() error == 123 (ERROR_INVALID_NAME). This means an
                              illegal character or malformed file system
                              name was used.


 738. OS/2 DosCloseSem() General Information

 Question:

 I have the following questions when DosCloseSem(system_sem) is called
 and the semaphore is set (owned):

 1. Does DosCloseSem() always return a code of 102, or does it depend
    on the issuing process to be the owner of the semaphore? Also, is
    this affected by the semaphore being exclusive?

 2. If a code of 102 is returned, what happens to the semaphore: is it
    closed, cleared, closed and cleared, or none of the above?

 3. If a process calls DosCloseSem() and the semaphore is owned by
    this process, does the first thread (or process) receiving the
    ownership of the semaphore get a return code of 105?

 Response:

 The following are answers to the above questions:

 1. A 0 (zero) is returned by DosCloseSem() if the operation was
    successful. You get a return code of 102 if the owner tries to
    close an exclusive semaphore.

 2. As is the standard procedure with the OS/2 API, a nonzero return
    code means the call failed. DosCloseSem() does not clear or close
    the semaphore. Clearing would be an unexpected side effect.

 3. No, this return code occurs when a thread owning a semaphore dies
    (exits). This is not the same as closing a semaphore.

 For more general information about semaphores and their usage, there
 is a good article on semaphores in the May 1988 issue of "The
 Microsoft Systems Journal," titled "Using OS/2 Semaphores to
 Coordinate Concurrent Threads of Execution."


 739. Must Use DosGetMessage() to Obtain Length of Message

 Question:

 Is there any way of determining the length of a message without using
 a DosGetMessage() call?

 Response:

 No. The only way to see the messages in the file is to use the
 DosGetMessage() call. It is difficult to tell the length of a given
 message, as it may include replaceable parameters that are replaced
 with the text when the DosGetMessage() call is made.


 740. HPFS Versus FAT File System Performance Information

 There are several factors that affect HPFS performance. These factors
 are discussed below.

 First, the buffer size affects HPFS performance. HPFS is designed to
 use a larger buffer pool than the MS-DOS FAT file system because
 buffer RAM is much more available when the operating system is not
 constrained to a 640K address space. HPFS buffers are 2K each; this
 improves performance when buffering data and directories, but it also
 means a poorer buffer hit ratio compared to the MS-DOS FAT file
 system, which has 512 byte buffers.

 For a "good sized" HPFS buffer pool-- say, 256K -- the difference is
 minor, but for a default buffer pool of 32K or 64K, HPFS is impacted
 by the small size of the buffer. In other words, the default buffer
 size for HPFS is smaller than optimal.

 Second, HPFS is an installable file system, whereas the MS-DOS FAT
 file system is built into OS/2. HPFS is much faster than FAT, but it
 takes longer for a DosRead() call to get to the HPFS code than it does
 to the FAT code. As a result, the more calls you make for smaller and
 smaller requests, the more HPFS's speed is masked by the OS/2
 overhead. Issuing DosFindNext() calls for a single name rather than
 several names; otherwise, issuing reads for 10 bytes, etc., won't be
 any faster with HPFS. Naturally, future releases of OS/2 will improve
 the performance of IFS (Installable File System) to alleviate this
 problem.

 Finally, and most importantly, HPFS gains much of its performance for
 "small, short" operations via its lazy-write mechanism. To improve
 HPFS performance, you should make sure that the lazy-write handler is
 installed. You should also increase the default buffer size.

 If properly configured, HPFS has significantly improved performance in
 most areas over the MS-DOS FAT file system. However, because of the
 OS/2 overhead, improvements are masked for small and quick operations.

 Another factor to consider is the reduced limitation of HPFS. HPFS is
 slightly faster than the FAT file system when opening a file in a
 directory with 10 files, but HPFS is many times faster when opening a
 file in a directory with 1000 or 10,000 files. The same holds true for
 random access to large files -- HPFS can be orders of magnitude
 faster. You also will see improved performance in HPFS in heavy I/O
 systems if you can dedicate a large (2 MB) amount of memory to buffers
 on the disk.

 Currently, most users don't normally do the things mentioned above.
 However, this is mainly because in the past these things weren't
 possible. Now, HPFS gives you the capability to do these things, which
 for some programs and some users can be very handy. Users will rarely
 want to manage 1000 files in a directory, but a mail manager program,
 for example, may find it convenient to have 10,000 files named "1" to
 "10000". When the mail manager program is told to display a mail
 message, it would find the message's name in a database file, and tell
 the system to open file "5267". This is an example of why one of the
 most important goals for HPFS was to remove the performance-mediated
 restrictions on file, directory, and disk sizes.

 There is one more point to make about the relative performance of HPFS
 or any other file system. You should remember that it is the speed of
 the file system that is described as 30 to 400 percent faster, not
 especially the speed of the application. This point is often
 overlooked.

 Obviously, a real life application spends a lot of time doing other
 tasks besides I/O. Even when it appears to be "I/O bound," the
 application is probably doing something to process or prepare the data
 that it is reading or writing. Even using a copy program may introduce
 additional extra overhead. Perhaps the program transfers the data
 within its memory buffers, etc. When file systems are benchmarked,
 special programs are used that just do file system operations. There
 are significant gains with real programs such as database programs,
 C-compilers, etc., but not a 400 percent gain in performance.

 The 30 percent gain in performance comes from comparing HPFS and FAT
 simple file operations such as the reading and writing of moderately
 sized transfers of data. It's hard for HPFS to be much better than FAT
 for moderately sized sequential I/O because both systems just write
 the data out to the disk in a contiguous hunk, so there isn't much to
 be improved upon. HPFS works hard to keep files contiguous and is very
 successful at doing this. The FAT file system tends to keep files
 contiguous when there is only one file being written at one time
 because of the FAT chain. Also, the large allocation unit that the FAT
 file system needs for large disks is a waste of space, but it's a win
 on performance because it guarantees local contiguity. HPFS allocates
 on a sector basis but still maintains a high degree of contiguity even
 when multiple files are being simultaneously written.

 The 400 percent gain in performance comes from tasks such as creating
 and deleting files, for example, the time it takes to create three
 interpass files for a compiler. HPFS does particularly well at this,
 and the FAT file system does particularly poorly; hence, there is a 4
 to 1 performance difference.


 741. VioSetState() Palette Values Not Checked Correctly

 VioSetState() does not report errors consistently. For example, no
 error message is returned for palette values in the range of
 65520-65532. However, palette values from 65533-65535 do cause
 VioSetState() to return error 438, ERROR_VIO_INVALID_LENGTH.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 742. VioSetMode() Incorrectly Handles Row and Column Values

 When issuing a call of VioSetMode(12,3,4,40,25,320,200) no error
 message is returned. This is correct. If you issue a call of
 VioSetMode(12,3,4,0,0,320,200), the incorrect error message of
 "ERROR_VIO_MODE" is returned. If you change the row or column fields
 to any value other than 0, the following call works correctly:

    VioSetMode(12,3,4,1,1,320,200)

 In the above example, the row and column fields were both set to 1.

 It should not matter what values are used in the VioSetMode() call for
 the text row and column fields of the VIOMODEINFO structure when
 setting the screen mode to graphics mode.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 743. OS/2 Version 1.20 Doesn't Recognize Disk Change

 When a DIR is done on a floppy disk with the same volume ID and serial
 number as the previous disk, the same "Bytes Free" value is reported,
 regardless of the actual contents of the disk.

 This problem can be reproduced by making two floppy disks using the
 same image file with a program that copies disks including the volume
 and serial number information. Then, delete some of the files on one
 of the disks and do a DIR on one disk, then on the other disk. The
 "Bytes Free" value will be the same for both disks, even though the
 disks are different.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 744. DosSetSigHandler() Signal Handler Information

 Question:

 I have the following questions about signal handling in OS/2:

 1. On Page 6-183 in the "IBM Operating System/2 Version 1.1 Technical
    Reference Programming Reference: Volume 1," it states the following
    for the DosSetSigHandler() function call:

       The handler may exit by executing an intersegment return
       instruction, or by manually setting the stack frame to some
       known state and jumping to some known location.

    On Page 148 of the "Microsoft Operating System/2 Programmer's
    Reference Volume 3" for Version 1.10, the documentation leaves out
    the second half of the statement above. Is it true that I don't
    actually have to return from the signal handler?

 2. On Page 171 of Gordon Letwin's book, "Inside OS/2," Letwin goes
    into a lot of detail about what happens if you are inside the
    kernel when you get a signal. He states that basically you will
    not get the signal until you are about to resume executing the
    application. Therefore, from this information and the information
    listed above from the IBM documentation, is it correct to assume
    that our signal handler will always be called with ss set to our
    application stack, and not that of the operating system?

 3. The following sentence is included on Page 148 in the "Microsoft
    Operating System/2 Programmer's Reference Volume 3" for Version
    1.10:

       All registers other than cs, ip, ss, sp, and flags in
       assembly-language signal handlers contain the same values as
       when the signal was received.

    Does this mean that ss is always switched back to the stack segment
    defined for the handler during compile/link time?

 Response:

 The answers to the above questions are as follows:

 1. Yes, this is true. Your signal handler may reset the stack pointer
    to a valid stack frame and jump to some other part of your program
    without actually returning from your handler in the normal fashion.
    See Paragraph 4 on Page 6-183 of the "IBM Operating System/2
    Version 1.1 Technical Reference Programming Reference: Volume 1"
    for more information. You are also correct that the "Microsoft
    Operating System/2 Programmer's Reference Volume 3" for Version
    1.10, and the versions of QuickHelp included with OS/2 Versions
    1.10 and 1.20 do not mention this information. We will post new
    information when the documentation has been updated to include this
    information.

 2. Yes, your signal handler's stack segment will be set to the stack
    segment defined for that handler at compile/link time. If, for
    instance, your handler is in the same C source file as main(),
    your handler will use the same stack segment as your main()
    routine does. This will not be the same stack segment that the
    operating system uses.

 3. Yes, ss is always switched back to the stack segment defined for
    the handler during compile/link time. The ss and sp registers do
    not contain the same values as when the signal was received because
    you may be executing a thread that has its own stack segment. For
    example, DosExecPgm() starts a child with its own local descriptor
    table. The parent and child, by default, do not share ANY memory
    segments. When OS/2 jumps into your signal handler, ss and sp are
    set to the stack segment defined for that handler during
    compile/link time.


 745. Starting Program in Maximized and/or Smaller Font Mode

 Question:

 How can I start a program in the maximized and/or smaller font
 (43-line) state? For example, I want to be able to start MEP from the
 Start Programs menu in OS/2 Presentation Manager (PM), and have it
 already maximized and in the smaller font. Currently, I have to start
 the editor, maximize it, and then set it to smaller font. I have set
 the MEP.EXE file to WINDOWCOMPAT using MARKEXE, and I have set the
 TOOLS.INI file so that MEP runs properly once set to the 43-line mode.

 Response:

 To change the default size of a VIO text window to a smaller font,
 press SHIFT+F (or press SHIFT and click the left mouse button on the
 Font menu-item) instead of just pressing F to select the Font
 menu-item. After that, every time you start a character application in
 a VIO window, it will come up in the default font size you selected.

 Although the PM shell does allow you to change the default font size
 of a VIO text window, there isn't any method to change the default
 maximum/minimum size of the text windows for the PM shell. However, if
 you don't mind an intermediate step, you can write an application that
 calls DosStartSession() to launch a character application in a
 full-size VIO window. You then need to set the SessionType field of
 the STARTDATA structure to the value of 2, and the PgmControl field of
 the STARTDATA structure to the value of 2.

 For example, the following values for the STARTDATA structure will
 launch the application QH.EXE, located in the C:\BINB subdirectory:

     STARTDATA   stdata;
     USHORT      usSID;
     USHORT      usPID;
     USHORT      usErr;

     stdata.Length      = sizeof( stdata );
     stdata.Related     = FALSE;              /* Independent session */
     stdata.FgBg        = TRUE;               /* Run in Background   */
     stdata.TraceOpt    = 0;                  /* No tracing          */
     stdata.PgmTitle    = NULL;
     stdata.PgmName     = "C:\\BINB\\QH.EXE";
     stdata.PgmInputs   = NULL;               /* No Parameters       */
     stdata.TermQ       = NULL;               /* Optional            */
     stdata.Environment = (PBYTE)1;           /* Parent PROCESS's
                                                  environment        */
     stdata.InheritOpt  = 1;                  /* Parent PROCESS's
                                                  environment        */
     stdata.SessionType = 2;                  /* VIO window session  */
     stdata.IconFile    = "";
     stdata.PgmHandle   = 0;
     stdata.PgmControl  = 2;                  /*  2 == maximize      */
     stdata.InitXPos    = 0;
     stdata.InitYPos    = 0;
     stdata.InitXSize   = 0;
     stdata.InitYSize   = 0;

     /* Try to launch a VIO maximized application */
     usErr = DosStartSession( &stdata, &usSID, &usPID );


 746. Symbolic Constants for KBDINFO Flags Missing from BSESUB.H

 Question:

 I have Version 1.20 of the Presentation Manager (PM) Toolkit and I am
 using the KbdSetStatus() function. Within this function, I use the
 KBDINFO structure. I pass the fsMask parameter to the KBDINFO
 structure. The flag set for fsMask is KEYBOARD_ECHO_ON. When I compile
 my application, I receive the error message "C2029 error,
 KEYBOARD_ECHO_ON; undefined." This same function worked properly with
 Version 1.10 of the PM Toolkit. Why won't it work with Version 1.20?

 Response:

 In Version 1.20 of the PM Toolkit, KEYBOARD_ECHO_ON and other symbolic
 constants for the KBDINFO masks were mistakenly omitted from the
 header file BSESUB.H.

 The following are two workarounds for this problem:

 1. Instead of using the symbolic constants for the KBDINFO masks, you
    can use the actual values that correspond to the KBDINFO symbolic
    constants. For example, instead of using the following assignment

       Kbdinfo.fsMask = KEYBOARD_ECHO_ON;

    you could use the following assignment:

       Kbdinfo.fsMask = 0x0001;        // KEYBOARD_ECHO_ON

    This solution has the negative side-effect that you are using
    hard-coded values in your code. Code that uses symbolic constants
    is generally more flexible and easier to maintain.

 2. Modify the header file BSESUB.H so that it includes all the
    symbolic constants for the KBDINFO masks that were inadvertently
    left out. This workaround to the problem is probably the best
    approach to take, but you might want to keep an unedited copy of
    the original file BSESUB.H for archival purposes. The symbolic
    constants for the KBDINFO masks are as follows:

     /* KBDINFO.fsMask */

     #define KEYBOARD_ECHO_ON                0x0001
     #define KEYBOARD_ECHO_OFF               0x0002
     #define KEYBOARD_BINARY_MODE            0x0004
     #define KEYBOARD_ASCII_MODE             0x0008
     #define KEYBOARD_MODIFY_STATE           0x0010
     #define KEYBOARD_MODIFY_INTERIM         0x0020
     #define KEYBOARD_MODIFY_TURNAROUND      0x0040
     #define KEYBOARD_2B_TURNAROUND          0x0080
     #define KEYBOARD_SHIFT_REPORT           0x0100


 747. DosMakeNmPipe() and Four Instances of Given Pipe Problem

 A problem has been found with the DosMakeNmPipe() function that occurs
 under the following circumstances. In a client-server application, if
 there are four instances of a given pipe, the client end can
 successfully open the pipe, perform transactions, and close the pipe.
 However, if the first instance of the pipe is closed and the server
 tries to execute the DosMakeNmPipe() function again, an error is
 incorrectly returned.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.

 The following is the pseudo (rough) code for the server program:

 while (1) {
         DosMakeNmPipe (...)
         if busy continue;

         DosConnectNmPipe (...)

         save handle in a 4 element table
         start a child process passing it the newly connected handle
 }

 The child process will subsequently perform all of the read/write
 transactions from/to the pipe, and upon completion it will execute a
 DosDisConnectNmPipe() call on its handle. Thus, the server just makes
 the pipes, and passes the handle to the child process, which actually
 performs the pipe read/write. The server then disconnects and closes
 the pipe, once the child process has been terminated.

 You can start four clients successfully. If you then close the first
 client program, this should result in one free instance of a pipe.
 However, if the server tries to make a DosMakeNmPipe() call, an error
 of ERROR_PIPE_BUSY is incorrectly returned.

 At this point, if the remaining three client programs are closed as
 well, the server can once again successfully make new pipes; that is,
 DosMakeNmPipe() does not return an error.


 748. DosQNmPipeInfo() Returns Incorrect Values in 1.20

 A problem has been found with the DosQNmPipeInfo() function that
 occurs under the following circumstances. In a client-server
 application, if there are four instances of a given pipe, the client
 end can successfully open the pipe, perform transactions, and close
 the pipe. However, on the server end, if you close one of the pipes
 and reopen it again, the number of pipes reported by DosQNmPipeInfo()
 is not correct.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.

 The following is the pseudo (rough) code for the server program:

 while (1) {
         DosMakeNmPipe (...)
         if busy continue;

         DosConnectNmPipe (...)

         save handle in a 4 element table
         start a child process passing it the newly connected handle
 }

 The child process will subsequently perform all of the read/write
 transactions from/to the pipe, and upon completion it will execute a
 DosDisConnectNmPipe() call on its handle. Thus, the server just makes
 the pipes, and passes the handle to the child process, which actually
 performs the pipe read/write transactions. The server then disconnects
 and closes the pipe, once the child has been terminated.

 After starting a client by using the DosQNmPipeHandle() call, the
 number of current pipe instances in use is 1. If you now close the
 client and start it again, the number of pipe instances in use is now
 2, and will never go back down to 1 again. This information was
 obtained by using the DosQNmPipeInfo() call.


 749. Executing Different .CMD File, Depending on Session Type

 Question:

 In my OS/2 CONFIG.SYS file, I have the following statement:

    PROTSHELL=C:\OS2\PMSHELL.EXE C:\OS2\OS2.INI
               C:\OS2\CMD.EXE /k c:\progs\cmd\os2init.cmd

 One of the side effects of this statement is to cause the command file
 OS2INIT.CMD to be run whenever a command processor is started up. This
 is true for both the full-screen and windowed command processors.

 However, I would like to run a different set of commands depending on
 whether the windowed command processor or the full-screen shell is
 being run. Can this be done?

 Response:

 Yes, this can be done, but not directly with an OS/2 command. You can
 write your OS2INIT.CMD file so that it runs a program that you have
 written that checks what type of session you are running in, and then
 returns an appropriate error level. Your .CMD file then can have an
 errorlevel check, and it can call whatever .CMD file you want to run,
 depending on the session type.

 The following example demonstrates this technique:

 OS2INIT.CMD
 -----------

 @echo off
 sesstype
 IF errorlevel 2
     fullscrn.cmd
 IF errorlevel 1
     windscrn.cmd

 SESSTYPE.EXE would be a WINDOWCOMPAT program that calls
 DosGetInfoSeg(), then looks at the value in the typeProcess field in
 the LINFOSEG structure to see what type of session it was started in.
 The program would then return the appropriate error code (2 if
 PT_FULLSCREEN and 1 if PT_WINDOWABLEVIO).

 An alternative way to do this is included in the Software/Data Library
 in a file named IFNOTWIN. IFNOTWIN contains two programs named
 IFWIN.EXE and IFNOTWIN.EXE. These sample programs run or do not run a
 command, based on whether it is running in a windowed session or not.

 To use IFWIN.EXE and IFNOTWIN.EXE for the example above, use the
 following commands in your OS2INIT.CMD file:

    @ifnotwin cmd.exe /c fullscrn.cmd
    @ifwin cmd.exe /c windscrn.cmd

 Currently, you are required to run CMD.EXE for internal commands, but
 you can change this if you want to.

 Because it is running a secondary copy of CMD.EXE, actions such as
 changing directories and setting the environment, if placed within
 FULLSCRN.CMD or WINDSCRN.CMD, will not remain in effect after IFNOTWIN
 or IFWIN completes, so you need to use the first method if you want to
 do those operations.

 IFNOTWIN can be found in the Software/Data Library by searching on the
 keyword IFNOTWIN, the Q number of this article, or S12555. IFNOTWIN
 was archived using the PKware file-compression utility.


 750. Incorrect Error Codes Listed for DosGetResource()

 Page 76 of the "Microsoft Operating System/2 Programmer's Reference
 Volume 3" for Version 1.10 lists the following return values for the
 DosGetResource() function:

    ERROR_CANT_FIND_RESOURCE
    ERROR_INVALID_MODULE

 However, ERROR_CANT_FIND_RESOURCE and ERROR_INVALID_MODULE are not
 defined in any of the .H files.

 After doing some testing, we found that the following error codes
 are returned instead. For the ERROR_CANT_FIND_RESOURCE error, if you
 ask for an invalid resource, DosGetResource() returns error code 87;
 which is defined in BSEERR.H as ERROR_INVALID_PARAMETER. For the
 ERROR_INVALID_MODULE error, if you ask for an invalid module,
 DosGetResource() returns error code 6, which is defined in BSEERR.H
 as ERROR_INVALID_HANDLE (which refers to the handle of the invalid
 module).

 Microsoft has confirmed this to be a problem in OS/2 Version 1.10. We
 are researching this problem and will post new information here as it
 becomes available.


 751. Improving Speed of Numeric Calculations in OS/2

 Question:

 A significant portion of our work using the C Compiler requires
 numeric (floating-point) calculations. The C Compiler has been
 installed with the Alternate Math Library. Is this the optimum
 configuration for our requirements? If it would increase performance,
 we could require a numeric coprocessor for use with our software.
 Alternatively, we could use the Emulator Library instead.

 Response:

 You are not using the optimum configuration, if by optimum you are
 referring to speed.

 For the fastest performance, you should require a numeric coprocessor
 used in conjunction with your own floating-point libraries. OS/2 will
 support multiple threads by saving their status during context
 switching through the numeric coprocessor. Of course, this means more
 work on your part.

 The second fastest performance can be obtained by using a C run-time
 library with an Emulator AND a numeric coprocessor. This is a more
 straightforward method. The Emulator will let the numeric coprocessor
 run if it exists, but it will run anyway even if the numeric
 coprocessor does not exist. Unfortunately, if a numeric coprocessor is
 not installed, this will produce the slowest performance. The Emulator
 is just as precise as the numeric coprocessor, but this precision
 costs you in speed. Also, if you use an Emulator, you cannot use
 LLIBCDLL.LIB because it only uses Alternate Math.

 The third fastest performance can be obtained by using Alternate Math.
 The Alternate Math Library is not as precise as the Emulator, but it
 is faster than an Emulator (one that is used without the numeric
 coprocessor) and it doesn't use a numeric coprocessor. Using Alternate
 Math allows you to use LLIBCDLL.LIB, if that's a requirement for you.

 In summary, the fastest performance can be obtained by using a numeric
 coprocessor with your own floating-point library. OS/2 will support
 multiple threads within the numeric coprocessor. The second fastest
 performance can be obtained by using an Emulator AND a numeric
 coprocessor. The third fastest performance can be obtained by using
 Alternate Math; it's faster than a stand-alone Emulator, but not as
 accurate. The fourth fastest performance can be obtained by using the
 Emulator without the numeric coprocessor. This option is very
 accurate, but you will sacrafice some speed.


 752. OS/2 Thread ID Numbers Are Reused

 Thread ID numbers within an OS/2 process are reused, as the example
 program included below demonstrates.

 This means that you need to do additional bookkeeping in an
 application that creates threads on an ongoing basis (as opposed to
 all threads being created at the start of your application), if your
 application needs to know when threads have died.

 Many applications do not need to know when threads die. The example
 listed below does not need to know this information.

 In the example included below, stack deallocation is not a problem,
 because each stack for the threads in the example is automatically
 deallocated by the _beginthread routine in the Microsoft C Compiler
 version 6.00 when the thread ID is reused. See Page 372 of the
 "Microsoft C 6.00 Advanced Programming Techniques" manual for more
 information on this topic.

 If you run the sample code listed below, the thread ID number in the
 example will always be 2.

 While stack deallocation is the most common reason to need to know
 when a thread has died, there can be other application dependent
 reasons.

 Stack deallocation may be a less important reason to need to know when
 a thread has died, now that the Microsoft C Compiler version 6.00
 performs stack checking on all threads created with _beginthread. See
 Page 379 of the "Microsoft C 6.00 Advanced Programming Techniques"
 manual for more information on this topic.

 Now that the Microsoft C Compiler version 6.00 performs stack checking
 on all threads created with _beginthread, it is convenient to let
 _beginthread both allocate and deallocate threads' stacks. Using the
 Microsoft C Compiler version 6.00, you won't need to use DosAllocSeg()
 to allocate thread stacks (to get GP fault protection against threads
 overflowing their stacks), unless you intend to run your .EXE with the
 Microsoft C Compiler's stack checking disabled.

 If your application creates all threads at start-up time, DosGetPrty()
 can be used to detect when a thread has died. DosGetPrty() returns an
 ERROR_INVALID_THREADID error when the thread has died.

 However, you might want to write an application where within a process
 you would do the following. Some threads would be created at start-up
 time, and some threads might die at any time. Also, still other
 threads might be created at any time. This sort of application cannot
 use DosGetPrty() to see if a thread has died, because by the time
 DosGetPrty() is called, another part of the application may have
 already reused the thread ID number.

 Under those conditions, to determine if a thread has died, you must
 devise a bookkeeping scheme such as the following. Have each thread
 indicate in a table that it is about to die; then, any part of your
 application that needs to create a thread will have to check this
 table just before creating the thread.

 If a thread has acknowledged it is about to die, do the DosGetPrty()
 call on that thread ID number. If this call to DosGetPrty() returns an
 ERROR_INVALID_THREADID error, you can assume that the thread actually
 died.

 However, if the call to DosGetPrty(), does not return an
 ERROR_INVALID_THREADID error, you can assume that the thread got
 interrupted sometime between the time it acknowledged that it was
 about to die, and before its _endthread routine had been completed.

 Sample Code
 -----------

 /* Compile with the Microsoft C Compiler version 6.00.
    Use PWB, and click on Multithreaded .EXE */

 #define   INCL_BASE
 #define   INCL_DOS
 #include  <os2.h>

 #include <process.h>
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>

 void tryThread(void *dummy)
 {
   TID       tid;
   PLINFOSEG Local;
   SEL       selGlobalSeg, selLocalSeg;

   DosGetInfoSeg(&selGlobalSeg,&selLocalSeg);
   Local = MAKEPLINFOSEG(selLocalSeg);
   tid=Local->tidCurrent;

   printf("\nI am thread tid=%2d\n",tid);

   _endthread();
 }

 void main(int argc,char *argv[])
 {
   #define MAXTHREADS     5
   #define STACKSIZE      4096

   TID    tidThreads[MAXTHREADS];
   USHORT rc;
   int    i;

   for (i=0; i<MAXTHREADS; i++) {
     tidThreads[i]=_beginthread(tryThread,NULL,STACKSIZE,NULL);
     printf("\n\rrc on _beginthread[%2d]=%2d",i+1,tidThreads[i]);

     /* give thread time to die */
     DosSleep(1000L);
     }
 }


 753. OS/2 Primary HPFS (or Other IFS) Partition Boot Process

 Listed below is a comparison of the boot process for both OS/2 FAT
 and Non-FAT partitions.

 A PC that boots from a primary FAT partition cannot read information
 from partitions that are managed by File System Drivers (FSDs) until
 their FSDs are loaded. For example, given a FAT partition on drive C:
 and an HPFS partition on drive D:, it is not possible to access data
 stored on drive D: until the following line from CONFIG.SYS is read
 and processed:

 	IFS=C:\OS2\HPFS.IFS

 A PC that boots from a primary FSD-managed partition can, on the other
 hand, gain limited access to that partition even before that
 partition's FSD is loaded. In this configuration, the boot sector
 loads a mini-FSD which has just enough functionality to allow it to
 scan the directory structure of the FSD-managed partition. The
 mini-FSD is then able to load the appropriate full FSD driver and turn
 over control to the full FSD driver.

 FAT Boot Process
 ================

 At the completion of the power-on-self-test (POST), Int 19h is
 executed and control is transferred to the reboot code. The BIOS' Int
 19h handler reads the boot sector from the disk into memory and
 transfers control to it.

 The boot sector contains a structure that describes the disk's
 parameters. It also contains code to read in the root directory, scan
 for OS2LDR, and read it into memory. Control is then passed to OS2LDR.

 OS2LDR contains the OS/2 loader. It performs some initialization,
 scans the root directory for OS2KRNL, and reads it into memory.
 Control is then passed to OS2KRNL.

 OS2KRNL contains the OS/2 kernel and initialization code. It scans the
 root directory and loads in the base device drivers and some required
 DLLs. It then loads the file and system drivers specified in
 CONFIG.SYS (for example, HPFS.IFS). Secondary nonboot FSD-managed
 volumes (such as the HPFS Drive D: in the above scenario) can now be
 accessed.

 All of the above directory scans and file loads are done with standard
 DOS calls and therefore go through the regular file system and device
 drivers.

 Non-FAT Boot Process
 ====================

 When a primary boot partition is formatted as an FSD-managed volume,
 special code is written to the hard disk's boot sector. At the
 completion of POST, the BIOS' Int 19h handler reads this "special
 code" from the boot sector into memory and transfers control to it.

 This special code is responsible for (among other things) establishing
 an image of the OS2LDR, OS2KRNL, and a "mini-FSD" in memory. Control
 is then passed to OS2LDR.

 OS2LDR performs its standard initialization routine, then passes
 control to OS2KRNL.

 OS2KRNL goes through an initialization routine similar to the FAT boot
 procedures, but with two important exceptions: the module loader is
 called to "load" the mini-FSD from its memory image in memory and the
 mini-FSD is called to read the base device drivers (one at a time)
 from the root directory.

 The required DLLs are then loaded via the mini-FSD, followed by the
 device and system drivers.

 The mini-FSD is required to support only a small number of the
 functions of an FSD. Therefore, the first FSD loaded must be the
 replacement for the mini-FSD.

 After the replacement, full FSD has been loaded (per the CONFIG.SYS IFS
 line(s) parameters), it is then told to initialize itself and take
 whatever action is necessary to effect a smooth transition from the
 mini-FSD to the FSD. The full FSD replaces the mini-FSD.

 From this point on, the system continues normally.


 754. SYS2070 Error Can Occur If OS/2 Executable Is Corrupted

 If an OS/2 executable (for example, PROGRAM.EXE) is invoked and the
 executable file is corrupted, the following OS/2 error can occur:

    ----------------------------------------------------------------------
    |   Session Title:                                                   |
    |   PROGRAM.EXE                                                      |
    |                                                                    |
    |      SYS2070: The system could not demand load the                 |
    |      application's segment.  PROGRAM is in error.                  |
    |      For additional detailed information also see message SYS0201. |
    |--------------------------------------------------------------------|
    |      End of program                                                |
    ----------------------------------------------------------------------

 The following is the help message for SYS0201, which is available by
 typing "HELP SYS0201":

    SYS0201:  The operating system cannot be run ***.

    EXPLANATION: The relocation-chain for a segment
    exceeds the segment limit.
    ACTION: Contact the supplier of the application
    program.

 This error message was observed when the executable file contained
 several blocks of 0xF6, where machine code should have been located.

 To correct this problem, obtain an uncorrupted version of the
 executable file.


 755. DosMakeNmPipe() Parameter Constant Documentation Error

 Microsoft has confirmed that the following documentation error occurs
 in the "Microsoft Operating System/2 Programmer's Reference Volume 3"
 for Version 1.10 on Pages 84-85 for the DosMakeNmPipe() function. On
 these pages, all of the constants should start with "NP" instead of
 "PIPE". For example:

    Use                      Instead of
    ---                      ----------

    NP_WAIT                  PIPE_WAIT
    NP_NOWAIT                PIPE_NOWAIT
    NP_READMODE_BYTE         PIPE_READMODE_BYTE
    NP_READMODE_MESSAGE      PIPE_READMODE_MESSAGE
    NP_TYPE_BYTE             PIPE_TYPE_BYTE
    NP_TYPE_MESSAGE          PIPE_TYPE_MESSAGE
    NP_UNLIMITED_INSTANCES   PIPE_UNLIMITED_INSTANCES
    NP_ACCESS_DUPLEX         PIPE_ACCESS_DUPLEX
    NP_ACCESS_INBOUND        PIPE_ACCESS_INBOUND
    NP_ACCESS_OUTBOUND       PIPE_ACCESS_OUTBOUND
    NP_INHERIT               PIPE_INHERIT
    NP_NOINHERIT             PIPE_NOINHERIT
    NP_NOWRITEBEHIND         PIPE_NOWRITEBEHIND
    NP_WRITEBEHIND           PIPE_WRITEBEHIND

 In BSEDOS.H, all of these constants start with "NP" instead of "PIPE".

 This error also occurs in the versions of QuickHelp included with the
 Version 1.10 OS/2 Software Development Kit (SDK), and the Version 1.20
 OS/2 Programmer's Toolkit.

 We will post new information when the documentation and QuickHelp have
 been updated to correct this error.


 756. Misleading Error Occurs If HPFS386 and HPFS Are Both Used

 When HPFS386 is included in CONFIG.SYS and an IFS statement for a
 normal HPFS follows, system error SYS1719 is returned stating that the
 file C:\OS2\HPFS.IFS is not a valid IFS. This error message is
 misleading.

 System error SYS1719, invalid device driver or file system driver, is
 not an inappropriate error message for the case where the loader
 encounters a conflicting file system driver. A more descriptive error
 message should be returned in this situation.

 This feature is under review and will be considered for inclusion in a
 future release.


 757. OS/2 SDK 1.10 Profiler Information

 Question:

 I have a question about the profiler included in the OS/2 Version 1.10
 Software Development Kit (SDK). What do the various return codes mean?
 In particular, I am getting an 8 from ProfInit(), and a 9 from
 ProfOff().

 Response:

 The error codes returned by the profiling APIs are the same as for the
 base Dos*() calls, and are defined in the BSEERR.H include file. Error
 code 8 is ERROR_NOT_ENOUGH_MEMORY, and error code 9 is
 ERROR_INVALID_BLOCK. The error code 9 on the ProfOff() call is
 probably happening because the ProfInit() call failed.

 When evaluating the cause of these memory errors, be aware that there
 is a limit on the size of the program that the profiler can profile.
 Therefore, it is possible that the system cannot find memory available
 if your application is large and/or your machine is short on available
 RAM.

 The profiler works in the following manner. For every code segment
 that your application has, a corresponding and equal sized data
 segment is allocated. The clock interrupt is then hooked. For every
 clock tick that comes in, the DS value is examined. If it belongs to
 the application being profiled, a DWORD value in the data segment
 corresponding to the code segment is incremented, based at an offset
 into the data segment that corresponds to the offset into the code
 segment. After incrementing the value, the clock interrupt handler
 returns control back to the system.

 Please note that because the data segment is updated at interrupt
 time, it MUST be present in memory at all times. This means that it
 cannot be swapped out. Consequently, the memory requirements for
 profiling an application are much larger than just running the
 application without profiling. Moreover, for every code segment in
 your application, there is also going to be an additional LDT slot
 used to allocate the corresponding data segment. Therefore, you could
 potentially run out of selectors, and an out of memory error may occur
 for this reason.


 758. New DosWaitNmPipe() NP_INDEFINITE and NP_DEFAULT Values

 Question:

 The DosWaitNmPipe() function parameters NP_INDEFINITE and NP_DEFAULT
 are described in the documentation, but they do not exist in any of
 the files in \OS2TOOLS\INCLUDE. What are their values?

 Response:

 NP_INDEFINITE and NP_DEFAULT have the following values:

    NP_INDEFINITE_WAIT = -1
    NP_DEFAULT_WAIT = 0

 You are correct; these values should be included in one of the include
 files.

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 759. OS/2 SDK: Alignment of Memory in DMA Transfer

 Question:

 I need to write a routine to transfer data from an I/O adapter card
 into memory using DMA. My requirements dictate that the routine be
 fast; therefore, I intend to write it in assembly. In addition, the
 routine must be callable from a C program, and it must accept as an
 argument a pointer to a buffer defined in the C program. I have the
 following questions about how to implement this type of functionality:

 1. Can this routine run at Ring 3 as part of my application, or do I
    have to write a device driver?

 2. The DMA operation needs to know the physical address of the
    destination memory. How does the assembly code find out the address
    of the array?

 3. The data to be transferred could be larger than 64K. Will DMA still
    work if the data has to cross a segment boundary?

 Response:

 The answers to the above questions are as follows:

 1. Your DMA transfer routine must be part of a device driver for the
    following reasons:

    a. To use DMA, your destination buffer must be aligned on 64K
       boundaries. However, a Ring 2 or Ring 3 process has no control
       over the alignment of memory. Processes running at Rings 2 or 3
       can only use the kernel's virtual memory management calls, and
       these calls cannot assure you that this boundary condition will
       be met (most likely it will not be met). A device driver, on the
       other hand, runs at Ring 0 and is capable of controlling memory
       alignment.

    b. To perform a DMA transfer to a buffer, you need to lock down the
       segment containing the destination buffer. If you did not lock
       down the DMA transfer segment, it could get swapped out by the
       kernel's virtual memory manager. The consequences of this would
       be the delay or corruption of the DMA transfer. The only way to
       lock down segments in memory is from a device driver.

 2. If you have written a device driver to handle these DMA transfers,
    as recommended above, the answer to this question is fairly
    straightforward. An outline of the necessary steps you need to
    perform is listed below:

    Application
    -----------

    *  Perform a DosOpen() call on your device driver.

    *  Do a DosRead() call on the returned handle, passing the address
       of your transfer buffer as a normal part of the DosRead() call.

    Device Driver Routine
    ---------------------

    *  Upon receipt of the READ request packet, directly reference the
       buffer address contained in the READ request packet.

       Note: When your device driver receives the READ request packet,
       the OS/2 kernel will have already (and automatically) locked
       down the segment containing the buffer address. The kernel will
       also have inserted a 32-bit physical address into your transfer
       buffer (into the READ request packet).

 3. Data transfers of more than 64K must first be broken up into blocks
    of less than or equal to 64K bytes, and then transferred using
    multiple DMA requests. This is really a hardware restriction, not a
    limitation of OS/2. The standard 8237A DMA Controller used in
    AT-class machines is basically just a 16-bit device. That is, it
    can only address up to 64K at a time.

    An easy way to accomplish this in a device driver is to use the
    AllocReqPacket() and PushReqPacket() DevHlps to effectively send
    yourself as many request packets as needed to complete a large
    (more than 64K) data transfer.


 760. Named-Pipe Functions QuickHelp Documentation Error

 In QuickHelp, the entry for "Named-Pipe Functions" that is under the
 "OS/2 API" category does not take you to the listing for named pipes.
 The following steps can be used to reproduce this problem:

 1. Select the "OS/2 API" category.

 2. Select "Function Groups."

 3. Select "Named-Pipe Functions."

 A list of Clipboard functions is incorrectly displayed.

 Microsoft has confirmed this to be a problem in the version of
 QuickHelp included with OS/2 Version 1.20. We are researching this
 problem and will post new information here as it becomes available.


 761. Obtaining Instance of Pipe over Network

 Question:

 Given a single instance of a pipe on a server, and several clients on
 independent workstations, is there any synchronization of the
 DosWaitNmPipe() call, or can a client be (theoretically) frozen out of
 access to this pipe forever by (luckier) competing clients?

 Response:

 Suppose a number of clients are waiting for an instance of a pipe to
 become free by making a DosWaitNmPipe() call. If an instance of a
 pipe becomes available, the (client) process with the highest
 priority gets this instance of the pipe. If two (client) processes
 have the same priority, the (client) process that has been
 waiting the longest gets the instance of the pipe.

 The behavior is the same over a network. The client (through the
 redirector) passes the request [DosWaitNmPipe()] to a server, which
 basically implements the same strategy for giving instances of a pipe
 to waiting (remote or local) pipes. For remote client cases, the
 client process, which first makes a DosWaitNmPipe() call and gets to
 the server first, will get the first available instance of the pipe.


 762. DosMonReg() Returns Incorrect Error Code in 1.20

 If you create a monitor and the buffers are too small, DosMonReg()
 will return an incorrect error code of ERROR_NOT_ENOUGH_MEMORY (error
 code 8). DosMonReg() should return the correct error code of
 ERROR_MON_BUFFER_TOO_SMALL (error code 382).

 Microsoft has confirmed this to be a problem in Version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 763. File Manager Program Name Filters Aren't Case Sensitive

 Case sensitivity does not work properly in the File Manager when used
 with program name filters. For example, a *.TXT filter does not work
 properly with a file using lowercase letters, as in *.txt. The icon
 will not display under the File Manager, although the application will
 run when the file is double-clicked.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 764. AMI Keyboard BIOS Compatibility Problems with OS/2 1.20

 Using the updated release of OS/2 version 1.20 from IBM, you may
 encounter various problems while using the File Manager. These
 problems include spurious "too many directory windows open" error
 messages (when only one directory window was open), "filename too
 long" error messages (even while opening windows on a FAT volume), and
 many other problems.

 One workaround to these problems is to use the original version 1.20
 HPFS.IFS file. However, these problems are due to incompatibility
 problems with OS/2 version 1.20 and the AMI keyboard BIOS.

 The AMI BIOS (known as the "K8" BIOS), which works properly with
 MS-DOS, seems to cause a number of problems under the most recent
 release of OS/2 Version 1.20. AMI has an updated BIOS, called the "KD"
 BIOS, which resolves these problems.

 Another problem that is also resolved by the updated BIOS is the more
 well-known problem of the extended cursor controls not working under
 Presentation Manager (PM). The cursor keys work properly in the
 character-mode windows and in the compatibility box, but not under PM.
 Upgrading the keyboard BIOS solves this problem as well as the file
 system problems.


 765. Protection Fault Occurs If Entry Field Overflows in QuickHelp

 QuickHelp (QH) version 1.60 causes a protection fault when a text entry
 field overflows. The following steps can be used to reproduce this
 problem:

 1. Choose Rename Paste File from the File menu.

 2. Type random characters until the cursor reaches the end of the
    entry field and QuickHelp starts beeping.

 3. Press the HOME key to move to the start of the entry field.

 4. Press the INS key.

 5. Type characters again until QuickHelp stops accepting characters.
    The text will overflow the entry field. If the cursor reaches the
    end of the entry field before QuickHelp stops accepting characters,
    press the HOME key and repeat this step.

 6. Press the ENTER key. A protection violation will occur.

 Microsoft has confirmed this to be a problem in version 1.60 of
 QuickHelp included with the version 1.20 Presentation Manager (PM)
 Toolkit. We are researching this problem and will post new information
 here as it becomes available.


 766. System Can Hang in OS/2 1.10 If VioPrtSc() Has Been Replaced

 Problem:

 We are having problems when attempting to register a replacement for
 the VioPrtSc() function in OS/2. The replacement is successfully
 registered, and under normal circumstances works correctly, but if the
 PRINT SCREEN key is pressed repeatedly, the machine eventually hangs
 up completely. As far as we can tell, by using the Presentation
 Manager (PM) Developer's Kit Process Status utility, registering a
 replacement for this function causes a separate thread of the process
 to be launched, which presumably waits on a semaphore that is cleared
 by the Task Manager (or something else) when the PRINT SCREEN key is
 pressed. The machine seems to hang when the PRINT SCREEN key is pressed
 while this secondary thread is running.

 Response:

 Microsoft has confirmed this to be a problem in OS/2 versions 1.10 and
 1.20. We are researching this problem and will post new information
 here as it becomes available.

 There is a workaround to this problem, but unfortunately the
 workaround does not work under version 1.10.

 You are correct that the system creates a special thread if you
 register a replacement for the VioPrtSc() or VioPrtScToggle()
 functions via the VioRegister() function. This thread is created only
 for these two replacement routines. This thread is blocked by the
 system until you press the PRINT SCREEN key, at which time Thread 2 of
 HARDERR.EXE does some processing in preparation to printing the
 screen, then unblocks this special thread (that belongs to your
 application) to execute the replacement routine(s) that you registered
 with VioRegister(). This thread has a rather small stack of 512 bytes
 that is created by the system at the time you register your
 replacement routine with VioRegister().

 When you create a replacement VIO routine entry-point handler that
 will be registered with VioRegister(), you must set this routine up in
 a certain way. First of all, it must be declared as shown in the
 documentation for VioRegister() in the "Microsoft Operating System/2
 Programmer's Reference Volume 3" for version 1.10. This entry-point
 function must NOT be of type PASCAL. This is critical!

 Another critical requirement is that the entry-point function must
 save the state of the CPU registers when it enters and restore them
 when it leaves. This can be done in C with the _saveregs function
 modifier; see the C compiler version 5.10 update section for more
 information on this topic. As stated in the documentation for
 VioRegister(), the stack must be left in its original state when
 returning from the entry-point function. If this entry-point function
 is written in C, this will be done for you.

 In the Software/Data Library is a file named PRTSCR that contains a
 sample application with an entry-point function that shows how to
 accomplish these tasks in Assembler. This function can be easily
 adapted to handle one or more different functions registered with
 VioRegister().

 PRTSCR can be found in the Software/Data Library by searching on the
 filename, the Q number of this article, or S12603. PRTSCR was archived
 with the PKware file-compression utility.

 Notes
 -----

 After the system calls into your entry-point function with the thread
 created by the system when you register either VioPrtSc() or
 VioPrtScToggle() via VioRegister(), on return to the system, it does
 not clean up the stack of the thread that was created. This means that
 the stack is shrunk by six USHORT parameters (12 bytes) with each call
 into your entry-point routine. With the small stack that the system
 creates for this thread (512 bytes), after about 36 calls (PRINT
 SCREEN key presses), the system will crash.

 Also, if you press the PRINT SCREEN key very quickly, it will only
 take a few presses of the key before this small stack will underflow,
 and the system will crash. Please note that this only happens if you
 register for a replacement for VioPrtSc() or VioPrtScToggle(). These
 are the only two routines the system creates a special thread for. If
 you register any other VIO routine, the stack is cleaned off correctly
 by the system VIO router after calling your entry-point function.

 If you have the version 1.20 OS/2 SDK, with a debug kernel version
 before 12.177, you can use the following temporary workaround. If you
 pop those 12 bytes in your entry-point function, which you are not
 supposed to do according to the documentation, the stack will be
 cleaned off "before" you return to the system VIO router, and
 everything will function correctly.

 However, there are some special considerations. Doing this means that
 a routine written to replace the VioPrtSc() and/or VioPrtScToggle()
 functions must be written in Assembler, since the stack must be set up
 C-style, but the stack must be cleaned up in the callee (your
 entry-point function), which C will not do. Furthermore, you must put
 some special coding in your entry-point routine to decide when you
 need to do this special stack cleanup. You can easily look at the
 "fFunction" parameter (accessed by [bp].s_indx in the sample code) to
 determine whether this is a VioPrtSc() or VioPrtScToggle() call, and
 if it is, then do a "ret 12"; otherwise, do a regular "ret" when
 returning from your entry-point routine, and things should work
 correctly.

 When this problem is corrected, this extra stack popping will cause
 problems in the corrected version. Since you can have only one
 VioRegister() call outstanding, you will have a problem. However, this
 would probably be a relatively simple thing to distribute a patch for.


 767. DosSetSigHandler() pfnPrev Parameter Documentation Error

 On Page 146 of the "Microsoft Operating System/2 Programmer's
 Reference Volume 3" for version 1.10, and in QuickHelp included with
 OS/2 versions 1.10 and 1.20, it incorrectly states the following for
 the DosSetSigHandler() function:

    USHORT DosSetSigHandler(pfnSigHandler, pfnPrev, [...])
    PFNSIGHANDLER pfnSigHandler; /* pointer to signal-handler function */
    PFNSIGHANDLER FAR *pfnPrev;  /* pointer to previous handler address */

 In the first and third lines there is a documentation error: "pfnPrev"
 should be replaced with "ppfnPrev".

 Microsoft has confirmed this to be a problem in the printed
 documentation and in QuickHelp for OS/2 versions 1.10 and 1.20. We are
 researching this problem and will post new information here when both
 of these references have been updated to correct this error.


 768. System Hangs If Message Is Larger Than Length of Named Pipe

 When a client process tries to write a message larger than the length
 of a named pipe, and the server process is waiting for a semaphore
 associated to this pipe, the message is split into two pieces. The
 first piece of the message fills the pipe buffer, and the client hangs
 on the WRITE because the end of the message cannot be written. On the
 other hand, the server always waits for the semaphore because the
 message has not been completely written. The operating system should
 unlock the semaphore associated to the named pipe when the pipe is
 full, and not only when the entire message has been received.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 769. Message File Not Found If DPATH Is Set to Invalid Drive

 The DPATH variable is not searched completely if an invalid drive is
 entered in the DPATH variable. After booting the system, if an invalid
 drive is entered in the DPATH variable, the following error message
 occurs:

    SYS0319: The system cannot read the message file:OSO001.MSG

 For some reason, DPATH is not searched after encountering the invalid
 drive.

 On a system with only a Drive C partition, this problem can be
 reproduced by changing the DPATH variable to the following:

    SET PATH=C:\OS2;D:\TEST;C:\OS2\SYSTEM;C:\OS2\INSTALL;C:\;

 If you then reboot the system, the error message listed above is
 displayed because the VDISK and COM01 device drivers are trying to get
 their messages from the OSO001.MSG message file. If you type DPATH
 from the command line, DPATH is set up correctly, but any time you do
 something that requires a message from the OSO001.MSG message file, it
 can't be found.

 You can get the same behavior without having to change the CONFIG.SYS
 file. Simply change the DPATH variable from CMD.EXE.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 770. System Hangs If DosWaitNmPipe() Is Called and Pipe Is Broken

 If a process uses the system call DosWaitNmPipe() call, that process
 will wait forever if the pipe is broken (for example, if the other
 process has been killed by a CTRL+C).

 In this situation, the waiting process should be awakened by the
 operating system, even if the SEM_INDEFINITE_WAIT option has been
 selected in the DosWaitNmPipe() call.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 771. Updating a DLL While a Program Is Still Using the DLL

 Question:

 How can I update a dynamic linked library (DLL) while a program that
 uses this same DLL is still running? We tried to do this under OS/2 by
 loading the DLL, freeing the DLL, modifying, and then reloading the
 DLL, but the change is not reflected. OS/2 still seems to think the
 DLL is in use even after calling DosFreeModule().

 Response:

 You need to check the return code from DosFreeModule(). If the return
 code is error 12, some part of the DLL is needed by an exitlist
 routine. If you do not get an error, the DLL must be being used by
 some other process.


 772. Using System Error Messages with DosGetMessage() in a Program

 Question:

 I would like to use the system error messages in my program. For
 example, if DosFindFirst() returns 15, I want to return the following
 error message to the user:

    SYS0015: The system cannot find the drive specified.

 For my own messages, I can use DosGetMessage() and DosPutMessage()
 with my message file. For the system messages, should I use
 DosGetMessage() with the message filename hard-coded to OSO001.MSG?

 Response:

 Yes, this is the correct way to perform this type of functionality.
 This is how the system does it. If you give the name "OSO001.MSG", the
 system will search for OSO001.MSG on the DPATH variable. OSO001.MSG is
 set up to be on the DPATH variable by default, so you can always find
 it.


 773. Processing Data Returned from DosQNmPipeSemState()

 DosQNmPipeSemState() returns information in the form of PIPESEMSTATE
 structures. In earlier releases, these structures were named "npss".
 The following questions are frequently asked involving these
 structures:

 1. How much space do you have to pass to DosQNmPipeSemState() to hold
    the PIPESEMSTATE structures returned?

    You can set the variable "pipes" to the number of pipes associated
    with the semaphore you pass to DosQNmPipeSemState(), and then use
    the following statement to calculate the buffer size:

       USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);

 2. In what order does DosQNmPipeSemState() return the PIPESEMSTATE
    structures?

    Your application cannot safely make any assumptions about the order
    returned, because the order is not specified. Since the order is
    not specified, the order may change; therefore, do not rely on any
    order that you may see in the current releases of OS/2.

 Further information regarding the above questions is listed below.

 The long answer to question 1 is listed below:

 More detailed information regarding the above questions is as follows:

 1. [How much space do you have to pass to DosQNmPipeSemState() to hold
    the PIPESEMSTATE structures returned?]

    OS/2 does not allocate any space to hold PIPESEMSTATE structures.
    Each time you call DosQNmPipeSemState(), OS/2 looks at each named
    pipe currently associated with the semaphore you passed to
    DosQNmPipeSemState(), and builds the PIPESEMSTATE structures in the
    buffer you passed to DosQNmPipeSemState().

    In other words, each time you call DosQNmPipeSemState(), OS/2
    builds the PIPESEMSTATE structures "on the fly" into the buffer you
    pass.

    If the buffer you pass to DosQNmPipeSemState() isn't big enough to
    hold all the PIPESEMSTATE structures that OS/2 might have returned,
    OS/2 just stops building PIPESEMSTATE structures into your buffer,
    and returns to you the ones it was able to build before your buffer
    filled up.

    Although you can check the DosQNmPipeSemState() return code to see
    whether the buffer you passed was too small, the only practical
    approach to use is to pass DosQNmPipeSemState() a buffer you know
    in advance will be big enough to hold all of the structures.

    The reason for this is that if your buffer is too small, you may
    have been returned no PIPESEMSTATE structures at all for some of
    the named pipes associated with the semaphore.

    If the return code from DosQNmPipeSemState() states that your
    buffer was too small, you cannot call DosQNmPipeSemState() again
    with the same size buffer to get the rest of the PIPESEMSTATE
    structures that wouldn't fit in your buffer on the previous call.
    You can, of course, make as many calls as you want, it's just that
    subsequent calls don't get "the rest of the PIPESEMSTATE
    structures"; subsequent calls build complete new lists of
    PIPESEMSTATE structures.

    If you try to get "the rest of the PIPESEMSTATE structures,"
    DosQNmPipeSemState() will again build PIPESEMSTATE structures on
    the fly into your buffer, and will probably again return you no
    PIPESEMSTATE structures at all for the same named pipes associated
    with the semaphore for which it returned you no PIPESEMSTATE
    structures the first time you called DosQNmPipeSemState().

    This is because DosQNmPipeSemState() builds PIPESEMSTATE structures
    into your buffer on the fly, and DosQNmPipeSemState() keeps no
    records of what named pipes were previously successfully queried.

    Therefore, it's fine to call again if the return code states that
    your buffer was too small; however, you should understand that the
    second call will behave as if the first call had not been made.

    For some other OS/2 APIs, a practical approach to use is to make
    the call with a buffer that you know is too small, and have the API
    return to you how much data was available (total). You then can
    allocate a buffer of that size, and make the call again. This
    approach allows you to allocate a buffer not one byte larger than
    is needed for those other APIs. This approach, however, does not
    work for DosQNmPipeSemState(), because DosQNmPipeSemState() gives
    no indication of how much data is available.

    Fortunately, the approach mentioned above as "the only practical
    approach" for DosQNmPipeSemState() is both easy and cheap enough
    for most applications.

    Allocating a buffer you know in advance is big enough costs about
    18 bytes per pipe associated with the semaphore, because the
    PIPESEMSTATE structures are only 6 bytes long, and you need to
    allocate three of them per pipe.

    As mentioned above, just set the variable "pipes" to the number of
    pipes associated with the semaphore you pass to
    DosQNmPipeSemState(), then use the following statement to calculate
    the buffer size:

       USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);

    This allocates space for three PIPESEMSTATE structures per pipe
    associated with the semaphore, plus space for one PIPESEMSTATE
    structure for the NPSS_EOI (end of information) structure that is
    always returned at the end of your buffer.

    The reason you need to allocate three PIPESEMSTATES structures per
    pipe is that at most, DosQNmPipeSemState() will return for each
    pipe associated with the semaphore one NPSS_RDATA, one NPSS_WSPACE,
    and one NPSS_CLOSE PIPESEMSTATE structure.

    NPSS_RDATA, NPSS_WSPACE, and NPSS_CLOSE are defined in BSEDOS.H.
    The following is an extract from BSEDOS.H for your convenience:

       #define NPSS_EOI         0 /* End Of Information    */
       #define NPSS_RDATA       1 /* read data available   */
       #define NPSS_WSPACE      2 /* write space available */
       #define NPSS_CLOSE       3 /* pipe in CLOSING state */

    For some applications, you might be able to get by with a little
    less than ((3*pipes)+1)*sizeof(PIPESEMSTATE) because you know at a
    certain point that there can't be any data to read in a certain
    pipe, or there can't be any write space available, or the pipe
    can't be closing.

    However, please remember that you shave off only 6 bytes per
    PIPESEMSTATE structure you don't allocate. In most cases, shaving
    off only 6 bytes is not worth the risk that the buffer you pass
    will be too small.

    It is not recommended that you attempt to save 5 bytes by only
    allocating 1 byte in your buffer for the NPSS_EOI structure instead
    of the full 6. This may work in some releases of OS/2, but the
    specified behavior is that the NPSS_EOI structure is a PIPESEMSTATE
    structure, so you should allocate the same space for it as you
    would for the other structures.

    To summarize the information for Question 1: the recommended
    approach is to use the following statement to calculate your buffer
    size:

       USHORT PipeInfoSize=((3*pipes)+1)*sizeof(PIPESEMSTATE);

    It is not recommended that you try to get by with less, because the
    risks outweigh the number of bytes you might save.

 2. [In what order does DosQNmPipeSemState() return the PIPESEMSTATE
    structures?]

    There is no specific order regarding the order in which
    DosQNmPipeSemState() must return the PIPESEMSTATE structures in
    your buffer.

    Therefore, your application should not make any assumptions about
    the order of these structures.

    You may have noticed that the current releases of OS/2 return the
    PIPESEMSTATE structures in the following order:

       NPSS_CLOSE    (optional)
       NPSS_WSPACE   (optional)
       NPSS_RDATA    (optional)

    The NPSS_CLOSE structure comes first for a given pipe, if the pipe
    is closing, followed by the NPSS_WSPACE structure if there is write
    space available for that same given pipe, followed by the
    NPSS_RDATA structure, if that same given pipe has any read data
    available. Then, more PIPESEMSTATE structures follow in the same
    order for any other pipes associated with the semaphore.

    It is not safe to assume that this type of ordering scheme will
    continue to be used in all future releases of OS/2. Your
    application should process the PIPESEMSTATE structures returned in
    your buffer in such a way that any order in which you need to see
    the PIPESEMSTATE structures is guaranteed by the way you process
    your buffer.

    For example, let's say you want to see any NPSS_CLOSE structures
    first. You then can record the fact that a pipe is closing, so
    you'll know, when later processing the NPSS_RDATA structure, that
    the pipe is closing; therefore, trying to write to it won't work.
    Similarly, you might want to see any NPSS_WSPACE structures before
    the NPSS_RDATA structures, so you will need to know ahead of time
    how much you can write into the pipe in response to the NPSS_RDATA
    structures.

    Please note that the sample ordering in the preceding paragraph
    seems to be one of the most practical orderings, and also happens
    to be the ordering that current releases of OS/2 seem to provide.

    Nevertheless, rather than relying on the fact that current releases
    of OS/2 seem to provide exactly that order, if that's the order you
    need you should write your code so that order will happen even if
    OS/2 changes in the future.

    Fortunately, this is easy to do. You just need to loop twice
    through the buffer returned. In the first loop, look for and record
    any NPSS_WSPACE and/or NPSS_CLOSE structures. Then, in the second
    loop, look for and process any NPSS_RDATA structures.

    Guaranteeing this order in your code costs an extra loop, and a
    place to record for each pipe whether it's closing and how much
    write space is available. For applications where
    DosQNmPipeSemState() returns extremely long lists of PIPESEMSTATE
    structures, you might use a different approach. For example, you
    might loop through the buffer returned just once, recording the
    NPSS_RDATA structures along with the NPSS_WSPACE and/or NPSS_CLOSE
    structures. Then in the second loop, loop through your array of
    pipes (instead of a second loop through the buffer).

    To summarize the answer to Question 2: You shouldn't rely on the
    order in which current releases of OS/2 happen to return the
    PIPESEMSTATE structures. You should write your own code (as in the
    example below) to explicitly process the PIPESEMSTATE structures in
    the order your applications require.

    // Your application might not need this first resetting loop. In
    //  fact, this first resetting loop may be wrong for some
    //  applications.
    for (i = 0; i < pipes; i++) {
      hPipes[i].usWriteSpace = 0;
      hPipes[i].bClosing     = FALSE;
      }
    for (pInfo = PipeInfo; NPSS_EOI != pInfo->fStatus; pInfo++) {
      if      (NPSS_WSPACE == pInfo->fStatus)
        hPipes[pInfo->usKey].usWriteSpace = pInfo->usAvail;
      else if (NPSS_CLOSE  == pInfo->fStatus)
        hPipes[pInfo->usKey].bClosing     = TRUE;
      }
    for (pInfo = PipeInfo; NPSS_EOI != pInfo->fStatus; pInfo++) {
      if (NPSS_RDATA==pInfo->fStatus) {
       hPipes[pInfo->usKey].pData=malloc(pInfo->usAvail);

        rc=DosRead(hPipes[pInfo->usKey].hP,hPipes[pInfo->usKey].pData
                  ,pInfo->usAvail,&uReadBytes);
        if (0!=rc)
          printf("\n\rRead error: rc=%d",rc);
        else {
          printf("\n\rJust read: %s",hPipes[pInfo->usKey].pData);
          if      (hPipes[pInfo->usKey].bClosing) {
            printf("\n\rCan't write, pipe's closed");
            }
          else if (hPipes[pInfo->usKey].usWriteSpace <= 0) {
            printf("\n\rCan't write, no space available");
            }
          else {
            // For this example, ignore the possibility that some
            //  write space might not be enough.
            // For this example, just write back the message received.
            rc=DosWrite(hPipes[pInfo->usKey].hP
                       ,hPipes[pInfo->usKey].pData
                       ,(strlen(hPipes[pInfo->usKey].pData)+1)
                       ,&uWriteBytes);
            if (0!=rc)
               printf("\n\rWrite error: rc=%d",rc);
            }
          }
        free(hPipes[pInfo->usKey].pData);
        }
      }


 774. IFS and FSD Information

 Listed below is information about the installable file system (IFS)
 and the file system driver (FSD).

 A default (built-in) file system is a type of software that supports
 the storing of information on a device. An installable file system
 (IFS) is a file system whose software is used as an alternative to the
 default file system, and can be activated/installed when the operating
 system boots up. The IFS can be thought of as a user-defined file
 system, or an alternative to the file allocation table (FAT) file
 system.

 Basically, an IFS consists of the following: a file system driver
 (FSD), which manages the flow of information to the device, and a
 device driver, which accesses the device. The FSD is technically a
 device driver; that is, it runs at ring 0 with the same authority as a
 device driver. However, an FSD is different than a device driver in
 that a device driver is a device helper, and an FSD is a file helper.
 The FSD falls into a new logical category of its own.

 OS/2 will allow multiple file systems to be active at the same time in
 different partitions of your disk. For example, you can have a high
 performance file system (HPFS), an IFS, on Drive C; and you can also
 have FAT on Drive D. You activate/install the IFS with various
 commands in your CONFIG.SYS file. The IFS command names the file
 system, and the DEVICE command names the driver.

 Installable file systems are only supported by OS/2 versions 1.20 and
 later. Currently, the only IFS available is the HPFS. However, an IFS
 for CD-ROM will be available in the future.


 775. Giving DLL Function Access to an Entry Point in Your Program

 Question:

 Can I give a function in a dynamic linked library (DLL) access to an
 entry point in my application? If so, how can this be done?

 Response:

 Yes, it is possible to give a DLL function access to an entry point
 into your application. This technique commonly is called a "callback"
 routine. Basically, you pass the DLL function a pointer to the desired
 function within your application. Please note that the name of the
 function is a pointer to that function. Listed below is an example of
 a small application and a small DLL, along with their .DEF files,
 which perform a callback.

 DLLTEST.C
  ***********************************************************************
  *#include <stdio.h>                                                   *
  *#include <os2def.h>  /* for '#define EXPENTRY pascal far _loadds' */ *
  *typedef int (far pascal *FARPROC)(); /* far pointer to an int        *
  *                                         procedure */                *
  *                                                                     *
  *int far pascal myfunc(FARPROC foo, int b);                           *
  *int EXPENTRY Three(void);                                            *
  *                                                                     *
  *void main()                                                          *
  *{                                                                    *
  *   printf("Calling MyFunc\n\n");                                     *
  *   printf("  . . . it returns the value %d\n", myfunc(Three, 6));    *
  *   printf("Everything is done correctly.\n\n");                      *
  *}                                                                    *
  *                                                                     *
  *int EXPENTRY Three(void)                                             *
  *{                                                                    *
  *  return (3);                                                        *
  *}                                                                    *
  ***********************************************************************

 In DLLTEST.C, the application calls on a function from a DLL called
 MYFUNC(). MYFUNC() is sent Three, which is a far pointer to a
 procedure (in this case, a Pascal convention procedure, because it is
 slightly faster). Please note that Three() is a function in this
 application that is declared as an EXPENTRY. EXPENTRY is a Pascal "far
 _loadds", which basically makes Three() visible to other modules
 outside the application.

 DLLTEST.DEF
  ***********************************************************************
  *NAME        DLLTEST                                                  *
  *PROTMODE                                                             *
  *STACKSIZE   4096                                                     *
  *IMPORTS                                                              *
  *            CDLL.MYFUNC                                              *
  ***********************************************************************

 Please note that in DLLTEST.DEF, the function MYFUNC is imported from
 CDLL.DLL.

 CDLL.DLL
  ***********************************************************************
  *int _acrtused = 0;     /* don't link startup */                      *
  *                                                                     *
  *typedef int (far pascal *FARPROC)(); /* far pointer to a procedure */*
  *                                                                     *
  *int far pascal MYFUNC(FARPROC foo, int b)                            *
  *{                                                                    *
  *    return(foo()+b);          /* return function result */           *
  *}                                                                    *
  ***********************************************************************

 In CDLL.DLL, MYFUNC is a procedure that takes a far pointer to a
 procedure [Three()], and adds the results of a call to that procedure
 to the integer b. In this case, foo is pointing to Three(), the
 function in the application named DLLTEST.

 CDLL.DEF
  ***********************************************************************
  *LIBRARY CDLL INITINSTANCE                                            *
  *PROTMODE                                                             *
  *CODE LOADONCALL                                                      *
  *DATA LOADONCALL NONSHARED                                            *
  *EXPORTS                                                              *
  *     MYFUNC                                                          *
  ***********************************************************************

 CDLL.DEF is a simple DLL .DEF file. It exports MYFUNC so that it can
 be called by the application. Please note that it does not import
 anything from the application to do a callback.

 The following information summarizes the most important points of the
 above example. For the DLL to gain access to an entry point inside the
 application, a function within the DLL must be passed a pointer to the
 entry point in the application. That pointer (Three) must be declared
 as a far pointer to a procedure. The function itself [Three()] must be
 declared as a "far _loadds" so that it may be seen outside the
 application. The function within the application is not exported from
 the application's .DEF file. The function within main does not have to
 be imported into the DLL. In fact, importing the function into the DLL
 destroys the whole purpose of the DLL, because it ties the DLL to that
 specific application.


 776. Use of BOOT/DOS Produces SYS1731 Error Message in OS/2 1.20

 If you use either of the following commands, a SYS1731 error message
 will be incorrectly displayed.

    boot/dos

 or

    echo y | boot /dos

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 777. Use of OS/2 EXTDSKDD.SYS Produces Nonstandard Formatted Disk

 Question:

 When specifying the following line to use the internal floppy disk
 drive as 2DD format in the CONFIG.SYS file

      DEVICE=C:\OS2\EXTDSKDD.SYS /d:0 /f:2

 the formatting of this logical drive is not the same as the formatting
 of an internal drive.

 When the "FORMAT a: /f:720" command is used, FORMAT reports 730112
 bytes total disk space.

 When the "FORMAT d:" command is used (where D: is the drive assigned
 by EXTDSKDD), FORMAT reports 728064 bytes total disk space.

 Why are the values different?

 Response:

 Microsoft has confirmed this to be a problem with the version of
 EXTDSKDD.SYS that comes with OS/2 version 1.20. We are researching
 this problem and will post new information here as it becomes
 available.

 If you do a CHKDSK on the floppy disk that was formatted in Drive A
 using OS/2's default disk driver (DISK01.SYS), you will notice that
 the floppy disk uses two sectors per cluster (1024 byte allocation
 units). This is the correct way to format a 720K floppy disk (using
 IBM as a standard).

 If, on the other hand, you do a CHKDSK on the floppy disk that was
 formatted in Drive D via EXTDSKDD.SYS, you will notice that the floppy
 disk uses 1 sector per cluster (512 byte allocation units). Although
 this should not give you any problems, this is a nonstandard format.


 778. Interprocess Communication Between DOS 3.x Box & OS/2 Process

 Listed below are some questions and answers that involve the forms of
 Interprocess Communication (IPC) possible between the DOS
 compatibility (3.x) box and an OS/2 process.

 1. Can OS/2 IPCs, such as pipes, queues, or shared memory, operate in
    conjunction with an application running in the DOS compatibility
    box?

    Queues will not work between the DOS compatibility box and an OS/2
    application. Shared memory is a possibility, but that would require
    you to write a device driver to do so. This device driver would
    have to bypass many of OS/2's protection safeguards, and it would
    be a relatively difficult thing to do. We do not recommend this
    alternative.

    Named pipes, however, will work, which is the cleanest solution to
    this problem. The named pipe mechanism is also fully supported by
    the operating system. In the Software/Data Library is a file named
    DOSPIPE that contains two sample programs. One program runs under
    MS-DOS only, and the other program runs under OS/2 only. Both of
    these programs communicate successfully via a named pipe.

    DOSPIPE can be found in the Software/Data Library by searching on
    the keyword DOSPIPE, the Q number of this article, or S12577.
    DOSPIPE was archived using the PKware file-compression utility.

    There is also a good article on IPCs and more on communicating
    with the DOS compatibility box via named pipes in the September
    1989 issue (volume 4, number 5) of the "Microsoft Systems Journal."

 2. An application in the DOS compatibility box may write to a file on
    a FAT volume and that file can then be read by an OS/2 process.
    These events could be synchronized in several ways, perhaps most
    simply by having the OS/2 thread block on the file being available
    for it to open, and issuing a DosSleep() call immediately after
    closing it, etc. Even though this is clumsy and probably slow, will
    it work?

    Yes, this is probably the slowest way, but it will work as outlined
    above.

 3. Can the clipboard be used in conjunction with an application running
    in the DOS compatibility box?

    No, you cannot access the clipboard from the DOS compatibility box.

 4. Can DDE be used in conjunction with an application running in the
    DOS compatibility box?

    No, you cannot use DDE from the DOS compatibility box.

 Table of Possibilities (Y=Yes, N=No)
 ------------------------------------

 Approach (for OS/2 versions 1.10, 1.20, and for both FAT and HPFS):

        1a. (Queues) N
        1b. (Shared memory) Y (but most difficult)
        1c. (Named pipes) Y (best solution, easy, supported by operating
                             system)

        2. Y (slowest but easiest)

        3. N

        4. N

 We strongly recommend that you use named pipes; it will be the easiest
 option for you to code and maintain in future versions of OS/2, and it
 is considered to be a "clean" solution. Please see the sample
 applications in DOSPIPE to see how this is done.


 779. Invalid DosGetDateTime() Call Causes Trap 0D Error to Occur

 When making a call to DosGetDateTime() that contains an invalid
 pointer, the system traps out with TRAP 0D and internal processing
 errors at location 02A0:354B.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 780. Adding a Program to the Desktop in a VIO Application

 Question:

 Can a VIO application add a program to the Desktop? I want the
 installation procedure for my Presentation Manager (PM) application to
 do a PrfAddProgram() call to the desktop; however, the PrfAddProgram()
 call states that it needs a message queue and the call to
 CreateMsgQueue() fails in my VIO application.

 I've tried spawning a separate application to do the PrfAddProgram()
 call, but it appears to fail also when creating the message queue. My
 application runs properly when it is not spawned (that is, the message
 queue is created) and the PrfAddProgram() call is successful.

 Response:

 Yes, a VIO application can add a program to the Desktop. Below is a
 sample program that demonstrates this technique. You need to call
 PrfCreateGroup() (if you want your own group), then use the group
 handle returned from that call in the PrfAddProgram() call. If you
 want to make your program be the first group defined in the Desktop,
 you can do so by using 0 for the group handle in the call to
 PrfAddProgram().

 Sample Program
 --------------

 /* PRF.C: Create a program group and add a program to it. */

 #define INCL_WINPROGRAMLIST
 #define INCL_WINSHELLDATA

 #include <os2.h>
 #include <stdio.h>
 #include <assert.h>

 main()
 {
   HPROGRAM hProg, hGroup;  /* Program and group handle */
   PROGDETAILS progde;  /* Program details struct for PrfAddProgram() */
   HAB anchorBlock;  /* PM anchor block */
   HINI prfHandle;  /* Profile file handle */

   /* Get PM anchor block */
   anchorBlock = WinInitialize(0);
   /* Create a new group in the Desktop */
   hGroup = PrfCreateGroup(HINI_USERPROFILE, "testGroup",
                           (UCHAR) (SHE_VISIBLE | SHE_UNPROTECTED));
   assert(hGroup != NULL);
   /* Set up PROGDETAILS struct with information about program to add to
       group */
   progde.Length = sizeof(PROGDETAILS);
   progde.progt.progc = PROG_DEFAULT | PROG_WINDOWABLEVIO;
   progde.progt.fbVisible = SHE_VISIBLE | SHE_UNPROTECTED;
   progde.pszTitle = "Foobar!";
   progde.pszExecutable = "c:\\os2\\cmd.exe";
   progde.pszParameters = NULL;
   progde.pszStartupDir = NULL;
   progde.pszEnvironment = NULL;
   progde.swpInitial.fs = SWP_SHOW;
   progde.swpInitial.cy = 0;
   progde.swpInitial.cx = 0;
   progde.swpInitial.y = 0;
   progde.swpInitial.x = 0;
   /* Now add the program to our group */
   hProg = PrfAddProgram(HINI_USERPROFILE, &progde, hGroup);
   assert(hProg != NULL);
   WinTerminate(0);
   return(0);
 }


 781. Named Pipe Error Codes Missing in DosOpen() Documentation

 Both DosOpen2() and DosOpen() will return the value ERROR_PIPE_BUSY if
 the client end of a named pipe attempts to open a named pipe that has
 been created, but is not yet in a listening state (that is, the server
 end of the pipe has not yet attempted a DosConnectNmPipe() after its
 initial DosMakeNmPipe() call).

 This behavior is documented under the DosOpen2() API, but the same
 behavior also applies to DosOpen() and should be so documented.

 We will post new information here when the documentation has been
 updated to include this information.


 782. Documentation Error Regarding DosSetFHandState()

 Both QuickHelp and the "Microsoft Operating System/2 Programmer's
 Reference" show the following incorrect usage of DosSetFHandState():

 HFILE hf;
 USHORT usAction, fState;
 DosQFHandState(hf, &fState);             /* gets the current state */
 DosSetFHandState(hf,                     /* handle to the file     */
     (fState | OPEN_FLAGS_NOINHERIT));    /* set noinheritance flag */

 The correct usage of DosSetFHandState()  should be as follows:

 HFILE hf;
 USHORT usAction, fState;

 DosSetFHandState(hf,                     /* handle to the file     */
     OPEN_FLAGS_NOINHERIT);    /* set noinheritance flag */

 The incorrect usage will give OS/2 error 87 (Invalid Parameter).


 783. E Editor System Requests Do Not Work with Large Text Files

 The System Editor for OS/2 1.2 does not respond to system requests
 while it is processing large files. The following steps can be used
 to reproduce this problem:

 1. Turn on word wrap in the System Editor and try to load a 3 MB text
 file.

 2. Try to expand the width (the editor will take about 3 minutes to
 recalculate the word wrap).

 3. While the editor is trying to redisplay the window, press CTRL+ESC.

 4. A "NOT RESPONDING TO SYSTEM REQUESTS" message is displayed. Select
 the CANCEL button.

 5. The warning box does not subside until recalculation is done.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 784. Placing Items in Categories Menu in QuickHelp

 Question:

 How can I place a new menu item in the Categories Menu in QuickHelp
 (QH) for the database I'm creating?

 Response:

 You need to place a context string in your help source file that is
 similar to the following:

    .context List Categories

 QuickHelp looks for the context string "List Categories" in the
 QuickHelp file. It then places the items that you have listed after
 the ".list" command into the Categories pull-down menu. QH will then
 give your new menu item the next available letter choice. Below is an
 example of a help file.

 Text from a sample source help file (before encoding):

    .context List Categories
    .list
    MY NEW HELP
    .context MY NEW HELP
    .list
    Subject 1
    Subject 2
    Subject 3
    .context Subject 1
    ......your subject information for Subject 1
    ......
    .context Subject 2
    ......your subject information for Subject 2
    ......

 After you have encoded your QuickHelp source file, run QH, and pulled
 down the Categories menu, the words "MY NEW HELP" will appear next to
 a letter choice in the pull-down menu. When you choose the letter
 choice by "MY NEW HELP," you will get a list of Subject choices,
 (three, by what is shown in this sample help file). If you then select
 one of the Subject items, you will see the text for that particular
 subject.

 Please refer to Chapter 6 of the "Microsoft Operating System/2
 Programming Tools" manual from the OS/2 Presentation Manager (PM)
 Toolkit version 1.20, or Chapter 7 in the "Microsoft C Advanced
 Programming Techniques" book that comes with the Microsoft C 6.00
 Compiler for additional help in creating QuickHelp database files.


 785. GETICON: Interpreting Extended Attribute Information

 Question:

 I am looking into the Extended Attribute (EA) functions now included
 in OS/2 version 1.20 and have some questions concerning how they are
 used.

 The documentation as to what gets set and how is somewhat unclear. At
 the end of the variable length portion of the FEA structure, it
 contains the Extended Attribute name and value. The format of this
 information appears to be left up to the application (for example,
 name). I am unclear as to what the next two sections that deal with
 data type conversions and standard Extended Attributes are used for.

 Are these sections entered as part of the variable length data of the
 FEA structure, or are they part of a structure that I have overlooked?

 The way the standard Extended Attributes are referenced leads me to
 believe that they are a field to be filled in with something similar
 to the following:

    The Extended Attribute contains a brief summary of the file's
    content and/or purpose.

 Are these headers with information to follow included in the variable
 portion of the FEA structure?

 Response:

 Yes, the format of the variable length portion of the EA after the FEA
 structure is pretty much left up to the application. However, storing
 the EA name, data type, and (if required) length as the first part of
 the EA is a convention used so that other applications can understand
 what type of EA data is attached to a particular file and, with the EA
 data length, can navigate through the EA data.

 Listed below is a description of the "typical" contents of a variable
 length portion of an EA (for example, an ICON.) Suppose we have
 declared an FEA by the name of myFea with the following line:

    FEA myFea;

 Offsets from myFea will be used to show where these "fields" occur in
 the variable length portion following the FEA structure for an ICON
 EA.

    Field       Location
    -----       --------

    .ICON       At &myFea + sizeof(FEA). The name of the EA; this is a
                string. By looking at the cbName value of the FEA
                structure, we know how long this string is.

    NULL        (hex value 0). At &myFea + sizeof(FEA) + myFea.cbValue.
                Size: 1 byte. A NULL always follows the EA name.

    EAT_ICON    (hex value FFF9). At &myFea + sizeof(FEA) + myFea.cbValue
                + 1. Size: 2 bytes. This is the "type" of the actual EA
                data. Values 0000 through 7fff are available for
                user-definable types. A list of the standard types can
                be found in section 2.3.2.2 of the "Microsoft Operating
                System/2 Programmer's Reference Volume 4" for version
                1.20.

    4082        at &myFea + sizeof(FEA) + myFea.cbValue + 1 + 2. Size:
                2 bytes. This is the size of the actual EA data, which
                directly follows these two bytes. Some standard EAs
                differ from this format from this point onward; namely,
                the multivalue/multitype types.

    ...         at &myFea + sizeof(FEA) + myFea.cbValue + 1 + 2 + 2.
                This is the actual EA data, of length 4082, in this
                example, as specified by the previous 2 bytes.

 In the Software/Data Library is a sample program named GETICON that
 extracts the data portion of an EA and writes it out to a separate
 file. It is currently configured to extract ICON data and write it out
 to a file that can be edited with ICONEDIT.EXE. You can examine the
 code to see how you can access the variable length portion of the EA.

 In GETICON, a simple technique is used to declare a pointer and point
 it to the data type bytes, which begin immediately after the
 terminating null of the EA name string, and advance the pointer by
 appropriate amounts to read the rest of the "fields" in the variable
 portion.

 GETICON can be found in the Software/Data Library by searching on the
 filename, the Q number of this article, or S12592. GETICON was
 archived with the PKware file-compression utility.

 There is also an article in the April 24, 1990 issue of "PC Magazine"
 (Vol. 9, No. 8) on using Extended Attributes. You may find this
 helpful in understanding how EAs are used.


 786. "..." Truncated At End of HPFS Filename in OS/2 1.20

 An HPFS file cannot be created with trailing dots. The following steps
 can be used to reproduce this problem:

 1. Enter the following:

       copy con "foo..."

 2. Enter the following:

       foo

 3. Press CTRL+Z.

 4. Enter DIR. A file named "foo" will be displayed. For some reason,
    the trailing dots (...) are truncated.

 If you replace the command in Step 1 with the following command, the
 "..." remains:

    copy con "foo...t"

 Microsoft has confirmed that this behavior is by design. For
 compatibility reasons, trailing dots on components names are
 discarded.


 787. Unsupported Functions Included in OS2.LIB in OS/2 1.20

 The DosFindNotifyFirst() and DosFindNotifyNext() functions are
 included in the OS2.LIB file; however, they are not described in any
 of the documentation.

 Microsoft has confirmed that these functions are unsupported and
 should not be documented. We will post new information here when this
 error has been corrected.


 788. Using OS/2 FIND Command to Find Quotation Mark in File

 Question:

 A file named FOO contains the following:

    this line has a quote "

 How do I use the FIND command to find the quotation mark (") in this
 file?

 Response:

 You can use the following command to find the quotation mark in a file
 named FOO:

    FIND "\"" FOO

 This method is used to match the C string handling convention.


 789. DosFSAttach() Options Documentation Error in OS/2 PR Volume 4

 The BSEDOS.H header file defines the options for DosFSAttach() as
 FSATTACH and FSDETACH. On Page 96 of the "Microsoft Operating System/2
 Programmer's Reference Volume 4" for version 1.20, these same options
 are defined as FS_ATTACH and FS_DETACH.

 Microsoft has confirmed that this is a documentation error on Page 96
 of the "Microsoft Operating System/2 Programmer's Reference Volume 4"
 for version 1.20, and also in QuickHelp. We will post new information
 here when the documentation has been updated to correct this error.


 790. /ONCE Parameter System Help Inconsistency in OS/2 1.20

 The /ONCE parameter for the FORMAT command is inconsistently
 documented under OS/2 1.2. OS/2's online help for system error SYS1276
 refers to the /ONCE parameter, but this parameter is not documented in
 CMDREF.INF -- the Command Reference database for the Information
 Presentation Facility.

 Microsoft has confirmed this to be a problem occurs in version 1.20.
 It has not yet been decided whether to document the /ONCE parameter or
 to remove its mention in the error message for SYS1276. We are
 researching this problem and will post new information here as it
 becomes available.


 791. Unable to Select Key Group in E Editor Key Help Panel in 1.20

 Microsoft has confirmed that the following problem occurs with the
 the System Editor for OS/2 version 1.2.

 While in the System Editor, select the Help menu. From within the Help
 menu, select the "Keys help..." menu-item. This will bring up the
 "Help for the Keys" panel, which instructs the user to double-click on
 one of the key groups listed. However, when you attempt to do so,
 nothing happens.

 We are researching this problem and will post new information here as
 it becomes available.


 792. E System Editor Doesn't Clear Italics Font Character Correctly

 Microsoft has confirmed that the System Editor for OS/2 1.2
 incorrectly displays blank characters that are inserted before some
 italic characters. The following steps can be used to reproduce this
 problem.

 	1. While using E, change the type style to italic.

 	2. Enter the letters "ypgj" (without quotation marks).

 	3. Enter Insert mode.

 	4. Press the SPACEBAR in front of the letters you entered in
 	   Step 2.

 As you insert the blank characters, you will notice some small dots
 trailing the italic characters as they are shifted to the right. This
 failure is apparent with most fonts and most font sizes.

 The default VGA driver with a VGA color adapter was used to reproduce
 this problem.

 Microsoft is researching this problem and will post new information
 here as it becomes available.



 793. OS/2 1.20 FDISKPM Extended Help Doesn't List HPFS Type

 In the Extended Help for FDISKPM, in the Type paragraph under the
 partition information section, the Extended Help states that PMFDISK
 recognizes the partition types PRI OS/2, EXT OS/2, ALT OS/2 and some
 others. When you format the primary partition with HPFS, the partition
 type displayed is HPFS; however, HPFS is not listed in the Extended
 Help.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 794. Can't Use DosOpen() to Read a Track On a Disk in MS-DOS

 Question:

 I wrote a FAPI program that checks Drive A to determine whether or not
 it contains a formatted disk. This code works correctly in OS/2 and in
 the DOS 3.x box of OS/2, but when run in MS-DOS versions 3.30 and
 4.00, the DosOpen() call (used with OPEN_FLAGS_DASD) returns an error
 code of 0, a uAction of 0, and a file handle of FFFE. The DosRead()
 call then subsequently rejects this handle as being invalid. Why is
 this happening?

 Response:

 The OPEN_FLAGS_DASD option of the DosOpen() function only supports the
 use of DosDevIOCtl functions. The Category 8 functions DSK_READTRACK
 and DSK_WRITETRACK are not supported in MS-DOS versions 3.x or 4.00.
 Therefore, you cannot use DosOpen() to read a track on a disk under
 MS-DOS.

 In the DOS 3.x box, these calls are intercepted by OS/2, which can
 handle these requests. Under MS-DOS, no such facility is available.

 Microsoft has confirmed that this information should be included in
 the documentation. We will post new information here when the
 documentation has been updated to include this information.


 795. E System Editor Problem Switching from High to Low Resolution

 The System Editor, E.EXE, is capable of saving its position and window
 extents (the size of its window). The following problem occurs with
 the current implementation of E.EXE if you change your display adapter
 or display driver from a high-resolution version to a low-resolution
 version.

 For example, suppose E's main window was saved in a maximized state,
 under an 8514/A display adapter and display driver, and the video
 adapter and corresponding display driver were then changed to VGA.
 When you reboot the machine, E's main window comes up larger than the
 screen.

 One possible solution is to have E compare its position on the screen
 against the screen's resolution when it first loads. If E detects that
 it is going to appear off screen, then it could reposition its window
 to some default position.

 Please note that this is not just a problem with E.EXE. This behavior
 is also noted in other standard OS/2 applications, such as the PM
 shell and the way it manages its Group boxes (for example, the
 Group-Main box).

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 796. Journal Playback Using WM_JOUNALNOTIFY Doesn't Work in 1.20

 The WM_JOURNALNOTIFY mechanism does not work correctly in version
 1.20. Any application using WinGetPhysKeyState() or
 WinQueryQueueStatus() while journaling will not get the expected
 results.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 797. VioGetPhysBuf() Doesn't Return Correct Buffer Length in 1.20

 VioGetPhysBuf() uses a fixed internal table that does not consist of
 all the possible modes a user may be in. For example, if the mode is
 60 lines by 80 columns, VioGetPhysBuf() should return a buffer length
 of 60 x 80 x 2; instead, it returns a buffer length of 25 x 80 x 2.
 This length is too small and upon addressing this selector area, you
 can receive a protection violation and not know why it is occurring.

 VioGetPhysBuf() should use the present mode for figuring out the
 buffer length, and it should return the buffer length that the
 selector will be set to so that a protection violation will not occur.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 798. VioGetPhysBuf() Doesn't Do Input Range Check On Hardware

 VioGetPhysBuf() doesn't do an input range check on the hardware to see
 if it is possible to use the desired input video address on the
 hardware. Therefore, it is possible to get a video selector to
 nonexistent memory.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 799. VioGetPhysBuf() Input Error Checking Problem in OS/2 1.20

 If you use the inputs ".pBuf=0xA0000,.cb=0xFFFFFFFF,.asel=0" with the
 VioGetPhysBuf() function call, no error should be returned. However, a
 return code of 22 is returned, and 0xFFC7s are written throughout the
 VIOPHYSBUF area and beyond; this leads to a segment violation.
 VioGetPhysBuf() should either return an error or a selector to 0xA0000
 in this situation.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 800. VioGetPhysBuf() PhysBuf Block Not Being Checked Correctly

 If the user sets the buffer length to zero, the starting address of
 the buffer is the address of a PhysBuf Block. If the length of the
 PhysBuf Block is 0, VioGetPhysBuf() writes a 4, followed by a
 selector. If the length of the PhysBuf Block is 1, the same thing
 happens. The length of the PhysBuf Block is not being checked for even
 or valid values.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 801. DosTimerAsync() Requires CSEM_PUBLIC System Semaphore

 DosTimerAsync(ulTime, hsem, phTimer) is a function that clears a
 system semaphore (using the system semaphore handle hsem) after a
 given number of milliseconds (ulTime). The documentation for
 DosTimerAsync() claims that hsem must be a handle to a system
 semaphore. It also states that the handle must be created with
 DosCreateSem(). However, the documentation neglects to state that
 DosCreateSem() must be used with CSEM_PUBLIC and not CSEM_PRIVATE.

 If the semaphore is created with CSEM_PRIVATE, the semaphore can only
 be modified by the threads belonging to the process that made the
 call. Since DosTimerAsync() executes with a system thread, a thread
 that belongs to the system and not to the process that made the call,
 it cannot modify the thread created with CSEM_PRIVATE. The
 documentation for DosTimerAsync() does not mention that
 DosTimerAsync() uses a system thread, nor does it mention that the
 thread has to be created with CSEM_PUBLIC.

 Microsoft has confirmed that this information should be included on
 Page 156 of the "Microsoft Operating System/2 Programmer's Reference
 Volume 3" for version 1.10. We will post new information here when the
 documentation has been updated to include this information.

 The problem occurs because DosTimerAsync() is an asynchronous
 function. It is different than DosSleep(). DosSleep() will not return
 until the specified time has elapsed and it has cleared the semaphore.
 DosTimerAsync() returns control immediately to the process, and uses a
 system thread to wait for the time to elapse and clear the semaphore.
 Please note that DosTimerAsync() uses a system thread, and does not
 create another thread that belongs to the process owning the
 semaphore. Therefore, unless the semaphore was created as CSEM_PUBLIC,
 the system thread used by DosTimerAsync() cannot clear the semaphore
 after the time has elapsed.

 In the code listed below, DosSemWait() will return only if
 DosCreateSem() uses CSEM_PUBLIC. If that parameter is changed to be
 CSEM_PRIVATE, DosSemWait() will not return.

 #define INCL_DOS
 #define INCL_DOSSEMAPHORES
 #define INCL_DOSDATETIME
 #include <os2.h>

 void main()
 {
 HSYSSEM hsem;
 HTIMER  timer;

    DosCreateSem( CSEM_PUBLIC, &hsem, "\\sem\\test.sem");
    DosSemSet( hsem );
    DosTimerAsync( 500L, hsem, &timer );
    DosSemWait( hsem, SEM_INDEFINITE_WAIT );
 }


 802. Tip on Installing Microsoft OS/2 on a Compaq Portable III

 The information included below was obtained from an email message and
 has not yet been verified; therefore, it should be used with caution.

 This information has to do with trying to install Microsoft OS/2 on a
 Compaq Portable III machine when releases of the official Compaq OS/2
 aren't readily available. When Compaq OS/2 is available, users should
 just use the Compaq version of OS/2 instead of trying workarounds like
 the one described below.

 >From dougho Thu May 24 17:01:25 1990
 Subject: Re: Compaq Portable III

 Unless you use Compaq's OS/2 release, you need to reconfigure your
 hardware switches to emulate a CGA, rather than a monochrome. CGA or
 better is required to run 1.10 or later (PM).

 There is a jumper inside the back cover of the machine. Compaq's
 release uses some software method to force the mode out of monochrome.

 You will probably need to not only change the switch, but re-install
 after doing it (to get the proper bvh, config.sys, etc).

 | I'm not sure if this is a bug, or just my ignorance. I'm trying to
 | install build 184 from install disks onto a Portable III with 4 MB
 | RAM and a gas plasma screen. The install seemed to think the display
 | was a monochrome with parallel port, so I went along with it. When I
 | rebooted the machine, I got the usual message about installing the
 | mouse drivers, etc., then it flips to a blank screen, I get about 5
 | seconds of disk activity, then the machine hangs. I've tried
 | modifying config.sys to use bvhmpa, bvhega, and/or bvhvga with the
 | same result. If I remove the pmshell specific items from the
 | protshell line, everything works fine, so I suspect the problem
 | occurs when os/2 tries to switch to graphics mode. I'm not trying
 | to install Lanman at all. Any ideas?


 803. Command Reference Index Cross Referencing Problem in OS/2 1.20

 There seems to be a problem with the index cross referencing in OS/2
 version 1.20. The following steps can be used to reproduce this
 problem:

 1. Invoke the Command Reference and click on the Options Index.

 2. Find the CONFIG.SYS file in the index and click on it.

 3. Instead of bringing up an explanation for CONFIG.SYS, the "Welcome"
    screen is displayed.

 A similar problem occurs when you click on "Processes." An explanation
 of the MS-DOS BREAK command appears.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 804. Use of Mouse on Command Reference Can Hang System in 1.20

 Microsoft has confirmed that the following problem occurs in OS/2
 version 1.20. In the main group, select the Command Reference with the
 keyboard. At this point, the mouse pointer will turn into an
 hourglass, and then back into a pointer. Now, grab the main group box
 with the mouse and move the mouse rapidly around the screen. About one
 in three times, the screen will lock up. If you then click on the 3.x
 box, the mouse will also lock up.

 We are researching this problem and will post new information here as
 it becomes available.


 805. ANSI Display Differences Depending on Type of Session

 Question:

 I have noticed that some ANSI escape sequences work differently in
 Presentation Manager (PM) window text sessions than in full-screen
 text sessions. For example, if the following string is sent to the
 screen in a full-screen session, it will produce blinking yellow text:

    printf("\x1b[5;33mThis text should blink in yellow.\x1b[m");

 In a PM windowed text session, instead of producing blinking yellow
 text, the text is displayed in yellow on a white background. Why is
 the text displayed differently depending on whether the text is
 displayed in a PM window text session, or a full-screen text session?

 Response:

 This can be considered a documentation omission as it is expected
 behavior. To change colors on the screen, you have to set bits a
 certain way. In a full-screen session, you have complete control. In a
 VIO window, you are subject to what PM has set up for you and the
 colors are a result of this.


 806. VioGetModeInfo() Structure Definition Incorrect on Page 275

 Problem:

 The structure listed for the VioGetModeInfo() function on Page 275 of
 the "Microsoft Operating System/2 Programmer's Reference Volume 4" has
 different members than the same structure listed on Page 406 of the
 same manual. The reference to the structure on Page 406 corresponds to
 the BSESUB.H header file. Which definition is correct?

 Response:

 Microsoft has confirmed that the documentation for the structure is
 incorrect on Page 275 of the "Microsoft Operating System/2
 Programmer's Reference Volume 4," and that the documentation on Page
 406 of the same manual is correct. We will post new information here
 when the documentation has been updated to correct this error.


 807. Structure Definitions Incorrect in VioGetState() Documentation

 The structure assignment names for the VIOCOLORREG, VIOSETUNLINELOC,
 and VIOSETTARGET structures used with the VioGetState() function on
 Pages 276-277 in the "Microsoft Operating System/2 Programmer's
 Reference Volume 3" differ from those listed in Chapter 4 of the
 "Microsoft Operating System/2 Programmer's Reference Volume 4." The
 references in Chapter 4 correspond with those included in the BSESUB.H
 file.

 Microsoft has confirmed that the documentation for these structures is
 incorrect on Pages 276-277 of the "Microsoft Operating System/2
 Programmer's Reference Volume 3."

 The correct definitions for these structures are included in Chapter 4
 of the "Microsoft Operating System/2 Programmer's Reference Volume 4"
 and in BSESUB.H. The correct definition for VIOCOLORREG is listed on
 Page 404, and the correct definitions for VIOSETUNLINELOC and
 VIOSETTARGET are listed on Page 408 of the "Microsoft Operating
 System/2 Programmer's Reference Volume 4."

 We will post new information here when the documentation has been
 updated to correct this error.


 808. Purpose of OS/2 VioGetModeInfo() Ext_Data_Addr Parameter

 Question:

 What purpose does the ext_data_addr parameter of the VioGetModeInfo()
 function serve? What does the extended mode data structure look like?

 Response:

 The ext_data_addr parameter is used so that an application can pass
 the address of some sort of extended mode structure directly to a
 video device driver. The format of the extended mode structure (and
 what an extended mode is) is defined by the particular video driver
 and is unknown to OS/2. Unless you are working with a particular video
 driver that accepts this type of data, you should set this parameter
 to NULL.


 809. OS/2 DosFSAttach() cbData Field Definition

 Question:

 Is the cbData field of the DosFSAttach() function supposed to
 represent the total length of the data buffer or the length of the
 data that the buffer contains? The documentation implies that this
 field is used to represent the total buffer length; however, in actual
 practice it seems that this field is just the length of the data in
 the buffer. If you use the actual length of the buffer as the
 parameter rather than the length of the buffer contents, DosFSAttach()
 will return with an invalid parameter error.

 Response:

 You are correct; the correct length of the cbData field should be the
 length of the actual data in the buffer. The buffer should be no
 larger than the actual size of the data you need to put into it. In
 fact, this is the general rule for most DOS and VIO calls. You should
 give the call the length of the actual data that the function needs,
 not the size of the entire buffer (unless they are the same).


 810. VioSetState() Returns Incorrect Error If First Parm Is Invalid

 If you issue the following call

    VioSetState(length=38,requestype=0,parm1=256,)

 an error code of 438(ERROR_VIO_INVALID_LENGTH) is returned instead of
 the correct error code of 421(ERROR_VIO_INVALID_PARMS).

 Although the first parameter is of an invalid length, it is rather
 more of an invalid parameter since the invalid length error refers to
 the length variable.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 811. DosSetFileInfo() Documentation Error

 The documentation for DosSetFileInfo(), DosSetPathInfo(), and
 DosQFileInfo() in the OS/2 version 1.20 Toolkit is incorrect (on Pages
 138 and 139 of the "Microsoft Operating System/2 Programmer's
 Reference Volume 4" for version 1.20). The usInfoLevel value lists the
 following macros, which are not defined in the header files:

    FILE_INFO_1
    FILE_INFO_2
    FILE_INFO_3

 The proper macros for this parameter are the following:

    #define FIL_STANDARD         1   /* Info level 1, standard file info */
    #define FIL_QUERYEASIZE      2   /* Level 2, return Full EA size     */
    #define FIL_QUERYEASFROMLIST 3   /* Level 3, return requested EAs    */


 812. COPY Sends Extra Job to Spooler When LPT1: Is Used in 1.20

 Under the following circumstances, when sending a print job to the
 spooler of a 3+Open server from an OS/2 netstation, two .SPL files are
 created: one for the file to be printed, and one a 0-byte (zero-byte)
 length file. This problem can be reproduced by entering a COPY
 CONFIG.SYS LPT1: command with a trailing colon (as opposed to COPY
 CONFIG.SYS LPT1 with no colon). The messenger will send two
 acknowledgments to the user who sent the job, one for the actual print
 job and one for the 0-byte length file. The print queue functions
 properly otherwise.

 This is not a problem for simple redirection since the TYPE command
 works correctly. For example, in the case of TYPE CONFIG.SYS > LPT1:
 only one job is printed.

 Microsoft has confirmed that this problem occurs in version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 813. Trap 0D Occurs When Using File Manager to Search on Directory

 Microsoft has confirmed that the following problem occurs in version
 1.20. We are researching this problem and will post new information
 here as it becomes available.

 1. From the Tree window of the File Manager, choose View/Replace on
    Open.

 2. Execute a search that will find a directory.

 3. In the search window, double-click the directory.

 At this point, a Trap 0D occurs.


 814. HPFS Version 1.20 FORMAT Doesn't Always Detect Bad Sectors

 Bad spots on a hard disk are not always found when the hard disk is
 formatted with the HPFS file system. For example, there can be a
 sector on a hard disk that can be written to, but cannot be read,
 read-verified, or format-verified. The HPFS format only uses the write
 IOCTL, and thus does not find the sector to be bad. Then, when the
 hard disk goes into use, read faults can occur when the file system
 tries to read a file that has been written to a bad sector.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.

 If an unreadable sector is allocated to a file, the Recover utility
 can be used to take that bad sector out of circulation.

 Also, a recent change to HPFS CHKDSK will cause unreadable sectors to
 be put on the bad block list if you use "CHKDSK /F:3".


 815. Screen Colors Push Button Sample Window Not Updated Correctly

 There is a problem in the Control Panel Screen Colors Window. If you
 change the color of the Push Button Background, no apparent changes
 are reflected in the sample window. However, after saving the changes
 and exiting the Screen Colors window, you will notice that the scroll
 bar button changes colors. The scroll bar button in the sample window
 of the Screen Colors window should also reflect any changes to the
 Push Button Background.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 816. File Manager Confirmations Box Not Displayed Correctly in 1.20

 There is a small visual display bug in the File Manager. Under the
 Options menu, choose Confirmations; a Confirmations dialog box will
 appear. If you TAB down to the "Confirmation on subtree direct
 manipulation" choice, you will note that the dotted line box
 surrounding the text is clipped on the right side.

 Microsoft has confirmed this to be a problem in version 1.20. We are
 researching this problem and will post new information here as it
 becomes available.


 817. Scroll Bars Aren't Redrawn Correctly in System Editor in 1.20

 There is a problem with the Presentation Manager (PM) when it redraws
 scroll bars when you are using the System Editor. The following steps
 can be used to reproduce this problem:

 1. Invoke the System Editor.

 2. Create 20 lines of text.

 3. Size the window of the editor so that 16 lines of text are visible.

 4. Move the cursor to the first line of text.

 5. Click the scroll bar just below the scroll-bar button. This should
    result in lines 17 through 20 being displayed. Take note of the
    scroll bar. The scroll bar button has moved down and has shrunk in
    size; however, the scroll-bar background is not of a uniform color.

 Microsoft has confirmed this to be a problem in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.


 818. PM Does Not Resize Text Windows Consistently in 1.20

 Microsoft has confirmed that the following problem occurs in OS/2
 version 1.20. We are researching this problem and will post new
 information here as it becomes available.

 1. Open a text window in OS/2 and resize it as small as possible.

 2. Try to expand the size of the window in the upward direction by the
    smallest possible amount.

 After releasing the mouse, Presentation Manager (PM) will not expand
 the box because the box is still too small to draw the scroll bars.
 However, PM will move the box in the upward direction. If you try to
 expand the box in the same manner in the downward direction, PM will
 not move the position of the box.


 819. Use of ALT+F in OS/2 File Manager Doesn't Select Tree Menu

 Microsoft has confirmed that the following problem occurs in version
 1.20. We are researching this problem and will post new information
 here as it becomes available.

 The following steps can be used to reproduce this problem:

 1. Start the File Manager.

 2. Press ALT+F to select the File menu.

 3. Press the RIGHT ARROW key.

 This action should normally select the Tree menu. However, in this
 case, the cursor returns to the Drive window. This problem does not
 occur with other menu items.

 You can work around this problem by pressing ALT+T instead of ALT+F.


 820. PresentS: OS/2 Tools to Determine Memory Usage and Needs

 At this time, this tool should only be used by employees within
 Microsoft, it should not be sent out to any customers unless you have
 the permission of your manager. Mikebor is investigating the
 possibility of making this tool available to OnLine customers. This
 article will be updated once it has been determined whether this tool
 can be made available to OnLine customers.

 PresentS (Present Segments) is a set of software tools for OS/2
 version 1.20 that helps to determine memory usage and memory needs.

 In the Software Library is a file named ARENA that contains the
 PresentS software tools. ARENA can be found in the Software/Data
 Library by searching on the keyword ARENA, the Q number of this
 article, or S12620. ARENA was archived with the PKware
 file-compression utility.

 PresentS can be used to determine the amount of memory needed to
 operate without swapping during a single "working set phase." The
 following is a brief explanation of what is meant by "working set
 phase."

 Theoretically, at a given point during program execution, a "working
 set" is the set of segments touched during the last T seconds, where T
 is arbitrary (but fixed). You can think of T as being 1 second, given
 today's processor and disk speeds. So, informally, at any given point
 in time, a working set is the set of segments touched during the
 previous second.

 A working set phase is a time period during which the set of
 segments in the working set does not change. By definition, if you
 do not have enough memory for each working set phase, you will
 experience significant performance degradation due to swapping. This
 means that you need enough memory for the LARGEST working set phase.

 Working set phases can be hard to measure, but there is a functional
 definition that approximates the working set phase. It is a set of
 program operations that you do not want to be degraded by swapping.
 You can break down your program function according to groups of user
 interactions during which you would like to see no swapping. For
 example, if you are writing a spreadsheet application such as
 Microsoft Excel, you probably don't want swapping occurring during
 recalculation. Also, there may be a core of commands surrounding
 charting that you do not want degraded by swapping. If so, you can
 define a user scenario using those commands, etc.

 Suppose you decide that you want no swapping during recalculation, and
 you want no swapping during charting. This gives you two phases. Now
 the question is: what about when you transition from recalculation to
 charting and back again?

 If this is an infrequent operation, you will probably want to consider
 these as separate phases. However, if this operation occurs
 frequently, you may want room in memory for all the segments. There is
 a fine point to consider when making these decisions: how much overlap
 is there between segments in one phase and segments in another phase?
 If the overlap is small, the amount of memory to hold both phases at
 once may be large, as will be the time to swap between them. If the
 overlap is large, the cost of holding both in memory, or of swapping
 between them, is small (the ARENA tool in PresentS will let you
 determine which segments are in each phase; the process is somewhat
 tedious, but you can make it reasonable by writing a program to
 examine the ARENA output to identify segments in your application).

 One more point: you may have noticed that the amount of memory needed
 by a spreadsheet application to do a recalculation is dependent on the
 size of the spreadsheet. Thus, the choice of user data for your
 scenario is critical to getting the correct answer to the question of
 how much memory is required. Only you can decide what is typical for
 your application.

 Cardinal Rule of Working Set Measurement: The scenario measured
 determines the result.

 When determining the working set measurement, you should consider the
 following. Appropriate thought concerning the scenario to be measured
 -- including the type, size, and form of "user" data -- is critical to
 getting rational results from working set measurements.

 The following components are included in the PresentS system:

    Component           Description
    ---------           -----------

    LOCKMEM$.SYS        Device driver used to lock memory
    READPHYS.SYS        Device driver used to read physical memory
    ARENA.EXE           Measurement tool
    MEMUSER.EXE         Memory flushing utility
    READIT.EXE          First Stage reporting analyzer
    SORT.EXE            Sort utility (shipped with OS/2)
    SUBTOT.EXE          Second Stage reporting analyzer
    MTCHMERG.EXE        Compares multiple snapshots
    ARENACMD.CMD        Command file used to execute ARENA procedure

 The following steps can be used to execute the ARENA system:

  1. Install LOCKMEM$.SYS and READPHYS.SYS into your CONFIG.SYS file
     with the following commands:

        DEVICE=C:\PresentS\LOCKMEM$.SYS
        DEVICE=C:\PresentS\READPHYS.SYS

  2. Reboot your system.

  3. Start two screen groups, referred to as SG1 and SG2.

  4. In SG1, start up the ARENA procedure. For example

        cd \arena
        arenacmd <filename>

     where <filename> is an 8-byte filename for this snapshot.

  5. A list of locked segments will be displayed. You will be prompted
     to "Enter Y to take snap shot, or N to cancel." Don't select
     either option at this point; just proceed to Step 6.

  6. Start up the application that is being tested. Let it run long
     enough to pass through its initialization procedures. Get to the
     point where you are just about to start the working set phase of
     interest.

  7. Switch to SG2. Flush all unused segments using MEMUSER. For
     example:

        memuser <physical memory size + 2>m

     On a system with 9 MB of memory, you would enter the following
     command:

        memuser 11m

     Let this program run for 15 minutes. Press any keystroke to
     terminate this program.

  8. Execute the application working set phase that you want to study.

  9. Return to SG1. Enter "Y" to allow the arenacmd program to
     continue.

 10. The final report includes a tab-delimited file named
    <filename>.SUB. This file is best examined with Microsoft Excel.

 Please reboot your system after taking the snapshot. PresentS does not
 release the memory locks that it establishes.

 The report in <filename>.SUB includes the following columns:

    Column    Description
    ------    -----------

    Owner     This is the name associated with the memory. An asterisk
              after the name (*) indicates that the name refers to an
              .EXE file.

    Total     This is the total memory used by the Owner.

    High      This is the amount of the memory that is used above the
              1 MB line.

    Low       This is the amount of the memory that is used below the
              1 MB line.

    Swap      This is the amount of the memory that is swappable.

    Non-Swap  This is the amount of the memory that is not swappable.

    Fixed     This is the amount of the memory that is not movable.

    Disc      This is the amount of the memory that has been swapped to
              disk.

    Pres      This is the amount of the memory that is in real memory.


 821. DIR /F and /N Options Do Not Work in DOS 3.x Box

 The DIR /F and /N options can only be used in protect mode. You cannot
 use these options in the DOS 3.x box. Microsoft has confirmed that
 this restriction is not documented in the "Microsoft Operating
 System/2 Version 1.2 Command Reference" (prerelease) in the section on
 DIR.

 We will post new information here when the documentation has been
 updated to include this information.


 822. OS/2: Cannot REName Directory in DOS 3.x Box

 The RENaming of directories is allowed only in protected mode. You
 cannot REName a directory in the DOS 3.x box. Microsoft has confirmed
 that this restriction is not documented in the "Microsoft Operating
 System/2 Version 1.2 Command Reference" (prerelease) in the section on
 RENAME.

 We will post new information here when the documentation has been
 updated to include this information.


 823. OS/2 Full-Screen Menu Screen/Keyboard Initialization Problems

 Problem:

 I've just installed a new application that uses a full-screen,
 menu-driven interface (COWS interface) (such as LAN Manager or SQL
 Server). When I start the full-screen interface, I receive the
 following message at the top of the screen:

    Unable to initialize screen or keyboard

 The application then quits and returns to the OS/2 prompt.

 Response:

 Most likely, when you last installed OS/2, you did not install a mouse
 driver (that is, you selected no mouse during OS/2 installation). The
 full-screen menu interface used by many Microsoft programs requires
 the presence of the POINTDD.SYS driver and this driver is only
 installed when you install a mouse. Look in your CONFIG.SYS file for
 the following line (or one similar):

    DEVICE=C:\OS2\POINTDD.SYS

 If this line is missing, you need to install it and the appropriate
 mouse driver for your mouse and computer.


 824. Far String Calls Listed on Page 352 of OS/2 Prog. Ref. Vol. 1

 Question:

 I was attempting to use the OS/2 DDE (dynamic data exchange) examples
 on Page 352 of the "Microsoft Operating System/2 Programmer's
 Reference Volume 1," and found references to the functions
 "FarStructCopy" and "FarStrCopy." Would you please provide some
 further information regarding these functions?

 Response:

 These functions are not OS/2 API calls. They are just a sample
 framework. In large model, they are equivalent to the following C
 compiler run-time functions:

    FarStrLen --> strlen
    FarStrCopy --> strcpy
    FarStructCopy --> memcpy

 For small and medium models, you can just write them yourself. The key
 point is to declare the pointer arguments as far pointers so that the
 routines can be passed pointers to objects not in the application's
 DS.

 The Microsoft C Compiler version 6.00 run-time library has a set of
 far string and memory functions. They start with "_f", followed by the
 equivalent memory model dependent functions. For example, the function
 "_fstrcpy" is a memory model independent function that allows you to
 copy strings specified by far pointers even in a small model program.
 These functions can be used, or you can write your own functions and
 explicitly specify far pointers where needed.


 825. QFSINFO: Sample Program to Obtain Amount of Free Disk Space

 Question:

 What is the equivalent OS/2 call to _dos_getdiskfree()?

 Response:

 You should use the DosQFSInfo() call. In the Software/Data Library is
 an archived file named QFSINFO that contains a sample program that
 figures out the amount of free space on the disk specified using this
 API.

 QFSINFO can be found in the Software/Data Library by searching on the
 keyword QFSINFO, the Q number of this article, or S12622. QFSINFO was
 archived using the PKware file-compression utility.


 826. Invalid Printer Error Occurs While Printing with Print Picture

 Microsoft has confirmed that the following problem occurs when using
 the IBM 5152 compatible printer and driver in OS/2 version 1.20. We
 are researching this problem and will post new information here as it
 becomes available.

 If you print a metafile with the PM utility, Print Picture, the
 picture starts printing; however, while in the middle of printing, the
 following error message is displayed:

    PMV8005: Make sure the printer is switched on, that it is online,
    and that it is loaded with paper. Processing will continue.

 Also, the job in the spooler queue goes from the status of PRINTING to
 the status of PRINTER OFFLINE, but the job finishes printing without
 any problems. If you press the ENTER key, it causes the message to
 continue to pop up. If you select Cancel, it causes the message (and
 the stuck job in the spooler queue) to disappear.

 This problem does not occur with the Epson drivers.


 827. Allocating Memory to Be Used with OS/2 DosWriteQueue Function

 Question:

 Does the OS/2 DosWriteQueue() function call allocate memory for what I
 write to the queue? If so, how is this memory managed? Specifically,
 how does OS/2 know when my application has finished with the pointer
 returned by DosReadQueue()?

 Response:

 No, DosWriteQueue() does not allocate any memory for queue packets;
 you must do this yourself. One way to accomplish this is to allocate
 shared memory for the queue packet, give the memory to the queue
 reader with DosGiveSeg(), and then free the memory after the write.
 The memory is not actually freed until the queue reader also frees the
 shared memory. The following is a small code fragment that shows how
 this is done:

 PID pidOwner;
 SEL sel, selRecipient;

 DosOpenQueue(&pidOwner, &hqueue,
     "\\queues\\queuename");               /* Opens queue             */
 DosAllocSeg(512, &sel, SEG_GIVEABLE);     /* Allocates shared memory */
 DosGiveSeg(sel, pidOwner, &selRecipient); /* Gives it to queue owner */
     .
     . /* Copy the data to the shared memory segment */
     .
        DosWriteQueue(hqueue,    /* Queue handle                */
            0,                   /* Request data                */
            11,                  /* Length of data              */
     MAKEP(selRecipient, 0),     /* Data buffer                 */
            0);                  /* Element priority            */
        DosFreeSeg(sel);         /* Frees shared memory segment */


 828. Scheduling Time-Critical Threads with OS/2 IPC Calls

 Question:

 How can I guarantee the following sequence with OS/2 IPC (interprocess
 communication) calls:

 1. Time-critical Thread A has set a semaphore and then enters a
    processing loop of reading from a named pipe.

 2. Regular class Thread B is looping and blocked on this same
    semaphore.

 3. Every time a read occurs, Thread A clears its hold on the semaphore.

 4. Thread B begins.

 5. Thread A immediately regains control of semaphore so that Thread B
    will block after one iteration.

 The problem is that Thread A is time-critical, and in an environment
 of many threads it often gets scheduled prior to Thread B, which would
 effectively never get its iteration. I'm currently using a combination
 of semaphore and variable flags that works about 99 percent of the
 time. Is there an alternative method?

 Response:

 Listed below is one method that should accomplish this type of
 functionality. It involves the usage of two semaphores. Suppose you
 have two semaphores called s1 and s2. Included below is the sequence
 of events the two threads would execute to keep things synchronized
 (assuming both semaphores are initially set):

    Thread A (Time-Critical)           Thread B
    ------------------------           --------

    DosSemClear(s1);                   DosSemWait(s1);
    DosSemWait(s2);                    DosSemClear(s2);
    DosSemSet(s1);                     DosSleep(0L);
    DosSemSet(s2);                     process data...
    process data...

 Thread A clears s1, and Thread B is now marked as runnable. Thread A
 now blocks on s2, and Thread B eventually gets a chance to run. Thread
 B clears s2, which unblocks Thread A; Thread B then does a DosSleep(0)
 call, which surrenders the rest of its time-slice. This will help
 guarantee that Thread A gets a time-slice before Thread B, and Thread
 A will then reset both semaphores, s1 and s2.

