 Microsoft `C' Professional Development Environment
 =============================================================================


 1. C_FILE_INFO in Environment of Child Process

 Product Version(s): 3.00 4.00 5.00
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR55563
 Last Modified: 25-AUG-1989    ArticleIdent: Q11867

 When you shell from a C program (spawn a process), the environment
 will appear to become corrupted with a ;C_FILE_INFO (or _C_FILE_INFO)
 string. (Version 5.10 uses an underscore rather than a semicolon.)

 When a process is spawned, the C run time passes information about
 open files to the child by inserting the identifier ";C_FILE_INFO" (or
 "_C_FILE_INFO" -- no quotation marks in either case), followed by up
 to 20 bytes, into the environment. During start-up, the C run time
 reads the identifier, uses the information passed, and removes it from
 the environment.

 System() is implemented by spawning COMMAND.COM, and since COMMAND.COM
 is not a C program, ";C_FILE_INFO" (or "_C_FILE_INFO") gets left in
 the environment.

 This behavior is harmless. The leading ";" (or "_") prevents any
 collision with user-entered environment variables.


 2. matherr and Trapping Floating-Point Errors

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1990    ArticleIdent: Q22317

 Question:

 matherr is not trapping my floating point errors. Could you give me
 some advice on what I could be doing wrong?

 Response:

 matherr (Page 274 in the "Microsoft C Run-Time Library Reference"
 manual) does not trap in-line floating-point errors. matherr only
 traps floating-point errors generated by functions in our math
 libraries. For example, the following program returns control to our
 matherr routine, not yours:

    #include <math.h>

    matherr(x)
    struct exception *x;
    {
    x->retval=2;
    return(1);
    }

    main()
    {
    double f;
    f=2.0;
    while (1)
    f*=f;
    }

 To trap in-line floating-point errors such as the one above, we
 recommend that you use signal with SIGFPE (see the run-time reference
 manual).


 3. C 5.10 Prototypes Differ Between \INCLUDE and \INCLUDE\MT

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  1-FEB-1991    ArticleIdent: Q58069

 Multithreaded programs are linked with LLIBCMT.LIB and include header
 files from the \INCLUDE\MT directory. If you link with LLIBCMT, but
 include header files from the \INCLUDE directory, you may get the
 linker message "L2029, unresolved external" on one or more of the C
 run-time routines. You can resolve the problem by including the
 multithreaded header files.

 The linker must resolve external references based on the names written
 to the object file. The explicit format of these names is directly
 affected by the prototypes you use in your program, and when you
 include the header files, you are specifying function prototypes. The
 prototypes for some functions are different between the single and
 multithreaded header files. For example, atof() is defined in the
    double _CDECL atof(const char *);

 and in \INCLUDE\MT\STDLIB.H as follows:

    double far pascal atof(const char far *);

 The keyword _CDECL means to use C language conventions (that is,
 preserve case and prepend a leading underscore). The keyword pascal
 means to use Pascal language conventions (that is, promote to
 uppercase and do not add a leading underscore). When the linker is
 looking for _atof, it does not consider ATOF a match.

 You can find complete compile and link instructions for multithreaded
 programming in MTDYNA.DOC, which is on the C version 5.10 disks.


 4. _remappalette(8,_GRAY) Does Not Work Correctly

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | bug
 Last Modified: 12-OCT-1988    ArticleIdent: Q34623

 _remappalette(pixel,color) maps the number "pixel" to the value
 "color" and is suppose to return the previous color value. However,
 when this function is invoked as _remappalette(8,_GRAY), the value
 associated with _WHITE is returned.

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

 To demonstrate this problem, do the following:

 1. cl the following source-code chunklet with /Od /Zi
    switches.

 2. Go into CodeView.

 3. Set N16 to look at the value err returned by _remappalette() in hex,
    then compare the value with values for the colors in graph.h. You
    may want to make a hardcopy of these values prior to cving. The
    correct value is returned on the zeroth pass, but then erroneous
    values are returned. This has been raided.

 4. Use cv /S, where the S is for switching screen modes.

 The following sample code demonstrates the problem:

          #include <stdio.h>
          #include <graph,h>
          main()
          {
             int i;
             long err;
             _setvideomode(_HRES16COLOR);
             for (i=0;i<16;i++)
             {
               err=_remappalette(8,_GRAY);
               printf("%x\n",err);
             }
             _setvideomode(_DEFAULTMODE);
          }


 5. Warning C4040: near/far/huge Ignored

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 26-SEP-1988    ArticleIdent: Q23978

 Question:

 I am trying to declare some far data in small model, but I keep
 getting "Warning 40: near/far/huge ignored" with C Version 4.00, or
 the same warning with the number C4040 using C Versions 5.x. Does this
 mean I cannot declare far data in the small model?

 Response:

 The far data can be declared in the small-memory model. This warning
 means that the far descriptor is improper and/or unnecessary in the
 context in which it is being used. Far or huge arrays should be
 defined outside of functions, or with the static storage class if
 defined within functions.

 It also may mean you are trying to make the type of pointer definition
 "char * far pvar;" within the body of a function. This definition
 attempts to define a pointer to data (either near or far, depending on
 the memory model) and place it in a far data segment outside the
 default data segment. This process only will work properly if it is a
 global definition, or if it is defined as static within the body of
 the function.

 Please note the difference between the above definition and defining a
 pointer to far data, which is "char far *pvar;". The latter definition
 declares a pointer that can point to data outside the default data
 segment, but the pointer itself is within the default data segment.
 This declaration is quite acceptable within the body of a function.


 6. Initial Memory Allocation of C Programs

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | DGROUP 64K
 Last Modified: 15-JAN-1990    ArticleIdent: Q23905

 Question:

 I want to make a program "terminate and stay resident." It is a very
 short program with only 4K of data and about 2K of code. However, when
 I execute the program to make it resident and do a CHKDSK, it seems to
 occupy about 70K. Why does it take up so much space?

 Response:

 The linker normally allocates all of memory to a program. You can use
 the /CP switch to adjust the allocation down. If you specify an amount
 less than the minimum allocation, the maximum allocation will default
 to that minimum, so link with /CP:1.

 You can also use the /max <MinimumAllocationInHexParagraphs> option of
 the EXEMOD.EXE utility to adjust the maximum allocation of a program.

 Microsoft C was not designed for writing memory resident software.
 Although it is possible, you also may need to make modifications to
 the start-up code. Be cautious about what functions you use and what
 DOS functions are called.


 7. Changing STDIN Translation Mode from Text to Binary

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified:  7-MAR-1990    ArticleIdent: Q58427

 Question:

 Why is it that when I enter a ^Z (CTRL+Z) for a string input in
 response to gets() or scanf(), the next line does not prompt me for an
 input?

 Response:

 Since STDIN is a predefined file pointer opened in text mode, and a ^Z
 character is an end-of-file marker in DOS, the ^Z character
 automatically closes the file pointer. The gets() or scanf() functions
 do not stop to accept input from STDIN following the previous input
 containing a ^Z character.

 To work around this problem, change the translation mode of STDIN from
 text mode to binary mode. Since the ^Z character is not translated as
 an end-of-file character in binary mode, the gets() from the following
 example only accepts input following a ^Z from STDIN after the
 translation.

 To change STDIN from text mode to binary mode, use the setmode()
 run-time function to change the translation mode. The following code
 demonstrates this behavior, and includes the setmode() function to
 show how to change STDIN from text mode to binary mode. Remove the
 comment delimiters to observe the difference in the program's behavior
 after adding the setmode() function.

 Code Example
 ------------

 #include <stdio.h>
 #include <string.h>
 #include <fcntl.h>

 void main (void)
 {
    char str1[20];

 /* if( setmode ( fileno ( stdin ), O_BINARY ) == -1 )
           perror ( "Cannot set stdin to binary mode" );
    else
           printf ( "stdin mode successfully set to binary\n" );
 */
    do {
           printf ( "Enter a string : " );
           gets ( str1 );
    } while ( strcmp( str1,"n" ) );

 }

 Compile the above code and run the program. If you enter a string
 and then press the ENTER key, the program will loop and prompt for
 another string. However, if at the prompt you enter a ^Z or a string
 followed by a ^Z, the program will loop indefinitely. It does not pause
 at the gets() statement and wait for your input.

 Now, uncomment the if-else clause. Recompile the program and run it.
 Input that includes a ^Z character is now accepted without infinite
 looping.


 8. Evaluation Order of Expression and Function Args Undefined

 Product Version(s): 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | S_QUICKC S_QUICKASM
 Last Modified: 30-NOV-1989    ArticleIdent: Q50694

 Side effect operators (++, --, =, +=, -=, *=, /=, %=, &=, |=, ^=, <<=,
 and >>=) may cause unexpected results if they are used on the same
 variable or memory location more than once in the same expression. The
 order in which side effects occur within an expression is not
 specified.

 Do NOT expect any specific order of evaluation to take place. The
 discretion is left to the compiler on how it implements the evaluation
 order. The evaluation order could be affected by machine architecture
 and code optimization. Although such code may work sometimes, it is
 not guaranteed to work, and is therefore unsafe.

 Note: Kernighan and Ritchie do an excellent job explaining the ANSI C
 Standard for the evaluation order of expressions in Section 2.12 of
 "The C Programming Language - 2nd Edition" by Kernighan and Ritchie.

 It is very easy to accidentally write nonportable code with the C
 language. Below are some other common examples of statements that can
 cause side effects during run time:

    printf("%d %d \n", ++n, power(2, n));   /* WRONG */

 The above statement can produce different results with different
 compilers, depending on whether "n" is incremented before "power" is
 called. The correct code would look like the following:

       n++;                                  /* CORRECT */
       printf("%d %d \n", n, power(2, n));

 Another common pitfall is the following:

       a[i] = i++;     /* WRONG */

 The question is whether the subscript of "a" is the old value of "i"
 or the new value. Again the correct code would be the following:

       a[i] = a[i+1];    /* CORRECT */
       i++;

 Another example is as follows:

       int x[10], *p = x;

       *p++ = *p++ = 0;  /* WRONG */

 The compiler is allowed to "p" twice at the end after doing the two
 assignments, if it so chooses. To ensure correct code generation, you
 must code as follows:

       *p++ = 0;  *p++ = 0;   /* CORRECT */

 In general, any object may have its stored value modified at most once
 in a single expression; in addition, the prior value shall be accessed
 only to determine the value to be stored. Therefore,

       i = i + 1;    /* OK */

 is allowed because "i" is modified only once, and "i" is accessed only
 to determine what to store in "i", but

       i = ++i + 1;  /* UNDEFINED */

 is undefined because "i" is modified more than once in the course of
 the evaluation of the expression.

 Instead, the following pair of statements is correct:

       ++i;
       i = i + 1;    /* OK */

 The statement

       a[i] = i++;  /* UNDEFINED */

 is undefined, because, although "i" is only modified once, it is
 accessed both to determine the value to be stored in "i" by the ++
 operator and as a subscript.


 9. Memory Not Freed by DOS 2.x for exec or spawn with P_OVERLAY

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | tar57672
 Last Modified: 21-SEP-1988    ArticleIdent: Q24910

 Within DOS Versions 2.x only, recurrent use of an exec function or a
 spawn function with P_OVERLAY eventually causes a return indicating
 that there is no more available RAM memory.

 This is a DOS Versions 2.x problem, whose exact nature is unknown.
 Microsoft has traced the problem to the point where DOS corrupted
 memory, and memory is not being freed back to DOS Versions 2.x.

 If you encounter this problem, upgrade to DOS Versions 3.x, which
 do not have this problem.

 It appears that only the exec() family (or spawn() with P_OVERLAY
 specified) is affected by this DOS problem. The spawn() family (except
 when P_OVERLAY is specified) seems to work correctly.


 10. Variables in C 5.00/5.10 splitpath() Example Declared Wrong

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 11-FEB-1991    ArticleIdent: Q26589

 On page 560 of the "Microsoft C Optimizing Compiler: Run-Time Library
 Reference" that shipped with C versions 5.00 and 5.10, the example for
 the _splitpath() function declares its variables incorrectly. It
 declares arrays of pointers, rather than arrays of characters, as
 follows:

    char * drive [3];
    char * dir [30];
    char * fname [9];
    char * ext [4];

 The correct declaration should be as follows:

    char drive [3];
    char dir [30];
    char fname [9];
    char ext [4];

 Both declarations work correctly, but unpredictable results may occur
 with the original form of the array declarations.


 11. _amblksiz Not Declared

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-SEP-1988    ArticleIdent: Q26778

 Page 33 of the "Microsoft C Compiler Run-Time Library Reference
 Manual" (Page 31 for Version 4.00) incorrectly states that _amblksiz
 "is declared in the include file malloc.h". It is not there.

 You can use the variable in your program by declaring the variable as
 follows:

 extern unsigned int _amblksiz;


 12. _remapallpalette Example Causes C4049 Warning

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-SEP-1988    ArticleIdent: Q27803

 Problem:

 I get a warning C4049 when I run the example on Page 489 of the C
 Versions 5.00 and 5.10 "Run-Time Library Reference," in the section on
 _remapallpalette and _remappalette.

 Response:

 There is an error in the example program. The following line:

 _remapallpalette((char *)(&(colorsarray[0])));

 should read as follows to avoid the warning message:

 _remapallpalette((long far *)(&(colorsarray[0])));


 13. The struct videoconfig Declaration

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-SEP-1988    ArticleIdent: Q27804

 Page 342 of the "Microsoft C Run-Time Library Reference" manual for
 Version 5.00 has an omission. The struct videoconfig declaration
 member list leaves out the following four lines: mode, adaptor,
 monitor, and memory.

 The following is the structure as shown in the manual (incorrect):

 struct videoconfig {
   short numxpixels;   /* number of pixels on X axis */
   short numypixels;   /* number of pixels on Y axis */
   short numtextcols;  /* number of text columns available */
   short numtextrows;  /* number of text rows available */
   short numcolors;    /* number of actual colors */
   short bitsperpixel; /* number of bits per pixel */
   short numvideopages;/* number of available video pages */
 }

 The following is the structure as defined in GRAPH.H (correct):

 struct videoconfig {
   short numxpixels;   /* number of pixels on X axis */
   short numypixels;   /* number of pixels on Y axis */
   short numtextcols;  /* number of text columns available */
   short numtextrows;  /* number of text rows available */
   short numcolors;    /* number of actual colors */
   short bitsperpixel; /* number of bits per pixel */
   short numvideopages;/* number of available video pages */
   short mode;         /* current video mode */
   short adapter;      /* active display adapter */
   short monitor;      /* active display monitor */
   short memory;       /* adapter video memory in K bytes */
 }


 14. Beginner's Concerns for Writing Non-PM Graphic Applications

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | TAR73919
 Last Modified: 12-OCT-1988    ArticleIdent: Q28141

 Question:
    I have an OS/2 application (an analog simulator with postprocessor)
 that is ready to go, with the exception of the GRAPHICS output. I have
 been having difficulties getting graphics to work under OS/2. Can you
 give me any suggestions on how to use graphics?

 Response:
    The first problem is to get "addressability" to the video RAM. This
 is accomplished by using the VioGetPhysBuf API. For an EGA monitor the
 calling sequence would be as follows:

 struct    PhysBufData physbuf;
 char  far *base1, far *base2;

      physbuf.buf_start = 0xa0000;
      physbuf.buf_length = 0x20000;
      rcode = VIOGETPHYSBUF (&physbuf, 0);
      FP_SEG (base1) = physbuf.selectors[0];
      FP_OFF (base1) = 0;
      FP_SEG (base2) = physbuf.selectors[1];
      FP_OFF (base2) = 0;

 where base1 is the first 64K of memory on the EGA card, and base2
 would be the next 64K of memory. If you wanted to access more than
 128K you would have to increase the length and allocate space for more
 physbuf.selectors. (Look up this API.)
    Once you have valid pointers to the video memory, you still have
 more limitations. You can (should) not use these pointers unless your
 application is in the foreground. You must (should) inform the
 operating system before using the pointers. You use the API VioScrLock
 to lock your process into the foreground while you are writing to
 video memory. Once you are done writing to the video memory you must
 call VioScrUnLock, to re-enable screen switching. You should not keep
 the screen locked on any more time then absolutely necessary. (See
 this API for restrictions.) If your application attempts to write to
 the video memory when it is not in the foreground, it will gp_fault.
    Since your application is putting the monitor into graphics mode,
 it is its responsibility to save and restore the monitor's contents
 and mode. The application will have to use the API's VioSavRedrawWait
 and VioModeWait. VioSavRedrawWait is for the notification of when you
 should save or restore your screen image. VioModeWait is notified when
 you should save and restore video modes.
    Finally, if you plan to use I/O ports with your program you will
 have to "flag" it as needing IOPL (input/output privilege level). You
 do this by putting "CODE IOPL" in the program's definition file, and
 in config.os2 "IOPL=YES".

 API's to review:
      VioGetPhysBuf
      VioScrLock
      VioScrUnLock
      VioModeWait
      VioRedrawWait


 15. Include Directories Not Searched as Expected

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  5-DEC-1988    ArticleIdent: Q38383

 Question:

 It appears that the C compiler searches the INCLUDE list in the wrong
 order. Our INCLUDE=OS2\INC;\INC, but the compiler seemed to get an old
 version of the .h file from \INC. Deleting the old versions from \INC
 corrected the problem.

 Response:

 While the search order for a file enclosed in <>'s is simple, the
 order for a file enclosed in ""'s is different and more complicated.

 You are probably using ""'s rather than <>'s around the filename, and
 you've accidentally set up \INC as a "parent" or "grandparent"
 directory. (See below for more information.) To correct the problem,
 either use <>'s around the filename or reorganize your header files so
 that the search order will find the right file.

 Note: if you use ""'s around a complete path specification, the
 standard directories will NOT be searched.

 As documented on Page 202 in the "Microsoft C Language Reference" and
 on Page 80 of the "Microsoft C Optimizing Compiler User's Guide," the
 search order for #include <file.h> is as follows:

 1. Any directories specified using the /I switch on the cl command
    line, from left to right

 2. Directories specified in the include environment variable, again
    from left to right

 3. If the file is found in neither of these steps, the following
    message is issued:

       fatal error C1015:  cannot open include file 'file.h'

 For the following example, only the "\path" directory on the current
 default drive is searched:

    #include "\path\file.h"

 The standard directories will not be searched. However, the search
 order for:

    #include "file.h"

 is similar to the search order for:

    #include <file.h>

 except that "parent directories" are searched before directories
 specified by the /I switch and before directories specified in the
 INCLUDE environment variable.

 The parent directory is the directory that contains the source
 containing the #include directive. If #include files are nested, then
 the parent directories are searched in reverse order of the nesting:
 first parents, then grandparents, and so on.

 For example, if source file grandma.c contains:

    #include <parent.h>

 and parent.h contains:

    #include "child.h"

 the search for child.h would take place in the following order:

 1. The parent directory--in this case, the directory in which parent.h
    was previously found.

 2. If child.h was not there, the directory that contains grandma.c
    would be searched next.

 3. If child.h was still not found, the directories (if any) specified
    in /I switches on the CL command line would be searched in
    left-to-right order.

 4. If child.h was still not found, the directories (if any) specified
    by the INCLUDE environment variable would be searched in
    left-to-right order.

 5. If child.h was not found in any of these places, the compiler would
    give the following message:

       fatal error C1015:  cannot open include file 'child.h'


 16. Hexadecimal Unsigned Char Array Elements Missing "\"

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q28349

 The sample programs on Pages 325 and 521 of the "Microsoft C 5.1
 Optimizing Compiler Run-Time Library Reference" manual are incorrect.
 For the _getfillmask and _setfillmask examples, the unsigned char
 array element values should be shown with backslackes "\" preceding
 the x's to indicate that they are hexadecimal values.


 17. Reference Page 75 Example 9 Causes Error C2147

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q28567

 Using example nine on Page 75 of the "Microsoft C 5.1 Optimizing
 Compiler Language Reference" manual causes the compiler error
 "C2147: array: unknown size" on the line "(int *) p++".

 The example is incorrect. Instead of using example nine, use one of
 the two following examples:

 1. ((int*) p)++;
 2. p = (void *) ((char *) p + sizeof(int));

 Note that the expression "((int *) p)++" is a non-standard extension
 to the language, and the compiler will issue a warning.

 See Pages 99-100 of the user's guide for a discussion of enabling
 and disabling language extensions with the /Ze and /Za switches.
 There is an example at the bottom of Page 99, which is almost
 identical.

 Example nine on Page 75 is as follows:

         int i;
         void *p;

         p = &i;
         (int *) p++;

 The expression "(int *) p++" generates the C2147 error because the
 "++" operation is preformed before the "(int *)" cast. Thus, the
 expression is trying to increment a pointer that points to a void.
 Because void has no size, the compiler does not know how many bytes
 "p" should be incremented by.

 By using the extra parentheses in the expression "((int *) p)++", you
 are forcing the "(int *)" to convert "p" from a pointer-to-void to a
 pointer-to-int, which can be incremented.

 The second workaround, "p = (void *) ((char *) p + sizeof(int))",
 works correctly because you are telling the compiler how many bytes to
 increment the pointer.

 The second workaround is standard ANSI C and should compile on any
 standard ANSI C compiler.



 18. Example of TSR Program

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | APPNOTE
 Last Modified: 20-MAY-1988    ArticleIdent: Q28568

    The following article shows how to use Microsoft C to write a
 terminate-and-stay-resident (TSR) program. The article also
 illustrates the use of the following C run-time functions:

    _dos_setvect
    _dos_getvect
    _dos_keep
    _chain_intr
    spawnXXX

    The following example shows how to use Microsoft C to write a TSR
 program:

 /**************************************************************/
 /*                                                            */
 /*                            DirZap.h                        */
 /*                                                            */
 /*       This header file defines global variables, macros,   */
 /*       function pointers, and function prototypes           */
 /*       necessary for the DirZap.c program.                  */
 /*                                                            */
 /**************************************************************/

 /* Global Variable For Macro SHIFTL(x, n)*/
 long _ADDRESS;

 /* Macro Definitions */
 #define INT5  0x5
 #define INT21 0x21
 #define SHIFTL(x, n) (_ADDRESS = 0L, _ADDRESS = (long) x, _ADDRESS << n)
 #define HIBYTE(x) (((unsigned) (x) >> 8) & 0xff)
 #define REGPAK unsigned es, unsigned ds, unsigned di, unsigned si,\
                unsigned bp, unsigned sp, unsigned bx, unsigned dx,\
                unsigned cx, unsigned ax, unsigned ip,unsigned  cs,\
                unsigned flags

 /* Function Pointers */
 void (interrupt far *save_dir_adr)();
    /* Saves address of the original interrupt service routine */

 void (interrupt far *set_dir_adr)();
   /* This function pointer gets set to the address of the new
    interrupt service routine 'set_dir' */

 void (interrupt far *reset_dir_adr)();
    /* This function pointer gets set to the address of the new
    interrupt service routine 'reset_dir' */

 /* Function Declarations */
 void cdecl interrupt far set_dir(REGPAK);
    /* This is the new service routine whichs zaps the directory
    interrupt routines. */

 void interrupt far reset_dir(void);
    /* This routine toggles between setting and disabling the
    directory interrupt routines */

 unsigned _get_memsize(void);
    /* This function gets the number of bytes to keep resident */

 short _set_shell(void);
    /* Sets a DOS shell. */

 /**************************************************************/
 /*                                                            */
 /*                       DirZap.c                             */
 /*                                                            */
 /*        This is an illustration of a TSR program.           */
 /*     It traps and zaps the directory interrupts for         */
 /*     MkDir, RmDir, and ChDir. It also illustates how        */
 /*     to set a DOS shell by executing a new version of       */
 /*     COMMAND.COM.                                           */
 /*                                                            */
 /*     Copyright (c) Microsoft Corp 1988. All rights          */
 /*     reserved.                                              */
 /*                                                            */
 /*        To run, do the following:                           */
 /*                                                            */
 /*        1. EXEPACK DirZap to save memory.                   */
 /*        2. Type DirZap at DOS prompt. DirZap sets a         */
 /*        DOS shell and is not yet active.                    */
 /*        3. When "exit" is typed, DirZap is invoked.         */
 /*                                                            */
 /*        The PRINT SCREEN key now toggles                    */
 /*        DirZap on and off, but no memory has been           */
 /*        freed.                                              */
 /*                                                            */
 /**************************************************************/
 /*                                                            */
 /* NOTE:                                                      */
 /*                                                            */
 /* THIS PROGRAM, ITS USE, OPERATION, AND SUPPORT ARE PROVIDED */
 /* "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR  */
 /* IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED        */
 /* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR */
 /* PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE */
 /* OF THIS PROGRAM IS WITH THE USER. IN NO EVENT SHALL        */
 /* MICROSOFT BE LIABLE FOR ANY DAMAGES INCLUDING, WITHOUT     */
 /* LIMITATION, ANY LOST PROFITS, LOST SAVINGS OR OTHER        */
 /* INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING FROM THE USE   */
 /* OR INABILITY TO USE SUCH PROGRAM, EVEN IF MICROSOFT HAS    */
 /* BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES OR FOR ANY */
 /* CLAIM BY ANY OTHER PARTY.                                  */
 /*                                                            */
 /**************************************************************/
 #include <dos.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <process.h>
 #include <dirzap.h>

 extern unsigned _psp;
    /* Pre-defined varible, _psp = segment address of PSP */
 unsigned far *psp_pointer;
    /* Used to retrieve the memsize to stay resident */
 short hot_key=1;
    /* Flag to toggle DirZap on and off once it is invoked */

 void main(void);
 void main()
 {
    if (_set_shell())
    {
       /* Set trap for directory interrupts */
       save_dir_adr = _dos_getvect(INT21);
          /* Save original routine address */
       set_dir_adr = set_dir;
          /* Get address of new (user defined) routine  */
       _dos_setvect(INT21, set_dir_adr);
          /* Revector to new service routine */

       /* Set trap for PRINT SCREEN interrupt */
       reset_dir_adr = reset_dir;
          /* Get address of new routine */
       _dos_setvect(INT5, reset_dir_adr);
          /* Revector to new routine */

       /* Blast off into memory and reside until
       power down or CTRL-ALT-DEL */

       _dos_keep(0, _get_memsize());
    }
    else
       puts("problems running DirZap.exe, COMSPEC not found!");
 }

 void cdecl interrupt far set_dir(REGPAK)
 {

 /*
    Trap directory interrupts MkDir, RmDir, and ChDir and zap the
 string entered by the user. DS:DX points to the string, so change it
 to a string of length 0. WARNING: When compiled at high warning
 levels, several warnings are generated. This is because several
 elements of REGPAK are not referenced. These warnings should be
 ignored.
 */
    if (HIBYTE(ax) == 0x39 || HIBYTE(ax) == 0x3A || HIBYTE(ax) == 0x3B)
       dx=0;
    _chain_intr(save_dir_adr);
 }

 void interrupt far reset_dir()
 {
    if (hot_key)
    {
       hot_key=0;
       _dos_setvect(INT21, save_dir_adr); /* Reset initial vector */

       }
    else
    {
       hot_key=1;
       _dos_setvect(INT21, set_dir_adr); /* Install DirZap again */
       _chain_intr(set_dir_adr); /* Chain to the Zapper function */
    }
 }

 unsigned _get_memsize()
 {
    psp_pointer = (int far *) SHIFTL(_psp, 16); /* Get segment of the PSP*/
    return(psp_pointer[1] - _psp); /* Amount of memory to stay resident */
 }

 short _set_shell()
 {
    char *_COMSPEC_;

    _COMSPEC_ = getenv("COMSPEC"); /* Get value of COMSPEC */
    if (_COMSPEC_) /* If not equal to NULL */
    {
       puts("type 'EXIT' to invoke DirZapper...");
       spawnlp(P_WAIT, _COMSPEC_, NULL); /* Invoke Command.com */
       return(1);
    }
    return(0);
 }


 19. Object Module Format Extensions

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-NOV-1988    ArticleIdent: Q28613

 The following are Microsoft extensions to the Intel object module
 format that were incorporated in Versions 5.00 and 5.10 of the C
 compiler. For a complete description of the object module format, you
 can contact Microsoft System Languages Technical Support at (206)
 454-2030 and request the Object Module Format Application Note.

 Microsoft OMF Extensions

 Local Symbols (C 5.00) -- B4h, B6h, B7h, B8h

 There will be three new record types to handle local symbols:

 1. LEXTDEF = 0xb4 (180)
    Format is identical to EXTDEF.

 2. LPUBDEF = 0xb6 (182) or 0xb7 (183)
    Format is identical to PUBDEF.

 3. LCOMDEF = 0xb8 (184)
    Format is identical to COMDEF.

 LEXTDEF, LPUBDEF, and LCOMDEF are to be used exactly as EXTDEF,
 PUBDEF, and COMDEF, except that the symbols are not visible outside
 the module where they are defined--for example, C statics.

 New OMF Comment -- Class A1h

 A comment record with class A1h indicates that the obsolete method of
 communal representation through TYPDEF and EXTDEF pairs is not used,
 and that COMDEF records can be interpreted. The meaning of this record
 is undergoing revision.

 IMPDEF (OS2, Windows) -- Comment Class A0h, Subtype 1

 The IMPort DEFinition (IMPDEF) record takes the form of a COMENT
 record with class 0xa0:

     DB      88h         ; COMENT
     DW      reclen      ; record length
     DB      00h         ; for Intel compatibility
     DB      A0h         ; class: OMF extension
     DB      01h         ; subtype: IMPDEF
     DB      fOrd        ; nonzero value means import by ordinal
     ; Internal Name
     DB      n           ; length of name
     DB      n dup(?)    ; ASCII text of name
     ; Module Name
     DB      n           ; length of name
     DB      n dup(?)    ; ASCII text of name
 IF import by name (fOrd == 0)
     ;   Imported Name:  if length byte is 0 then imported name is
     ;   identical to internal name.
     ;
     DB      n           ; length of name
     DB      n dup(?)    ; ASCII text of name
 ELSE
     DW      ordno       ; ordinal number
 ENDIF

     DB      checksum

 EXPDEF (C 5.10) -- Comment Class A0h, Subtype 2

 The EXPort DEFinition record takes the form of a COMENT record with
 class 0xa0:

     DB      88h         ; COMENT
     DW      reclen      ; record length
     DB      00h         ; for Intel compatibility
     DB      A0h         ; class: OMF extension
     DB      02h         ; extension type:  EXPDEF
     DB      flags
         ;   80h = set if ordinal number specified
         ;   40h = set if RESIDENTNAME
         ;   20h = set if NODATA
         ;   1Fh = # of parameter words

     ; Exported name:
     DB      n           ; length of name
     DB      n dup(?)    ; ASCII text of name

     ; IF internal name different from exported name:
     DB      n           ; length of name
     DB      n dup(?)    ; ASCII text of name
     ; ELSE internal name same as exported name:
     DB      00h

     ; IF ordinal number specified
     DW      ordno       ; ordinal number

     DB      checksum

 LIBMOD Comment Record -- Class A3h (LIB 3.07 in MASM 5.00)

     DB      88h             ; COMENT
     DW      reclen          ; record length
     DB      00h             ; for Intel compatibility
     DB      A3h             ; class: LIBrary MODule name
     DB      N               ; length of module name
     DB      N dup(?)        ; ASCII text of module name
     DB      checksum

 The LIBMOD comment record identifies the name of a library module.
 This record allows LIB to preserve the source file name in the THEADR
 record and still identify the module name. Since the module name is
 the base name of the .OBJ file, the two names may be completely
 different.

 LIB adds a LIBMOD record when an .OBJ file is added to a library and
 strips the LIBMOD record when an .OBJ file is removed from a library,
 so this record usually only exists in .LIB files.


 20. Building C 5.10 Combined Libraries with the LIB Utility

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q28774

 Question:

 How does one go about building the combined libraries for C 5.10?

 Response:

 The preferred method for building the combined libraries is to use the
 SETUP program. To use SETUP to build libraries, you can run it with /L
 as a command-line parameter by typing the following

    a:setup /L

 at the DOS prompt with the SETUP disk in the drive A.

 If you have problems running the Setup program or you want to build
 the libraries manually using the LIB utility, you should build them as
 outlined in the following:

 1. Copy the appropriate library files to your hard disk. The memory
    model and floating-point option that you want to build will
    determine which library files are necessary. Refer to the file
    PACKING.LST to determine where each library file is located.

 2. Locate the LIB.EXE utility so that it is in your current directory
    or is located on your path.

 3. The details for how each library should be built are outlined
    below. These instructions assume that you will be using the default
    names for the real-mode libraries. The instructions also assume
    that you want graphics support built into your real-mode libraries
    (the graphics routines are not supported in protect mode). If this
    is not the case, do not include that library.

 The library name should be the command-line parameter to LIB.EXE. The
 question mark (?) is used to represent memory model (S, M, C, L) and
 you should substitute the appropriate letter when invoking the library
 manager. If you see the following prompt

    Library does not exist.  Create?

 you should respond with "y" to create the library and then provide the
 appropriate libraries at the next prompt which will be the
 "Operations:" prompt.

 The following is an example session:

 Assume that you want to build the small model emulator math library
 for real mode. This is how you would proceed from the DOS prompt
 assuming that you have already copied the correct component libraries
 to the following current directory:

 >lib slibce

 Microsoft (R) Library Manager  Version 3.08
 Copyright (C) Microsoft Corp 1983-1987.  All rights reserved.

 Library does not exist.  Create?y
 Operations:slibc.lib+libh.lib+em.lib+libfp.lib+graphics.lib;
 ---------------

 Here are the combine instructions for all combinations of the
 libraries:
 ---------------

 ?LIBCE.LIB-Real Mode mode emulator (?==S,M,C or L)

 Operations:?libc.lib+libh.lib+em.lib+?libfp.lib+graphics.lib;
 ---------------

 ?LIBCA.LIB-Real mode alternate math (?==S,M,C or L)

 Operations:?libc.lib+libh.lib+?libfa.lib+graphics.lib;
 ---------------

 ?LIBC7.LIB-Real mode 8087 (?==S,M,C or L)

 Operations:?libc.lib+libh.lib+87.lib+?libfp.lib+graphics.lib;
 ---------------

 ?LIBCEP.LIB-Protect mode emulator (?==S,M,C or L)

 Operations:?libcp.lib+libh.lib+em.lib+?libfp.lib;
 ---------------

 ?LIBCAP.LIB-Protect mode alternate math (?==S,M,C or L)

 Operations:?libcp.lib+libh.lib+?libfa.lib;
 ---------------

 ?LIBC7P.LIB-Protect mode 8087 (?==S,M,C or L)

 Operations:?libcp.lib+libh.lib+87.lib+?libfp.lib;


 21. Unresolved External on __Clpow with /Oi and /FPa in C 5.xx

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29188

 The C version 5.00 and 5.10 compilers generate an unresolved external
 reference to __CIpow when the sample program below is compiled with
 /Oi (or /Ox) and /FPa.

 Intrinsic optimization (/Oi) and the alternate floating-point option
 are not compatible and cannot be used together. This restriction is
 noted in the C 5.10 README.DOC. The maximum optimization that you can
 use with the alternate floating-point option is /Oalt.

 Sample Code
 -----------

    /* Compile with /Oi and /FPa  */

    #include <math.h>
    #include <stdio.h>

    main()
    {
    float  xx, yy;
    xx = 4.7;
    yy = 3.9;
    printf("%f", pow(xx,yy));
    }


 22. SORTDEMO.C/ BIND Use and Misuse

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-AUG-1989    ArticleIdent: Q29196

 The following article discusses a C Compiler Version 5.10 program
 called SORTDEMO.C, which is similar to the program that comes with
 QuickBasic Version 4.00.

 SORTDEMO.C for C Version 5.10 is for OS/2. It has OS/2 VIO, KBD, and
 DOS calls. If it has been bound, it can run in DOS and real-mode OS/2,
 as well as protected-mode OS/2.

 The following information details the correct way to run SORTDEMO.C
 (for a system targeting DOS):

    cl /Lp /Zp sortdemo.c
    bind sortdemo.exe c:\c\lib\doscalls.lib c:\c\lib\api.lib apilmr.obj

 The following is an example of several incorrect ways, their results,
 and their problems (for a system targeting DOS):

 1. Command: cl /Fb /Lp sortdemo.c (/Fb means to bind the application)

    Result: It links and appears to bind, but it hangs the computer
    when it runs from DOS.

    Problem: Apilmr.obj also needs to be bound. It must perform a
    separate bind.

 2. Command: cl /Fb /Lp sortdemo.c apilmr.obj

    Result: It links and appears to bind, but it hangs the computer
    when it runs from DOS.

    Problem: Apilmr.obj needs to be bound with the application because
    the application makes VIO calls and it accesses the near heap.

    Perform a separate bind (there is no way to bind in apilmr.obj from
    the cl compile line).

 3. Command: cl /Lp sortdemo.c /link doscalls.lib api.lib

    Result:  The linker gives the error: __acrtused multiply defined
    error.

    Problem: You should only link DOSCALLS.LIB. Bind it if it will be
    used under DOS.

 4. Command: cl  sortdemo.c

    Result:  The linker gives 13 unresolved externals, such as
    KBDCHARIN, VIO* and DOS*.

    Problem: SORTDEMO.C is an OS/2 application. The program must be
    compiled using the /Lp switch, and then bound if it will be used
    under DOS.

 5. Command: cl /Lp sortdemo.c or cl /Lp /Zp sortdemo.c

    Result:  It worked correctly for running under OS/2. To run under
    DOS, you must Bind it using the following:

    bind sortdemo.exe c:\c\lib\doscalls.lib c:\c\lib\api.lib apilmr.obj


 23. Why Pointer Subtraction Gives Signed Results

 Product Version(s): 3.00 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-MAR-1990    ArticleIdent: Q29197

    Pointer subtraction is performed in signed arithmetic. This can
 become confusing when the pointers being subtracted are more than 32K
 apart, because the result becomes a negative number.
    This is correct behavior for the C language as documented in the
 "Microsoft C Language Reference Manual" and the ANSI C Draft Proposed
 Standard.

    Consider the following code fragment:

         long size;
         char *ptr1, *ptr2;
         if (size < (ptr2 - ptr1))
           ...
    If the size is 32000, ptr1 is 0, and ptr2 is 33000, then ptr2 minus
 ptr1 exceeds the range of a signed value and is therefore negative.
 The comparison size (ptr2 - ptr1) is false, even though ptr1 and ptr2
 are 33000 elements apart.
    This situation is documented on Page 124 of the "Microsoft C
 Language Reference Manual," (Version 5.00 and Version 5.10) which says
 the following:

    "When two pointers are subtracted, the difference is converted to a
 signed integral value by dividing the difference by the size of a
 value of the type that the pointers address. The size of the integral
 value is defined by the type ptrdiff_t in the standard include file
 stddef.h."

    This also is documented on Page 3.3.6 of the November 9, 1987,
 edition of the Draft Proposed ANSI C Standard, which states the
 following:

    "The size of the result is implementation-defined, and its type (a
 signed integral type) is ptrdiff_t defined in the <stddef.h> header.
 As with any other arithmetic overflow, if the result does not fit in
 the space provided, the behavior is undefined."

    If you want to think of these pointers as unsigned quantities, you
 can typecast them as follows:

         long size;
         char *ptr1, *ptr2;
         if (size < ((unsigned) ptr2 - (unsigned) ptr1))
           ...


 24. Incorrect Interface Statement

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q29589

 The last example on Page 48 of the "Microsoft C 5.1 Optimizing
 Compiler Mixed-Language Programming Guide" reads as follows:

 INTERFACE TO FUNCTION REAL*8 CFUN [C] (I,J)

 This is incorrect. It should read as follows:

 INTERFACE TO REAL*8 FUNCTION CFUN [C] (I,J)


 25. Structure Packing: /Zp4 or #pragma pack(4), and /Zp2

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q29825

 The /Zp4 compiler option or #pragma pack(4) results in a more
 efficient use of space than indicated on Pages 100 to 102 in both the
 "Microsoft C 5.00 Optimizing Compiler User's Guide" and the "Microsoft
 C 5.10 Optimizing Compiler User's Guide." When the C compiler aligns
 structure members, it uses the /Zp4 or #pragma pack(4) (or /Zp2 or
 #pragma pack(2) values) as the maximum number of bytes for alignment,
 but will word (even-byte) align individual struct members whose size
 is one or two bytes. Contiguous char or array of char members that are
 immediately preceded by char members will be byte aligned.

 When specifying 4-byte (or 2-byte) boundaries for aligning structure
 members, the actual alignment is dependent on the size of the structure
 member. To avoid wasting space, the compiler will word align structure
 members that are one or two bytes in size. Structure members whose size
 is four or eight bytes or greater will be aligned on 4-byte boundaries
 with the /Zp4 switch or #pragma pack(4) as documented.

 Char or array of char struct members will be byte aligned if they are
 preceded by a char struct member, otherwise they will be word aligned.
 (Search on "Zp" and "char" to find articles with more information on
 the alignment of char struct members.)

 The sizeof operator correctly indicates the actual size of the
 structure with any alignment of struct members.

 Note that this struct member alignment is different than that which
 occurred with previous versions of Microsoft C compilers. If using
 object files containing structures produced by C 4.00 or earlier
 compiler versions, it may be necessary to use dummy bytes to word
 align contiguous char struct members.

 To gain complete control over the alignment of struct members, you may
 use the /Zp or /Zp1 compiler options, or #pragma pack(1), and pad your
 struct with an appropriate number of dummy char or array of char
 members.


 26. C 5.10 MTDYNA.DOC File: Single-Thread Dynamic-Link Libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-AUG-1989    ArticleIdent: Q29826

    The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C Version 5.10 MTDYNA.DOC file.

 5.1   Single-Thread Dynamic-Link Libraries
    The OS/2 support library, LLIBCDLL.LIB, is a large-model,
 single-thread  C run-time library for creating dynamic-link
 libraries. This support library is statically linked and uses only the
 alternate math library.
    To make the dynamic-link library independent of the program that
 calls it, the dynamic-link library must preserve the floating-point
 state and the status of the 80286 CPU registers. This is not possible
 with the emulator floating-point library, since it takes over the 287
 chip. However, math done with the alternate math library is done
 entirely with the 80286 registers. Since the status of the registers
 is preserved, the alternate math package fits the requirement for the
 single-thread dynamic-link library.
    The LLIBCDLL.LIB C OS/2 support library is not reentrant, and so
 only one thread per process may be executing in it. When creating a
 single-thread dynamic-link library, you should ensure that only one
 thread per process is ever executing in the C run-time library.
    A dynamic-link library written with LLIBCDLL.LIB can handle
 multiple threads within a process only by explicit serialization using
 semaphores or some similar mechanism to ensure that only one thread
 per process is executing in the C run-time library. In all cases the C
 run-time initialization code must be executed at program startup. This
 is normally done through the per-process automatic initialization
 mechanism provided to OS/2 dynamic-link libraries.
    Dynamic-link libraries created with this library must be linked
 with LLIBCDLL.LIB and DOSCALLS.LIB only. No other libraries should be
 used when linking.
    NOTE: This restriction on library use means that the compiler
 option /Lp must not be used with LLIBCDLL.LIB. If you are building
 objects for use with LLIBCDLL.LIB, you should use compiler option /Zl
 to suppress default-library search records in the object file. If
 not, you then MUST link with /NOD so that you do not get a default
 library (such as SLIBCE.LIB) linked in as well.
    This model uses the C register convention where AX, BX, CX, DX and
 ES are scratch registers. The direction flag is always assumed to be
 cleared ("up").
    The signal function is supported only for the SIGFPE signal. This
 floating-point exception is not a true signal, but is more like an
 exception.
    The DosSetSigHandler OS/2 API call should only be used with great
 caution since it can "steal" signals from the user program thereby
 causing problems in this environment.

 Editor's Note: The information above applies to single-thread DLL's
 linked with LLIBCDLL.LIB only. Multi-thread .EXE's built with
 LLIBCMT.LIB, or multi-thread DLL's that dynamically link to CRTLIB.DLL
 use emulator math only, and will use a coprocessor if it is present.



 27. C 5.10 MTDYNA.DOC: Threads

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29830

 The following information is from "Section 1: Introduction" of the
 Microsoft C version 5.10 MTDYNA.DOC file.

 1.1   Threads

 Three types of multitasking are present in OS/2: screen groups,
 processes, and threads. A screen group, the highest-level multitasking
 element, consists of one or more processes that share a logical screen
 and keyboard. For example, a word processor and a database operating
 simultaneously under OS/2 would represent two screen groups. A process
 is the part of an executing program that is the unit of ownership for
 resources such as memory, open files, and semaphores. Finally, a
 thread is the execution path within a process, and it is the smallest
 multitasking unit managed by OS/2. A process may consist of one or
 more threads.

 Two sample programs supplied with this release highlight the use of
 threads. The first example program, mhello.c, is a multiple-thread
 version of the classic "Hello world" program. The second example
 program, snap.c, uses multiple threads to capture screen images to a
 file.

 A pictorial representation of screen groups, processes, and threads is
 shown in Figure 1 below. Each screen group consists of two processes.
 These processes are composed of several threads. In any process,
 thread 1 is the main thread. All threads in a process are independent.

 Figure 1. Screen Groups, Processes, and Threads

 +============================================================================
 |
 |                                    OS/2
 |
 | +----------------------------------+  +----------------------------------+
 | |          Screen Group 1          |  |          Screen Group 2          |
 | | +------------+    +------------+ |  | +------------+    +------------+ |
 | | |  Process 1 |    |  Process 2 | |  | |  Process 1 |    |  Process 2 | |
 | | |            |    |            | |  | |            |    |            | |
 | | | *Thread 1* |    |            | |  | | *Thread 1* |    |  *Thread 1*| |
 | | |            |    | *Thread 1* | |  | | *Thread 2* |    |            | |
 | | | *Thread 2* |    |            | |  | | *Thread 3* |    |  *Thread 2*| |
 | | |            |    |            | |  | |            |    |            | |
 | | +------------+    +------------+ |  | +------------+    +------------+ |
 | |                                  |  |                                  |
 | +----------------------------------+  +----------------------------------+
 |
 +============================================================================


 28. C 5.10 MTDYNA.DOC: Dynamic-Link Libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29832

 The following information is from "Section 1: Introduction" of the
 Microsoft C version 5.10 MTDYNA.DOC file.

 1.2   Dynamic-Link Libraries

 A dynamic-link library is a set of routines that are linked with the
 program at either load time or run time rather than at the time of
 compilation.

 The easiest way to understand dynamic linking is to contrast it with
 the more familiar method of static linking.

 Static linking involves the following steps:

 1. Write and compile a program that calls routines (such as the
    printf() function) not in the source file. This produces an object
    file that contains a reference to the external printf() function.

 2. Link the object file with a library file containing the external
    function. This linking step combines the two files by including the
    code for the printf() function into the final executable file. In
    other words, the reference to printf() is resolved at link time.

 3. Run the executable file from step 2. This executable file is
    totally self contained (since it contains the code for the external
    function).

 Static linking is useful, but it has the following disadvantages:

 1. The finale executable code cannot be upgraded or changed without
    relinking to the main program's object files. In the commercial
    realm this means that a new release of a program requires that the
    entire executable file be replaced with a new version.

 2. Common sets of code cannot be shared. Any and all executable files
    that use the printf() function must explicitly link in this
    function. Thus, the code for printf()may be duplicated in many
    different executable files on a disk or in memory.

 Dynamic linking, on the other hand, involves the following general
 steps (the complete process is detailed in Section 5.0 below):

 1. Write and compile a program that references an external function,
    just as you do for static linking.

 2. Create a special definition file (.DEF extension) that specifies
    which functions the main program will import from the dynamic-link
    library.

 3. Link the main program with the appropriate dynamic-link library
    support library to produce an executable file. This file contains a
    reference to the external function in the dynamic-link library.
    This file does NOT contain any code from the external function.

 4. Create a dynamic-link library that contains the code referenced in
    the main program.

 5. Execute the program created in step 3. When this executable file is
    run, OS/2 loads the code and discovers the special reference to the
    dynamic-link library. For each external dynamic-link-library
    reference, OS/2 searches the dynamic-link-library directory and
    resolves the external reference at load time.

 The process of dynamic linking has the following advantages:

 1. An executable file is smaller since it does not contain the code
    for external functions.

 2. A program can be upgraded by supplying a new version of the
    dynamic-link library without relinking the executable file.

 3. Code may be shared between executable files. A common set of
    routines can be placed in a dynamic-link library and accessed by
    any number of executable files. In fact, the OS/2 operating system
    itself is a dynamic-link library. All of the OS/2 system functions
    are presented as external procedures that a user program can call.

 4. Linking is faster.


 29. C 5.10 MTDYNA.DOC: Multiple-Thread Programs

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 10-DEC-1990    ArticleIdent: Q29833

 The following information is from "Section 2: Multiple-Thread
 Programs" of the Microsoft C version 5.10 MTDYNA.DOC file.

 Multiple-Thread Programs
 ------------------------

 The simplest multiple-thread program is an independent self-contained
 program that is created by the static linking method.

 The support library LLIBCMT.LIB is a large-model library that supports
 the creation of multiple-thread programs. A multiple-thread program
 created with this library can be any memory model although all calls
 to the C run-time library must use the large-model calling interface.
 In other words, all pointers must be far.

 NOTE: The support library library LLIBCMT.LIB is a large model
 library. If you want to use pointers returned by the C run-time
 library, you must use the far keyword in the declaration of your
 variables. For example, if you want to call fopen(), you would need to
 say:

                 FILE far * fp;
                 fp = fopen (...);

 This C run-time library is used to create a program that is entirely
 self contained and that does not share C run-time code or data with
 any other programs or dynamic-link libraries.

 A multiple-thread program that uses this library must be linked with
 only LLIBCMT.LIB and DOSCALLS.LIB. No other C run-time libraries
 should be used in linking.

 NOTE: This restriction on library use means that the compiler option
 /Lp must not be used with LLIBCMT.LIB. If you are building objects for
 use with LLIBCMT.LIB, you should use compiler option /Zl to suppress
 default library search records in the object file. If not, you then
 must link with /NOD (/NODEFAULTLIBRARYSEARCH) so that you do not get a
 default library (such as SLIBCE.LIB) linked in as well.

 Programs created for this simple multiple-thread environment should
 use the special include files provided for this purpose. These files
 are normally stored in the MT subdirectory of your normal include
 directory and the constituent .h files have the same name as their
 regular C run-time counterparts.

 These special include files should only be used for creating
 multiple-thread programs. If the regular (that is, the include files
 in the \INCLUDE subdirectory) are used, multiple-thread programs will
 not work. Conversely, the multiple-thread include files should not be
 used to create nonthreaded C programs.

 Threads are managed in a multiple-thread program by the C functions
 _beginthread() and _endthread(). A description of these two functions
 is given below in Section 3.0. The OS/2 Applications Program Interface
 (API) call DosCreateThread should not be used. If the low-level API
 calls (DosCreateThread and DosExit) are used, the results are
 unpredictable.

 In a multiple-thread program, stack checking is done for each thread.

 Signal handling is complicated in a multiple-thread environment. In a
 multiple-thread environment, the C run-time function signal is not
 supported. Since OS/2 always gives thread 1 control when a signal is
 handled, thread 1 must not be executing in the C run-time library code
 when a signal is received. If this precaution is not followed, the
 possibility of deadlock arises. A deadlock occurs if a thread is
 waiting for a particular event that does not occur.

 Signal handling is managed in a multiple-thread environment by using
 the OS/2 API call DosSetSigHandler with the following restrictions:

 1. Thread 1 should be dedicated to signal handling and this thread
    should not call the C run-time library. When a signal is detected
    by thread 1, some type of semaphore or flag that will be polled
    from the other threads in the program should be set.

 2. The other threads check the status of semaphores set by thread 1
    and respond accordingly.


 30. C 5.10 MTDYNA.DOC: Sample MT Program/Description of Operation

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29835

 The following information is from "Section 4: Sample Multiple-Thread C
 Program" of the Microsoft C version 5.10 MTDYNA.DOC file.

 Sample Multiple-Thread C Program
 --------------------------------

 The subsections below describe the creation and operation of a
 multiple-thread version of the classic "Hello world" program.

 4.1   Description of operation

 The multiple-thread "Hello world" program brings up one thread for
 each command-line argument. Each thread will print "Hello world from
 thread <n>!" the number of times specified in the corresponding
 argument. The maximum number of threads supported in the
 multiple-thread library is 32.

 To use it, type

    mhello <arg1> <arg2> ... <up to 31 args>

 For example,

    mhello 2 4 6

 brings up 3 threads; the first thread says hello 2 times, the second
 thread says hello 4 times, the third thread says hello 6 times.

 In operation, the program works as follows:

 1. Brings up the requested number of threads with _beginthread

 2. Waits until all threads have been brought up

 3. Begins multiple-thread execution and waits for completion

 The explicit synchronization (by means of the flag variable
 Synchronize) is required because of the small time spent in the child
 code. Without this synchronization, all threads would begin as thread
 2. This occurs because the first spawned thread completes execution
 before the next request to create a thread is acted upon. The time
 slice allotted to any of the threads is much larger than the execution
 time spent in each thread. To get around this, bring up all of the
 threads and then simultaneously start them.

 An alternative method of synchronization between threads is to use
 semaphores. A semaphore is a software flag used to coordinate the
 activities of two or more threads. The use of semaphores for thread
 control is illustrated in the sample program, snap.c, which is
 included with this release.

 Using semaphores is a more elegant and efficient means of
 synchronizing threads. The DosSleep function causes threads to
 periodically wake up and check a flag, and thus, the following can
 occur:

 1. The thread wakes up when it doesn't have to and performs some
    processing only to find out it has to go to sleep again.

 2. The thread sleeps longer than it has to (i.e., the event it's
    waiting for has already occurred, but the thread is still sleeping
    until the sleep request expires).

 Programs should generally use semaphores, particularly when the wait
 time is non deterministic and potentially long (or forever).

 For the mhello.c example program, the use of DosSleep is appropriate
 for the following reasons:

 1. DosSleep is easily understood and has self-evident functionality.

 2. The program is not particularly time dependent, and the above two
    disadvantages will not hurt. Also, we know that this is a one time
    event, and that main code "quickly" wakes up the child-code portion
    of the program. That is, the DosSleep code path occurs once at
    start-up time and is never entered again during child execution.

    Also, the sleep time is short and deterministic. That is, we know
    the parent code sets the flag as soon as all the threads have been
    started. In other words, there is no chance for the parent code to
    do other things and leave the thread waiting for DosSleep for long
    periods of time.


 31. C 5.10 MTDYNA.DOC: Sample MT Program/Compiling and Linking

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29836

 The following information is from "Section 4: Sample Multiple-Thread C
 Program" of the Microsoft C version 5.10 MTDYNA.DOC file.

 4.2   Compiling and Linking a Multiple-Thread Program

 The program mhello.c is a statically linked multiple-thread program.
 The process of compiling and linking this program is given below:

 1. Ensure that the files LLIBCMT.LIB and DOSCALLS.LIB are available.

    The file LLIBCMT.LIB takes the place of the regular *.LIB files
    used in linking. It is a large-model library that supports the
    creation of statically linked multiple-thread programs. A
    multiple-thread program created with this library can be any memory
    model, although all calls to the C run-time library must use the
    large-model calling interface.

    The file DOSCALLS.LIB provides support for any OS/2 calls made in
    the multiple-thread program. In this example, the DosSleep function
    is used.

 2. Ensure that the special multiple-thread include files are used.
    These are normally stored in the MT subdirectory of the normal
    \INCLUDE directory. In this example, this is done by explicitly
    specifying them within the mhello.c program as shown below:

       #include <mt\malloc.h>

    The multiple-thread files may also be specified by using the \I
    option on the CL command line. The multiple-thread dynamic-link
    library example (Section 5.2.3) uses this method to specify an
    alternate include directory path.

 3. Compile the program with the following conditions set:

    a. Large code-pointer size
    b. Far data-pointer size
    c. Segment setup of SS not equal to DS; DS fixed

    These conditions are specified by setting up a customized memory
    model using the following CL command option:

       /Alfw

    The complete CL invocation is shown below:

       CL  /Alfw /c  mhello.c

 4. Link the resulting object file with LLIBCMT.LIB and DOSCALLS.LIB
    only. The default .LIB file should not be used. Specify the
    /NODEFAULTLIBRARY search option (/NOD) to ignore the default
    libraries.

    The complete LINK invocation is shown below:

       LINK  /NOD thread LLIBCMT.LIB DOSCALLS.LIB;

    An alternative invocation that invokes both the compiler and linker
    is shown below:

       CL /Alfw /Zl mhello.c /link llibcmt doscalls

 5. Run the program under OS/2.


 32. C 5.10 MTDYNA.DOC: Sample MT Program/Possible Problem Areas

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29837

 The following information is from "Section 4: Sample Multiple-Thread C
 Program" of the Microsoft C version 5.10 MTDYNA.DOC file.

 4.3   Possible Problem Areas

 Several possible problems may occur when creating, linking, or
 executing a multiple-thread C program. Some of the more common ones
 are listed below. The symptom is listed first, followed by the likely
 cause:

 1. LINK searches for xLIByz.LIB

    This is caused by omitting the /NOD option from the LINK command.
    If /NOD is omitted, LINK searches for the default library. The
    default library should NOT be used with multiple-thread programs.
    The /NOD option tells the computer not to search the default
    libraries. This problem may also be avoided by compiling with the
    /Zl option which suppresses default library search records in the
    object files.

 2. You get the following execution error:

       SYS1943: A program caused a protection violation.

    This is caused by failing to specify the condition "SS is not equal
    to DS" in the CL command invocation. Specify the correct conditions
    with the /Alfw customized memory-model option. Recompile the
    program with /Alfw.


 33. C 5.10 MTDYNA.DOC: Creating Dynamic-Link Libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29838

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 Creating Dynamic-Link Libraries

 You can create the following two types of dynamic-link libraries with
 this release of C:

 1. A stand-alone, single-thread dynamic-link library

 2. A C run-time dynamic-link library that supports multiple threads
    and is itself dynamically linked.

 The stand-alone dynamic-link library is independent of the calling
 program and is single thread only and statically linked. This isolated
 dynamic-link library is independent of the effects of other
 dynamic-link libraries and can be viewed conceptually as an extension
 of the operating system. Use the OS/2 support library, LLIBCDLL.LIB, a
 large-model, single-thread C run-time library for creating
 single-thread dynamic-link libraries. LLIBCDLL.LIB is statically
 linked and uses only the alternate math library.

 The dynamically-linked C run-time library may be used by a
 multiple-thread program and an optional group of dynamic-link
 libraries that are closely associated with it. Use the OS/2 support
 library, CDLLOBJS.LIB to create a C run-time library that is
 dynamically linked.

 Dynamic-link libraries can be debugged with the protected-mode
 CodeView debugger (CVP). For more information on this topic, see
 Section 2.2.2 "Debugging Dynamic-Link Modules" in the Microsoft
 CodeView and Utilities Update document.


 34. C 5.10 MTDYNA.DOC: Component Files of a Single Thread DLL

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29839

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C Version 5.10 MTDYNA.DOC file.

 5.1.1 Component Files of Single-Thread Dynamic-Link Libraries

 Several files are supplied for the creation of single-thread
 dynamic-link libraries. A list and brief description of the files
 supplied with this release is shown below:

    DOSCALLS.LIB     OS/2 support library.

    LLIBCDLL.LIB     Large-model single-thread C run-time library
                     for dynamic-link library support.

    xLIByP.LIB       Any protected-mode C run-time library; used to
                     link sample main program.

    STMAIN.C         Sample main program (single-thread version).
    STMAIN.DEF       Module-definition file for main program
                     (single-thread).

    STDLL.C          Sample dynamic-link library file.
    STDLL.DEF        Module-definition file for STDLL.C.

    MKSTDLL.CMD      OS/2 batch file for creating single-thread
                     dynamic-link library.


 35. C 5.10 MTDYNA.DOC: Creating a Single Thread DLL

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29840

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 5.1.2   Creating a Single-Thread Dynamic-Link Library

 The process of creating a single-thread dynamic-link library is
 outlined below:

 1. Create a definition file (.DEF extension) for the main program
    (STMAIN.DEF). This definition file specifies which functions it
    will import from the dynamic-link library. In this simple example,
    the file STMAIN.DEF contains the following:

       NAME STMAIN
       IMPORTS STDLL._DynalibTest

 2. Create a definition file for the dynamic-link library (STDLL.DEF)
    that specifies which functions it will export. In this simple
    example, the file STDLL.DEF contains the following:

       LIBRARY STDLL
       DESCRIPTION 'Sample Dynamic-Link Library written in Microsoft C'
       PROTMODE
       EXPORTS _DynalibTest
       DATA MULTIPLE

 3. Compile the main program. The program may be compiled using any
    memory model and any math package. Since the sample single-thread
    dynamic-link library (STDLL.C) uses far data, the sample main
    program (STMAIN.C) can be compiled as either compact or large
    memory model. For a compact memory model, the C compiler is invoked
    with something like this:

       cl /AC /G2 /c stmain.c

 4. Link the main program to produce STMAIN.EXE. The following files
    are linked together:

       STMAIN.OBJ     Output from step 3
       DOSCALLS.LIB   OS/2 support library
       CLIBCEP.LIB    Any regular C run-time library (in this
                      case, compact memory model, emulator math
                      package)
       STMAIN.DEF     Main definition-module (single thread)
       STMAIN.EXE     Output from LINK (single thread)

    The linker is invoked with something like this:

       link stmain.obj/noi,,, clibcep.lib doscalls.lib/nod,stmain.def;

 5. Compile the dynamic-link library module. The module should be
    compiled with the /ALfw option which specifies large-code pointer
    size, far-data pointer size and a segment setup of SS not equal to
    DS; DS fixed. Stack checking should also be turned off. The C
    compiler is invoked with something like this:

       cl /Alfw /G2 /Gs /c stdll.c

 6. Link the dynamic-link library module to produce STDLL.DLL. The
    following files are linked together:

       STDLL.OBJ      Output from step 5
       DOSCALLS.LIB   OS/2 support library
       LLIBCDLL.LIB   Single-thread dynamic-link library C
                      run-time support library
       STDLL.DEF      Dynamic-link library definition-module
       STDLL.DLL      Output from LINK

    The linker is invoked with something like this:

       link stdll.obj,stdll.dll/noi,,llibcdll.lib doscalls.lib/nod,stdll.def;

 7. Place the STDLL.DLL file (from step 6) in a directory on your
    LIBPATH so OS/2 is able to find it. Then run the program
    STMAIN.EXE. If the dynamic-link-library file is not in your
    LIBPATH, OS/2 is not be able to run STMAIN.EXE.

 Note: The LIBPATH is set in your CONFIG.SYS or CONFIG.OS2 file,
 depending on which version of OS/2 you are using. LIBPATH is not part
 of your environment strings like the LIB, INCLUDE and PATH variables.


 36. C 5.10 MTDYNA.DOC: Multiple Thread Dynamic-Link libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29841

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 5.2   Multiple-Thread Dynamic-Link Libraries

 The CDLLOBJS.LIB OS/2 support file is an object-file library used to
 create a dynamically linked C run-time library. This library is
 provided as an object library with an associated definition file. This
 allows the programmer to choose only those run-time modules that are
 required for a particular application.

 The C run-time library created with this support file is dynamically
 linked and may be used by a multiple-thread program and an optional
 group of dynamic-link libraries that are closely associated with it.

 The "close association" of the multiple-thread program, the C run-time
 library and a group of dynamic-link libraries is shown in Figure 2.

         +----------------------------------------------------+
         |                                                    |
         |                +----------+        +----------+    |
         |                |          |        |          |    |
         |  +-----------> | DLL1.DLL |<------>| DLL2.DLL |<---+
         |  |             |          |<-+     |          |<----------+
         |  |             +----------+  |     +----------+           |
     +-------------+                    |                            |
     |             |                    |                            |
     | PROGRAM.EXE |                    |                            |
     |             |<---+               |                            |
     +-------------+    |               |                            |
                        |               |   +--------------------+   |
                        |               |   |                    |   |
                        |               +-->|   C Run-time DLL   |<--+
                        +------------------>|     CRTLIB.DLL     |
                                            +--------------------+

      Figure 2. Relationship between Multiple-Thread Program, C
                Run-Time Library, and Dynamic-Link Libraries

 The main program (PROGRAM.EXE) and the two dynamic-link libraries
 (DLL1.DLL and DLL2.DLL) share the C run-time data (in CRTLIB.DLL). The
 PROG.EXE, DLL1.DLL, and DLL2.DLL files each have their own data
 segment that is not shared. The C run-time dynamic-link library is
 closely tied to the program (PROGRAM.EXE) and the other dynamic-link
 libraries (DLL1.DLL and DLL2.DLL), since the file CRTLIB.DLL contains
 such things as shared environment strings, global C run-time data, and
 thread identification numbers.

 A program built using the dynamically linked multiple-thread support
 of the C run-time library may share the C run-time library with one or
 more dynamic-link libraries that are closely related to it. C run-time
 global data (such as the standard I/O package FILE, pointers of
 buffered I/O, and memory allocated with malloc functions) is shared.
 This means that the program and the associated dynamic-link libraries
 must cooperate on the usage of this data.

 Before compiling any programs using routines from the dynamic-link
 library's object library CDLLOBJS.LIB, ensure that the MT include
 files are being used (rather than the standard include files), and
 that the symbol DLL is defined.

 If the multiple-thread include files are placed in a subdirectory of
 the normal INCLUDE directory the following style of include can be
 used:

     #include  <mt\stdio.h>       /* multiple-thread version */

 A better approach is to specify a special search path for include
 files by using the /I option on the CL command line. In this method,
 the /I adds the specified directory to the front of the list of
 directories to be searched for include files. A typical use of the /I
 option is shown below:

     cl /I\include\mt /AS /Gs2 /DDLL /c mtmain.c

 This method has the advantage that the program can refer to <stdio.h>,
 and the appropriate version can be selected at compile time. This
 approach is used in the sample programs mtmain.c and mtdll.c. If
 multiple include paths are required, you can specify them with
 multiple /I options. The include paths are searched in the order in
 which they appear on the CL command line.

 The symbol DLL is used to distinguish between multiple-thread programs
 using LLIBCMT.LIB (where the symbol DLL is not defined) and programs
 using the dynamically linked C run-time library (where the symbol DLL
 is defined), which also supports multiple threads.)  This ensures that
 the appropriate data references (e.g. stdout) are resolved correctly.
 The symbol DLL may be defined in one of the ways shown below:

 1. Compile with the /D option on the CL command line. The use of this
    option is explained in Section 3.3.9.1 of the Microsoft C
    Optimizing Compiler User's Guide. The syntax of the /D option is

       CL  /DDLL myprog.c

 2. Explicitly define the DLL symbol prior to any other preprocessor
    directives in your source file. This option is shown below:

       #define DLL
       #include < ... >    /* include files as needed */

 Threads are managed in a dynamic-link library created in this
 environment by the C functions _beginthread() and _endthread(). The
 OS/2 API call DosCreateThread should not be used. A description of
 these two functions is given in Section 3.0.


 37. C 5.10 MTDYNA.DOC: Component Files of MTDYNA Libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29842

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 5.2.1   Component Files of Multiple-Thread Dynamic-Link Libraries

 A large number of files are supplied for the creation of
 multiple-thread dynamic-link libraries. A list and brief description
 of the files supplied with this release is shown below:

    CRTDLL.OBJ         Start-up code for dynamic-link library files.
    CRTEXE.OBJ         Start-up code for executable files.
    CRTLIB.OBJ         Start-up code for C run-time library.

    CDLLOBJS.LIB       C run-time library objects.
    CDLLOBJS.DEF       Module-definition file that contains the entry
                       points for all C functions.
    CDLLOBJS.CMD       OS/2 batch file to create multiple-thread C
                       run-time dynamic-link library.

    CDLLSUPP.LIB       Supplemental file that contains C run-time
                       information that cannot be dynamically linked.

    MTMAIN.C           Sample main program (multiple thread).
    MTMAIN.DEF         Module-definition file for main (multiple
                       thread).

    MTDLL.C            Sample dynamic-link library file (multiple
                       thread).
    MTDLL.DEF          Module-definition file for DLL.C (multiple
                       thread).

    MKMTDLL.CMD        OS/2 batch file for creating multiple-thread
                       dynamic-link library.


 38. C 5.10 MTDYNA.DOC: Creating an MTDYNA Library

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29843

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 5.2.2   Creating a Multiple-Thread Dynamic-Link Library

 The process of creating a multiple-thread dynamic-link library is
 outlined below. The process of creating a multiple-thread dynamic-link
 library is also contained in the file CDLLOBJS.CMD.

 1. Create a definition file that specifies the exports from the C
    run-time library for the dynamic-link library. The file
    CDLLOBJS.DEF, which is included in this release, is a sample
    definition file that includes all of the C run-time functions
    currently supported.

 2. Link the special start-up file CRTLIB.OBJ with CDLLOBJS.LIB,
    DOSCALLS.LIB, and the definition file (CDLLOBJS.DEF) from step 1.
    This creates a customized C run-time dynamic-link library file
    (named CRTLIB.DLL). The following files are linked together:

       crtlib.obj     Start-up code for library files
       cdllobjs.lib   C run-time library objects
       doscalls.lib   OS/2 support library
       cdllobjs.def   Definition module from step 1
       crtlib.dll     Output from LINK

 The command to accomplish this is shown below:

 link crtlib.obj,crtlib.dll/noi,,cdllobjs.lib doscalls.lib/nod/noe,cdllobjs.de

 3. Run IMPLIB on the definition file from step 1 to create a
    customized library file (CRTLIB.LIB) containing the exported
    functions. The command is shown below:

       implib crtlib.lib cdllobjs.def

 4. Use the Microsoft Library Manager (LIB) to append CDLLSUPP.LIB to
    the customized library created in step 3. The file CDLLSUP.LIB
    contains a few small routines that cannot be dynamically linked
    because they are called near. The LIB program automatically creates
    a back-up file (with a .BAK extension), which can be deleted. The
    command for this step is shown below:

       lib crtlib.lib+cdllsupp.lib;


 39. C 5.10 MTDYNA.DOC: Using an MTDYNA Library

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29844

 The following information is from "Section 5: Creating Dynamic-Link
 Libraries" of the Microsoft C version 5.10 MTDYNA.DOC file.

 5.2.3   Using a Multiple-Thread Dynamic-Link Library

 Once a C run-time multiple-thread dynamic-link library has been
 created (Section 5.2.2), it can be used by a program and associated
 dynamic-link libraries. The process of using this C run-time
 dynamic-link library is shown below:

 1. Compile the main program. When creating executable and dynamic-link
    library files that will use the dynamically linked C run-time
    library, the C compiler must be called with the multiple-thread
    versions of the include files. Additionally, stack checking must be
    turned off if your code is being compiled as small or compact
    models. Stack checking can only be supported in the dynamically
    linked C run-time library using far calls (medium/large memory
    models).  The C compiler is invoked with something like this:

             cl /I\include\mt /AS /Gs2 /DDLL /c mtmain.c

    The /Gs option specifies no stack checking. The /DDLL option
    defines the DLL symbol. The /AS option specifies small memory
    model. The /I\include\mt option specifies that the special
    multiple-thread include files are to be used.

 2. Link the main program to produce MTMAIN.EXE. The following files
    are linked together:

       mtmain.obj     Output from step 1
       crtexe.obj     Start-up code for executable files
       crtlib.lib     Customized C run-time library (Section 5.2.2)
       doscalls.lib   OS/2 support library
       mtmain.def     Definition file for mtmain.c
       mtmain.exe     Output from LINK

    The linker is invoked with something like this:

       link mtmain+crtexe,/noi,,crtlib.lib doscalls.lib/nod,mtmain.def;

 3. Compile the dynamic-link-library module. When creating executable
    and dynamic-link library files that will use the dynamically linked
    C run- time library, the C compiler must be called with the
    multiple-thread versions of the include files. Additionally, stack
    checking must be turned off if your code is being compiled as small
    or compact model. Stack checking can only be supported in the
    dynamically linked C run-time library using far calls
    (medium/large memory models.)  The C compiler is invoked with
    something like this:

       cl /I\include\mt /Alfw /G2 /DDLL /c mtdll.c

    The /Alfw option specifies large code-pointer size, far
    data-pointer size and a segment setup of SS not equal to DS; DS
    fixed. The /DDLL option defines the DLL symbol. The /I\include\mt
    option specifies that the special multiple-thread include files are
    to be used.

 4. Link the dynamic-link-library module to produce MTDLL.DLL. The
    following files are linked together:

       mtdll.obj      Output from step 3
       crtdll.obj     Start-up code for dynamic-link library files
       crtlib.lib     Customized C run-time library (Section 5.2.2)
       doscalls.lib   OS/2 support library
       mtdll.def      Dynamic-link library definition file
       mtdll.dll      Output from LINK

    The linker is invoked with something like this:

       link mtdll+crtdll,mtdll.dll/noi,,crtlib.lib doscalls.lib/nod,mtdll.def;

 5. Place the MTDLL.DLL file (from step 4) and the CRTLIB.DLL file
    (from Section 5.2.2) in a directory on your LIBPATH so OS/2 can
    find it. Then run the program MTMAIN.EXE. If either dynamic-link
    library file is not in your LIBPATH, OS/2 will not be able to run
    MTMAIN.EXE.

 Note: The LIBPATH is set in your CONFIG.SYS or CONFIG.OS2 file,
 depending on which version of OS/2 you are using. LIBPATH is not part
 of your environment strings like the LIB, INCLUDE and PATH variables.


 40. C 5.10 MTDYNA.DOC: Matrix of Components

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29845

 The following information is from "Section 6: Matrix of Components" of
 the Microsoft C version 5.10 MTDYNA.DOC file.

 Matrix of Components
 --------------------

 Table 1 lists the various components needed to create multiple-thread
 programs and the two types of dynamic-link libraries discussed above.
 For comparison, a single-thread executable file is also included in
 the table. (A single-thread executable file is simply a regular C
 program.)

 The components have the following meanings:

    .OBJ            Object files

    .LIB            Library files

    .h              Location (default) of include files

    DLL             Status of DLL symbol (either defined or not defined)

    xLIBCyP.LIB     Regular C run-time library for protected mode
                       x = memory model (S, C, M, L)
                       y = math package (A, E, 7)

 Table 1.  Output-File Type

                      Executable                    Dynamic-Link Library

 Component  Single Thread    Multiple Thread   Single Thread    Multiple Threa
 ---------  -------------    ---------------   -------------    --------------

 .OBJ       ...              ...               ...              CRTDLL.OBJ
                                                                CRTEXE.OBJ
                                                                CRTLIB.OBJ

 .LIB       xCLIBCyP.LIB     LLIBCMT.LIB       LLIBCDLL.LIB     CDLLOBJS.LIB
                             DOSCALLS.LIB      DOSCALLS.LIB     CDLLOBJS.DEF
                                                                CDLLSUPP.LIB
                                                                DOSCALLS.LIB

 .h         \INCLUDE         \INCLUDE\MT       \INCLUDE         \INCLUDE\MT

 DLL        Not defined      Not defined       Not defined      Defined


 41. Appending to CTRL+Z Terminated File with Fopen()

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-SEP-1988    ArticleIdent: Q29852

 When appending to a stream file that is terminated with the
 end-of-file marker CTRL+Z (CONTROL+Z or the ASCII code 1A
 hexadecimal), use the "a+" type with the fopen() function. The "+" in
 the type "a+" allows for both writing and reading.

 If you use the "a" type with fopen() for appending in write-only mode,
 the end-of-file marker will not be removed. Subsequently using the DOS
 type command on the file will only display data up to the original
 end-of-file marker, and will not display appended data.

 The fopen() type "a+" will allow the removal of the end-of-file marker
 from the file before appending, so that the appended data can then be
 displayed by the DOS type command.

 The "a+" is required because DOS must be permitted to read the file to
 locate the end-of-file marker and overwrite it with appended data.
 Using the "a" type prohibits DOS from reading the file, so DOS is
 unable to find the end-of-file marker for overwriting and instead the
 appended data is written after the end-of-file marker.


 42. C 5.10 UTILITY.DOC: Microsoft Pascal Programs

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr s_codeview
 Last Modified: 16-JAN-1991    ArticleIdent: Q29903

 The following information is from the section titled "Microsoft(R)
 CodeView(R) Debugger" of the Microsoft C Version 5.10 UTILITY.DOC
 file.

 Microsoft Pascal Programs

 In this release, Microsoft Pascal programs cannot be debugged with
 the CodeView debugger.

 The Pascal example on pg. 61 of the Microsoft CodeView and
 Utilities manual should read

 PAS1 /Zz TEST;

 rather than

 PAS1 /Zi TEST;


 43. Wild-Card Expansion

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q29925

 Problem:

 I am attempting to insert the _setargv module into my standard C
 library to expand wild-card command line arguments as documented on
 Page 130 of the "Microsoft C 5.10 Optimizing Compiler User's Guide."

 When I invoke the LIB utility to remove the old _setargv module
 from the C library, I get the warning message "setargv.obj: warning
 U4151: '__setargv': symbol defined in module stdargv, redefinition
 ignored."

 My program is supposed to expand *.dat and print the names of all .dat
 files in the current directory. When I link my compiled code to the
 modified C library, I do not receive any errors. However, when I run
 my program, it prints out *.dat instead of expanding the wild card.

 Response:

 This is an error in documentation. The name of the module that you
 should extract from the C run-time library is stdargv. To replace this
 module with the module for expanding wild cards, use the LIB utility
 and enter the following module names after the Operations: prompt:

 Operations: -stdargv+setargv

 After performing this operation with LIB, linking the modified C
 library to your code will now permit the expansion of wild-card
 arguments by means of the argv[] array that is one of the main()
 function arguments.

 Note that you may link the object file setargv.obj with your code and
 an unmodified C run-time library to allow the expansion of wild cards.
 The replacement of module stdargv with setargv.obj allows wild-card
 expansion without explicitly linking in "setargv.obj" each time.

 C Version 4.00 and its documentation about the wild-card expansion
 library module had a similar problem.

 If you are using C Version 4.00, search for wild card and setargv for
 more information.


 44. Reading F11 and F12 Keys on Extended Keyboard

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 11-AUG-1989    ArticleIdent: Q30370

    The following program will allow you to read the F11 and F12 keys
 on an extended keyboard. The key to this process is to call
 _bios_keybrd() with the service argument 0x10. This will allow an
 extended keyboard read. This program will sit in an infinite loop
 until F11 or F12 is pressed. Note that the C run-time library
 functions getch() or getche() will not be able to read in the extended
 function keys even after the change above has been made.

 #include <bios.h>
 #include <stdio.h>
 #define _EXTKEYREAD 0x10
 #define MASK 0xFF00
 #define ZMASK 0x00FF
 main()
 {
   unsigned value, nextval;
   while(1)
   {
   value = _bios_keybrd(_EXTKEYREAD);
   nextval = value;
   if ((value & ZMASK) == 0)         /* check low order byte for zero*/
                                     /* if zero, then we have extended key*/
     {

        if((nextval & MASK) == 0x8500)   /* buffer code = 8500h for F11 */
        printf("F11 key pushed\n");

        if((nextval & MASK) == 0x8600)   /* buffer code = 8600 for F12 */
        printf("F12 key pushed\n");
     }
   else
     printf("not an extended key\n");

   }
 }



 45. Trapping FP Execptions with In-Line 8087 Code

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 27-OCT-1988    ArticleIdent: Q30644

 Problem:

 I am following the instructions on Pages 167-68 of the "Microsoft C
 Optimizing Compiler User's Guide" to generate true in-line 8087 code.
 I can link a module to remove the fixups for the interrupts, but I can
 no longer handle floating-point exceptions using the signal function.

 Response:

 This is a documentation error. To trap floating-point exceptions with
 the signal function while having true in-line 8087 code, you need to
 add the following instructions to your FIXUP.ASM module:

            extrn __fpmath:far
            extrn __fptaskdata:far
            extrn __fpsignal:far

            CDATA   segment word common 'DATA'
                    dw      0
                    dd      __fpmath
                    dd      __fptaskdata
                    dd      __fpsignal
            CDATA   ends

 Without the previous code, the start-up code will not initialize
 the emulator and the signal function returns an error when you attempt
 to use signal to trap floating-point exceptions.


 46. Cannot Create .COM Files in C Compiler

 Product Version(s): 3.00 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JUN-1988    ArticleIdent: Q30646

    The Microsoft C Compiler Versions 3.00, 4.00, 5.00, and 5.10 do not
 support the creation of .COM programs. This is because the smallest
 memory model that can be created is Small Model, which has one Code
 segment and one Data segment, while .COM programs can only have one
 segment.

    .EXE files are converted to .COM files using the MS-DOS utility
 EXE2BIN (see your MS-DOS manual and/or Page 51 of Ray Duncan's
 "Advanced MS-DOS"). The .COM programs cannot contain more than one
 declared segment; however, the Microsoft C compiler creates segments
 named _DATA, _TEXT, CONST, _BSS, etc.
    There are no compiler options to create a "Tiny model" program.
 For this reason, most .COM programs are written in assembler.
    One way to use the C Compiler in creating .COM programs is to
 compile with the /Fa option to create an assembly listing. The .ASM
 file(s) can then be modified so it only uses one segment.



 47. Initialization of auto Arrays, Structs, Unions Not Allowed

 Product Version(s): 4.00 5.00 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-AUG-1989    ArticleIdent: Q34668

 Problem:

 Both the ANSI draft standard for C (May 1988) and "The C Programming
 Language," Second Edition (by Kernighan and Ritchie) show that
 initializing aggregate data items declared with auto storage class is
 allowed in Standard C; however, our compiler flags fatal errors when
 such attempts are made.

 The error message C2073 cannot initialize array if function is issued
 when attempting to compile an array initilization within a function
 such as the following:

 foo() {
     char array[]="intialized local array will cause an error";
 }

 Response:

 This restriction is stated in the "Microsoft C 5.1 Optimizing Compiler
 Language Reference" on Page 89.

 One possible workaround is to use the static storage class rather than
 auto (auto is the default for declarations inside a function). This
 process has the advantage of making only one copy of the array and
 initializing it only ONCE, conceptually at the start of program
 execution; however, this can be a problem for recursive functions that
 may need a separate copy of the array for each invocation of the
 function.

 Another workaround is to declare two arrays: one static and one auto.
 Initialize the static array and copy it into the auto array (e.g.
 using the fast memcpy function) at the beginning of the function. Note
 that there is no speed or space penalty for this process because the
 second workaround is basically what the compiler would have to do if
 it allowed initialization of auto arrays.

 The first workaround will give a savings of both time and space over
 both the second workaround and over initializing an auto aggregate.


 48. chdir() Example Is Incorrect

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q30959

 The example of the chdir() function on Page 156 of the "Microsoft C
 Run-Time Library Reference" manual is incorrect. This example is
 missing double quotation marks around the path. It should read as
 follows:

 chdir("c:\\temp") ;


 49. Array Index Multiplication with Integers Causes Link Error

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR77788
 Last Modified: 16-JUN-1988    ArticleIdent: Q31448

    When the following program is compiled and linked, the linker
 generates the error "L2029 -unresolved external for the variable
 _arr." However, the array appears to be declared legally. The
 following code generates the error:

    char huge arr[256*512];
    main(){}

   The problem occurs because the multiplication for the array index is
 done with integers and the result of the multiplication is too large
 to fit in an integer. This will result in the array index being 0
 (zero). Because of this array, the following declaration

    char huge arr[256*512];

 is equivalent to the following declaration:

    char huge arr[0];

    The second declaration in turn, is equivalent to the following
 declaration:

    char huge arr[];

    This type of declaration will cause the compiler to generate an
 explicit external reference for the array arr and force the linker to
 look for the variable arr.
    To solve this problem, do the multiplication for the array index
 with long integers by declaring one or both of the integer constants
 as long. The following is a code example:

    char huge arr[256L*512];



 50. README.DOC Refers to Undocumented "Link Options"

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 24-AUG-1988    ArticleIdent: Q31454

    The following statement appears in the note for Page 130 ("Part 2:
 Notes for the Microsoft C Optimizing Compiler User's Guide") of the
 README.DOC file on the C Version 5.10 Setup disk:

    See the description of the /NOE option under the heading "Linker
 Options" later in this document.

    However, there is no such heading, nor is there any linker option
 information in the UTILITY.DOC file.
    The CodeView and Utilities manual contains an inserted manual
 section labelled "Update (CV. and Util.)". In this document, the /NOE
 option and the /NON option are described in Section 4, "Using the OS/2
 Linker", subsection 4.3, "New Options for Both Modes", Page Update-28.


 51. PATCH87 Gives "Cannot Open IO.SYS" Message

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JUN-1988    ArticleIdent: Q31468

    If the instructions in the PATCH87.DOC file for using PATCH87.EXE
 are followed through Step 4 of the "Do I Need to Use This Program?"
 section, and the diagnostic test results in a "Cannot open IO.SYS"
 message, then you must contact the original equipment manufacturer
 (OEM) for more information. It is likely that the IO.SYS file has been
 renamed in the provided version of DOS.


 52. Bitwise Complement Operator Appears to Fail on Comparison

 Product Version(s): 4.00 5.10 5.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JUN-1988    ArticleIdent: Q31510

    The bitwise complement operator (~) may appear to work incorrectly
 when used to compare unsigned characters, as illustrated in the
 following example.
    However, when using the bitwise complement operator, it is
 important to note that it will perform the "usual arithmetic
 conversions" on operands. The usual arithmetic conversions are
 described in detail in Section 5.3.1 of "The Microsoft C Language
 Reference Guide."

    The following program prints out as "failed" even though it
 appears that the two items should compare as "equal":

 #include <stdio.h>
 main()
 {
  unsigned char i,j;
  unsigned char k = 4;
  i = k;
  j = ~i;

   if (j == ~i)
     printf("passed\n");
   else
     printf("failed\n");

 }

    The compiler takes the steps below to evaluate the following
 statement:

    if (j == ~i)

    1. The compiler converts the operand "i" to an unsigned integer (in
 the C manual, see step 5 of the usual arithmetic conversions).
    2. The compiler complements the bits of this unsigned integer (the
 high byte becomes 0xFF).
    3. The compiler converts the operand "j" to an unsigned integer
 (the high byte becomes 0x00).
    4. The compiler compares the two operands.

    Since the high bytes of the two operands differ, the comparison
 will fail.
    To ensure that the compiler will compare only the low bytes of the
 two operands, cast the operand that is being complemented. For
 example, you can change the comparison to the following:

  if (j == ~(unsigned char)i)


 53. Linking FORTRAN and C, "L2044 _FF_MsgBanner Multiply Defined"

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | h_fortran 4.00 4.01
 Last Modified: 16-JUN-1988    ArticleIdent: Q31563

 Problem:
    When linking FORTRAN and C modules, I receive the error "L2044
 _FF_MsgBanner Symbol Multiply Defined." I have set up FORTRAN for C
 compatibility, and I am linking with the /NOE switch.

 Response:
    When using FORTRAN Versions 4.00 or 4.01 with C, you need to run
 the F4COMPAT file to make your FORTRAN libraries C compatible because
 FORTRAN Versions 4.00 and 4.01 were written in C Version 4.00.
    If the /NOD switch is used, altering the order of the libraries may
 change the error message received. When the FORTRAN library is first,
 the error may be "Floating Point Not Loaded." When the C library is
 first, the error will be "Symbol Multiply Defined."


 54. RunTmLibRef ftime Returns millitm to 100ths

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q31611

    The ftime function is described in a misleading way in the
 "Microsoft C 5.1 Optimizing Compiler Run-Time Library Reference" ,
 Page 308 for C Version 5.x and Page 217 for C Version 4.00.
    The field millitm in the timeb structure that ftime returns is
 described to hold the value of the fraction of a second in
 milliseconds. The field contains three digits as described;
 however, the last digit always is zero. Thus, the function returns
 millitm incremented to the nearest one hundredth of a second.
    Note also that this function uses the system clock to determine
 the time. Since the resolution of the clock on PC's is about 1/18.2
 seconds, the time function can not be more accurate than that.


 55. _beginthread()/_endthread() Coding Multi-Threaded Applications

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  8-JUL-1988    ArticleIdent: Q32057

 Question:
    What do _beginthread() and _endthread() do? Do we need to use
 these routines rather than the OS/2 API calls DosCreateThread() and
 DosExit()? Does _beginthread() affect the stack it is passed?

 Response:
    _beginthread() and _endthread() are discussed in MTDYNA.DOC.
    _beginthread() should be used in place of DosCreateThread() when
 coding multi-threaded applications in C Version 5.10. _endthread()
 should be used rather than DosExit() to terminate a thread before it
 runs to completion.
    _beginthread() takes care of important thread-creation tasks,
 such as the following:

    1. Initializing the per-thread floating-point package
    2. Saving/restoring the DGROUP environment
    3. Ensuring that there are not too many threads being created
    4. Verifying the validity of the stack generated

    The stack you pass to _beginthread() must meet the following
 requirements:

    1. It must not have null segment.
    2. It must not start at an odd address.
    3. It must not have 0 length.
    4. It must not have an odd length.
    5. It must not extend past the end of the segment.

    Because of the importance of these tasks, it is important to use
 _beginthread()/_endthread() instead of DosCreateThread()/ DosExit()
 when coding multi-threaded applications in C Version 5.10. Although
 you may be able to use DosCreateThread(), consistent results are not
 guaranteed.


 56. Compiler C2061 Syntax Error: Identifier 'dev_t' in stat.h

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |  s_quickc
 Last Modified: 15-JAN-1990    ArticleIdent: Q32068

 When compiling a file that includes stat.h or stat.h followed by an
 include of types.h, the following error is generated:

    C2061 syntax error: identifier 'dev_t'

 The error occurs because dev_t is defined in types.h and is not
 defined in stat.h.

 When using the include file stat.h, you must also include the file
 types.h. Specifically, the file types.h must be included before the
 file stat.h. For example:

 #include <sys\types.h>
 #include <sys\stat.h>

 The order in which these files are included must occur as shown to
 eliminate the compiler error message.


 57. No Error Message Text

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-SEP-1988    ArticleIdent: Q32069

 You can receive compiler errors with numbers but without text when
 compiling if the error message's file is not present.

 To see the error-message text, the files C1.ERR and C23.ERR must be in
 your path. Generally, these two files are placed in the same directory
 as the compiler driver and compiler passes, CL.EXE, C1.EXE, C2.EXE, and
 C3.EXE.


 58. D1001 "Could Not Execute C2.EXE" with DOS Version 2.10

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-SEP-1988    ArticleIdent: Q32070

 The compiler can generate the error D1001, "could not execute C2.EXE,"
 under the following conditions:

 1. The .EXE file cannot be found. A terminate-and-stay-resident
    (TSR) program could alter the setting of the PATH environment
    variable, causing the .EXE to not be found.

 2. There is not enough memory.

 3. The .EXE file is corrupt, or has an illegal .EXE file format.

 4. DOS and COMMAND.COM are incompatible. If their version numbers
    are different, the compiler might not be able to open the
    intermediate file in the TMP directory.


 59. Two Syntaxes for Calling Functions with Pointers

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-SEP-1988    ArticleIdent: Q32109

 The source code below contains what appears to be an improper use of a
 pointer to a function. However, the compiler fails to flag this either
 as a warning or as an error, and the code seems to work as expected.

 The behavior exhibited in the sample code is expected. The proposed
 ANSI Standard (Document Number X3J11/88-002, January 11, 1988) allows
 a function to be called through a pointer with the following syntax

 pointer_to_function();

 in addition to the following traditional syntax:

 (*pointer_to_function)();

 The following is a quotation from Page 40 of "Rationale for Draft
 Proposed American National Standard for Information Systems
 Programming Language C":

 "The...construct, not sanctioned in the Base Document, appears in some
 present versions of C, is unambiguous, invalidates no old code, and
 can be an important shorthand."

 The following sample code demonstrates this problem:

 #include <stdio.h>
 void main()
 {
    void ftn();
    void (*ptr_to_ftn)();
    ptr_to_ftn = ftn; /* the pointer is correctly assigned to
                         an address */
    printf("\nCalling all ftns\n\n");
    (ptr_to_ftn)();  /* note that the function is improperly called.
                        the correct syntax is (*ptr_to_ftn)() */
    printf("back to main\n");
 }
 void ftn()
 {
    printf("inside ftnland\n\n");
 }


 60. EXEC Problem with the Novell Network

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q32285

 When compiling a program under a Novell network, the following
 problems can occur:

 1. A command-line error message.
 2. A stack overflow.
 3. The compiler hangs.
 4. Programs created with C Version 4.00 and Link Version 3.51
    could generate Error 2003 : integer divide by zero.

 This is not a problem with the Microsoft C Compiler, nor is it an
 error on your part. A problem exists in the way Novell networking
 software handles the EXEC function, one of the DOS interrupt 21h
 functions used by the CL and MSC programs to start each of the
 compiler passes.

 Contact your Novell dealer about this problem; there should be a patch
 available. Novell has stated this problem has been corrected in
 Version 2.10 and later.

 Novell's network emulates DOS; the problem arises from incorrect
 emulation of the DOS int 21H function 4BH (EXEC program) call. The
 Novell network assumes the calling program will save SS:SP before the
 call. This was necessary on DOS Versions 2.x, but it is not necessary
 to save the registers on DOS Versions 3.x.

 The C compiler checks to see what version of DOS it is running on; if
 you are running DOS Versions 2.x, save SS:SP; if you are running DOS
 Versions 3.x (which is what Novell presents itself as) do not save
 SS:SP. The network destroys those registers on the call even though
 this behavior is unlike DOS Versions 3.x.


 61. Assert Macro Anomaly; Generating Syntax Errors

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  5-JUL-1988    ArticleIdent: Q32303

    The following code demonstrates an anomaly with the C Version 5.10
 compiler when compiled with the default options. Compile-time syntax
 warnings are generated when there are no apparent syntax errors.

 #include <stdio.h>
 #include <assert.h>
 main()
 {
   if(1)
   assert(1+1);
   else
   assert(1+2);
 }

 Response:
    The syntax errors are generated because assert() is implemented as
 a macro and is expanded to the following form:

     if (!(1+1)) { \
         fprintf(stderr, _assertstring, #1+1, __FILE__, __LINE__); \
         fflush(stderr); \
         abort(); \
         } \
     }

    When this macro is placed inside an if else conditional, the
 closing brace of the macro is seen as a syntax error.
    Although the syntax for the if else conditional in the above
 example is legal, it does not make much sense for use with assert
 because assert will call the abort function if it is true. Therefore,
 you can accomplish the same results with the following program:

 #include <stdio.h>
 #include <assert.h>
 main()
 {
   if(1)
   assert(1+1);
   assert(1+2);
 }

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


 62. L1063 Error Not Documented in C Versions 5.00 or 5.10

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 18-AUG-1988    ArticleIdent: Q32311

    The link error message, "L1063 out of memory for CodeView
 information," is not documented in the manuals or in the README.DOCs
 for C Versions 5.00 and 5.10. However, it is documented in the FORTRAN
 Version 4.10 package in the CVREADME.DOC on the disk labeled
 "Microsoft CodeView for MS-DOS".
    The following information was taken from the FORTRAN Version 4.10
 CVREADME.DOC, "NOTES ON CODEVIEW AND UTILITIES," the section titled
 "Microsoft Segmented-Executable Linker (LINK)," the subsection "New
 LINK Error Messages":

    L1063 out of memory for CodeView information

    The linker was given too many object files with debug information,
 and the linker ran out of space to store it. Reduce the number of
 object files that have debug information.


 63. C 5.00 and 5.10 putenv() Example Program Missing Backslashes

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-JAN-1991    ArticleIdent: Q32324

 The example program for the putenv() function on page 468 of the
 "Microsoft C 5.10 Optimizing Compiler Run-Time Library Reference" is
 incorrect. The C code requires double backslashes in order to work
 correctly.

 This is the incorrect line:

    if (putenv("PATH=a\bin;b:\tmp") == 1)

 The corrected line (with escaped backslashes) should read as follows:

    if (putenv("PATH=a:\\bin;b:\\tmp") == 1)


 64. Incorrect Comment Pragma Example

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-JAN-1990    ArticleIdent: Q32348

 Page 12 (Update-12) of the Update section for the "Microsoft C
 Optimizing Compiler User's Guide and Language Reference" manual shows
 an incorrect example of the comment pragma.

 The second parameter of the pragma is a string literal and should be
 enclosed in double quotation marks. The example should look like the
 following:

    #pragma comment(lib, "mylibry")

 Note: If the quotation marks are missing, the compiler will issue
 error C4079.


 65. _Heapchk() Performs Consistency Check on Heap

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-JUL-1988    ArticleIdent: Q32442

    The _heapchk() routine performs a consistency check on the heap by
 examining the header information of the memory blocks in the heap.
 However, it cannot detect corruption of data within the heap's nodes;
 it only can detect corruption of the heap's header information.
    The _heapchk() routine checks for the following:

    1. It checks to see if any heap has been allocated at all. If not,
       _heapchk() returns _HEAPEMPTY.
    2. It checks the beginning of the heap block to see if the first
       allocation block has been corrupted; if so, it returns _HEAPBADBEGIN.
       (Note that only the header information is checked.)
    3. It scans through the far heap block, moving from node to node.
       For each node, it checks the header information to make sure it has
       not been corrupted; if so, _heapchk() returns _HEAPBADNODE.
       Note that the only kind of corruption _heapchk() can detect is an
       out-of-bounds value in the header; it cannot detect corrupted data
       within the heap block itself. If the fill value passed is not
       _HEAPSET_NOFILL, and the block is unallocated, _heapchk() fills
       memory with the fill value.
    4. If _heapchk() made it all the way through the heap (i.e., it checked
       the headers for all nodes), it returns _HEAPOK.



 66. How Bitfields Are Stored in Memory

 Product Version(s): 1.04 2.03 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32841

    The Microsoft C compiler stores bitfields from low memory to high
 memory. For example, if you have the following declaration:

            struct   {
                    unsigned field_one:3;
                    unsigned field_two:9;
                    unsigned field_three:5;
            };

 then "field_one" will be stored in bits 0-2 in the first word,
 "field_two" will be stored in bits 3-11 in the same word, and
 "field_three" will be stored in bits 0-4 of the second word (because
 it cannot fit in the 4 bits remaining in the current word).



 67. Specifying .DEF Files on the CL Command Line

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  8-JUL-1988    ArticleIdent: Q32448

    You can use .DEF files when compiling and linking, using CL
 command-lines.
    List the .DEF files with the other files (.C, .OBJ, and .LIB). CL
 will compile and link them appropriately. Note that if you do not
 specify an extension, CL assumes the file is an .OBJ file and it will
 try to link it.
    The following command will build a protected-mode program called
 MYAPP.EXE by compiling myapp.c, then linking MYAPP.OBJ and MYSUB.OBJ
 with the library MYLIB.LIB, and use the MYDEF.DEF.definitions file:

     cl /Lp myapp.c mysub mylib.lib mydef.def



 68. ANSI Constants Not in Stdio.h

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  8-JUL-1988    ArticleIdent: Q32513

    The ANSI C standard requires the constants FILENAME_MAX and
 FOPEN_MAX in STDIO.H and the constants EXIT_SUCCESS and EXIT_FAILURE
 in STDLIB.H.
    The include files provided with Version 5.10 of the C compiler do not
 have these constants. These constants should be defined as follows:

 /* in stdio.h */

 #define FILENAME_MAX 63
 #define FOPEN_MAX    20

 /* in stdlib.h */

 #define EXIT_SUCCESS  0
 #define EXIT_FAILURE  1



 69. fclose() on Unopened Files Causes Protection Violation

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-AUG-1988    ArticleIdent: Q32539

    If you close an unopened file with the fclose() function, a
 protection violation occurs if the source is compiled in the large- or
 compact-memory model. In the small-memory model, fclose() returns an
 error as expected.
    Closing an unopened file is a user error and it is outside the
 functional realm of the C run time to check the validity of file
 handles passed to the fclose function. It is the responsibility of the
 user to ensure that only valid file handles are passed to the fclose
 function.

    The sample code below demonstrates this behavior. Compile this code
 with the CL /AL file.c. command line:

 #define INCL_BASE
 #include <os2.h>
 #include <stdio.h>
 FILE *myfile;
 int status;

 main()
 {
  myfile = fopen("myfile.dat","r");
  if (myfile == NULL) printf("file open error\n");
  status = fclose(myfile);
  printf("file close status = %d\n",status);
 }


 70. Reference to Section 2.11 Should Be 2.12 in User's Guide

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 18-AUG-1988    ArticleIdent: Q32805

    Page 145 of the "Microsoft C 5.0 (and 5.1) Optimizing Compiler User's
 Guide" has an error in the last sentence. The reference to Section
 2.11 is incorrect; it should read as follows:

    "For more information on library routines and memory models, see
 Section 2.12, `Using Huge Arrays with Library Functions,' in the
 Microsoft C Run-Time Library Reference."



 71. The fopen Function Fails to Open Printer in Bound Application

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-JAN-1990    ArticleIdent: Q32813

 Attempting to use the C run-time function fopen() to open the printer
 will fail in real mode if the application calling the function is
 bound. The "invalid argument" error is returned.

 This problem is caused by the Family API DosOpen function. It will
 fail to open the printer when called with a flag that specifies
 "truncate if the file exists," which is the flag used by fopen().

 The following program demonstrates a work around for this problem
 using the C run-time library functions open() and fdopen():
 The program below uses open() to get a file handle for the printer.
 Note that the oflag used is O_WRONLY. ORing in O_TRUNC would fail in
 real mode. The device name "lpt1" or "lpt2" could be used instead of
 "prn", depending on how the computer is set up. The generic name for
 the printer is "prn".

 Then the fdopen() function is used to create a stream for the printer,
 and the printer is written to by the fprintf() function.

 The following is the sample program:

 #include <fcntl.h>      /* include files for open() */
 #include <sys\types.h>
 #include <sys\stat.h>
 #include <io.h>
 #include <stdio.h>      /* include file for printf() and
 fdopen() */

 int   fh;     /* file handle for printer */
 FILE *stream; /* stream for printer     */

 main() {
 /* open file handle for printer, check for open failure */
     if ((fh = open("prn",O_WRONLY)) == -1 )
         printf("Opening file handle failed.\n");

 /* associate stream for fh above, check for failure */
     else {
         if((stream = fdopen(fh,"w")) == NULL)
             printf("Creation of stream from file handle
 failed.\n");

 /* if previous function calls succeeded, print "Hello" */
         else
             fprintf(stream,"Hello\n");
         }
     }


 72. The Cause of Run-Time Error R6000 Stack Overflow

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q32816

 The run-time error R6000 Stack Overflow can be caused by two
 different problems, as follows:

 1. Your program's stack is not large enough to hold all the data
    being pushed on it during execution of your program, so it
    overflowed. This problem can be caused by heavily recursive
    programs and programs that declare large amounts of data on
    the stack ("local" or "automatic" data in C jargon).

    In this case, you need a larger stack or less recursion and/or less
    local data.

 2. The second cause for the R6000 error is somewhat counter
    intuitive; it can be caused by the C startup (initialization)
    code when it tries to allocate space for the stack and is unable
    to do so.

    In this case, you need to reduce the size of your stack or reduce
    the amount of data in DGROUP.

 The following is a description of both problems, ways to solve the
 problem, and a method for determining which problem you are
 encountering:

 Case 1: R6000 Occurs at Run Time

 The stack overflowed because too much information was pushed on it.
 This information could be either function-return addresses or local
 data. Each time a function is called, the return address in the
 calling function is pushed on the stack along with any parameters;
 then, when the called function executes, it may allocate local
 ("automatic") data for its own use. This process requires stack space.

 To correct this problem, do one of the following:

 1. Decrease the number of local variables, perhaps by declaring
    those variables as static so they will not be pushed on the
    stack.

 2. Increase the stack size by compiling with the /F x option, where
    x is a hexadecimal number representing the number of bytes
    desired in the stack size (see Page 102 of the "Microsoft C 5.1
    Optimizing Compiler User's Guide").

 3. Change the stack size by linking with the /STACK switch, or using
    the EXEMOD utility. Note that increasing the stack size too much
    can cause an R6000 as described in case 2.

 Case 2: R6000 Occurs at Startup

 The startup code allocates space for the stack in the segment DGROUP.
 If DGROUP does not contain room for the specified stack size (default
 = 2K), the startup code issues the R6000 error.

 To correct this problem, either reduce the size of the stack or reduce
 the amount of data in DGROUP. To reduce the stack size, compile with
 the /F option, or link with the /STACK option, or use the EXEMOD
 utility. To reduce the amount of data in DGROUP, try switching from a
 small-data model (Small- or Medium-memory model) to a large-data model
 (Compact-, Large-, or Huge-memory model). If you already are in a
 large-data model, compile with the /Gt switch to move data from DGROUP
 to far data segments.

 To use the /Gt switch, specify /Gtx, where x is some decimal value
 representing a number of bytes. Data items larger than x bytes are
 allocated a new segment, thereby freeing up more space in DGROUP for
 the stack. For more information, see Page 156 of the "Microsoft C 5.1
 Optimizing Compiler User's Guide."

 How to Determine What is Causing the R6000 Error

 An excellent way to determine the cause of the problem is to use the
 CodeView debugger. After invoking CodeView on your program, execute to
 the beginning of function main() by doing one of the following:

 1. Single-Step with F8 or T.
 2. Enter "g main" at the CodeView prompt.

 When you've executed past the open curly-brace of main(), the C
 startup code has done its job by allocating space for stack and data.
 If the R6000 error does not occur at this time, you are experiencing
 Case 1, a run-time stack overflow (as opposed to Case 2, a
 startup-time stack overflow); you now can take appropriate action as
 described above.


 73. Command Line Error D2018

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32843

    If you receive the D2018: "cannot open linker cmd file" error,
 check to see that the TMP environment variable is set correctly. If
 the TMP variable is not set properly, temporary files cannot be
 created and this error may occur.



 74. Write Function Will Not Work Correctly with SS!=DS

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32871

 Problem:
    I have a program that needs to be run in an SS!=DS environment and
 I am trying to use the write function; however, it does not seem to be
 working.

 Response:
    The write function will not work correctly in SS!= DS in text
 mode. It should work properly in binary mode. In text mode, write()
 builds a buffer on the stack to do LF to CR/LF translation. It makes a
 call to stackavail() to make sure it does not overflow the stack; this
 call is what prevents it from working with SS!=DS.
    This is program design for this product.


 75. Toggling the Sign Bit on a Float or Double

 Product Version(s): 3.00 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JUL-1988    ArticleIdent: Q32889

 Problem:
    I want to toggle the sign bit on a float or double by either
 and'ing it with 0x7fff (make it positive) or or'ing it with 0x8000
 (make it negative). However, the compiler will not accept the
 following syntax:

    fl &= 0x7fff;
    fl |= 0x8000;

 Response:
    The bitwise operators only works correctly with integral types; you
 need to cast the float to be an integral type.
    The following are two macros that will allow you to toggle the sign
 bit on a float or a double (note that the same thing can be
 accomplished by multiplying the value by -1, but the macros are much
 faster because they do not make any calls to the floating-point
 library):

 /* Macro to make either a float or a double Negative by setting sign bit */
 #define NEG(arg) ((unsigned char *)&arg)[sizeof(arg)-1] |= \
                    (unsigned char)0x8000

 /* Macro to make either a float or a double Positive by clearing sign bit */
 #define POS(arg) ((unsigned char *)&arg)[sizeof(arg)-1] &= \
                    (unsigned char)0x7fff



 76. extern int i = 10; Compiles without Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 19-JUL-1988    ArticleIdent: Q32890

    Page 89 of "Microsoft C Optimizing Compiler Language Reference"
 states the following:

   "Declarations that use the extern storage-class specifier cannot
 include initializers."

   However, the following example compiles without error:

   extern int i = 10;

   The documentation is incorrect. The ANSI standard makes no
 distinction between the following declarations when they have file
 scope (i.e., they are declared globally):

   int i = 10;
   extern int i = 10;

   Therefore, the compiler does not generate a warning or error for
 either of these cases.



 77. __fac Unresolved at Link Time

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32891

 Problem:
    I am attempting to write a function to be used in a dynamic link
 library. The function returns a double. Whenever I compile and link
 with either of the multithread C run-time libraries (LLIBCMT.LIB
 or CRTLIB.LIB), I get the variable __fac unresolved.

 Response:
    In a single thread environment, the C run-time uses a global variable
 __fac to store the return value of a function that returns double. In
 a multithread reentrant environment, it is not possible to have a global
 variable that will potentially be modified by several threads.
    If you are writing functions that return doubles and you are using
 the multithread libraries, you need to declare the functions with the
 Pascal calling convention. Functions returning double with the Pascal
 calling convention pass the return value on the stack and allow you to
 work in a reentrant environment.



 78. Compiling with /Zi Causes Code Motion Optimization Suppression

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32892

    Compiling with /Zi and no other switches causes certain code motion
 optimizations to be suppressed, i.e, the code generated for a program
 with the defaults and with /Zi may differ.
    You can override this default behavior by explicitly specifying the
 default optimizations on the command line. For example, you can
 compile with the following command line to get the same code with or
 without /Zi:

    cl /Zi /Ot file.c



 79. Difference between Huge Pointers

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32893

 Problem:
    I have two huge pointers that are more than 32K apart. However,
 whenever I take the difference between them, I get an incorrect
 answer. I am using the following code:

 char huge *ptr1 = (char huge *)0xa0000000;
 char huge *ptr2 = (char huge *)0xb0000000;
 main()
 {
   long k;
   k = ptr2-ptr1;
   printf("difference is %ld\n",k);
 }

 Response:
    This problem occurs because the difference between two pointers is
 considered to be an integer quantity. The arithmetic that is done on
 the huge pointers is 32-bit arithmetic, but the result is truncated to
 an integer, then promoted back to a long value with a sign extension.
    To retain the original long value returned by the huge-pointer
 arithmetic, cast the result of the subtraction to a long value. For
 example, you will get the expected results with the following code:

 char huge *ptr1 = (char huge *)0xa0000000;
 char huge *ptr2 = (char huge *)0xb0000000;
 main()
 {
   long k;
   k = (long)(ptr2-ptr1); /* cast the integer to a long */
   printf("difference is %lp\n",k);
 }



 80. malloc May Truncate Request More Than 64K

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32998

    When trying to allocate memory with malloc() and calloc(), the
 request for memory will be truncated if it exceeds 64K.
    The maximum number of bytes that can be allocated by malloc is less
 than 64K because the allocation routines will consume a certain number
 of bytes to track memory allocation within the segment. The maximum
 number of bytes you can allocate using malloc or calloc is
 approximately 65516.
    Requests for more than 65516 bytes and less than 64K will result in
 malloc returning NULL. Requests for more than 64K will potentially
 return a pointer but it will be a pointer to a block of a size other than
 that requested because the parameter passed to malloc is an unsigned
 integer. This integer has a maximum value of 64K; passing a number greater
 than this value will result in undefined behavior. If malloc is passed a
 parameter greater than 64K, the compiler will issue a data-conversion
 warning, which should be heeded.
    If you require more than about 65516 bytes for a single allocation,
 you should use halloc().

    The following program demonstrates the behavior described above:

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

 int *intarray;

 main()
 {
     intarray= (int *)malloc(32768*sizeof(int));
     if (intarray == NULL)
         printf("not enough memory, no allocation");
     else
         printf("memory allocated");

     intarray= (int *)malloc(32767*sizeof(int));
     if (intarray == NULL)
         printf("not enough memory, no allocation");
     else
         printf("memory allocated");

 }



 81. DOS Append Interacts with /Fo /Fe

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-JUL-1988    ArticleIdent: Q33085

    When the DOS Append path is set, if an .OBJ or .EXE file of the same
 name as the file being compiled does not exist in the current
 directory or in the directory specified with the /Fo or /Fe but does
 exist in a directory in the Append path, the new .OBJ and .EXE file
 will be placed in the directory in the Append path instead of in the
 current directory or the directories specified by the /Fo and /Fe
 switches.
    Append searches the data path for all files regardless of
 extension; placing .OBJ or .EXE in the directory specified in the
 append directory is expected behavior.
    If you need to locate files in a specific directory and you are
 using Append, you should put a copy of the .OBJ and .EXE in the
 directory you wish to use as your destination.

    The following is a sample code:

    append c:\test1,c:\test2

    If program.obj resides in directory test1 and program.exe
 resides in test2, the following command line switches will
 not work correctly:

 cl /Foc:\test3\program.obj /Fec:\test3\program.exe program.c

    Although the .OBJ and .EXE files should be placed in the test3
 directory, they will be placed into the test1 and test2 directories,
 respectively.



 82. SH_COMPAT Share Flag for SOPEN()

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  2-AUG-1988    ArticleIdent: Q33104

    SH_COMPAT is not a valid share flag for SOPEN() under OS/2.
 SH_COMPAT is only valid in the DOS environment. The documentation in
 the "Microsoft C 5.1 Opitimizing Compiler Run-time Library Reference,"
 Page 548, does not document this restriction on the use of SH_COMPAT.



 83. Small-Memory Model and Far Routines

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | 5.10
 Flags: ENDUSER |
 Last Modified: 27-JUL-1988    ArticleIdent: Q33364

 Question:
    Is it incorrect to call a routine with a far call in the small
 memory model?
    When I try to call a C routine with a far call (from assembler),
 the CS register never changes and items start to be executed from the
 current CS instead of the one my routine is at. Are there any rules
 that must be followed to make a far call in the small-memory model?

 Response:
    In order for this to work correctly you need to be sure that the
 function is declared and defined as a far function (e.g. int far foo()).



 84. How _fheapwalk() Checks the Heap

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 27-JUL-1988    ArticleIdent: Q33366

    The following information describes how _fheapwalk() checks the
 heap.

    The _fheapwalk() function traverses those parts of the far heap
 that have been allocated either by fmalloc() or by a system call. This
 process is done by covering one such allocation per call of
 _fheapwalk(), independent of the size of the block allocated.
    On each call of _fheapwalk(), a manifest-constant int is returned
 as documented on Page 357 of the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Reference Library" manual.
    Also, a pointer to a structure is returned that contains
 information about the block allocated, which also is documented on
 Page 356 of the C manual.
    One undocumented feature of the function is that it does not return
 the actual memory address of an _fmalloc()ed block, only the block's
 size.
    As a result, it is incorrect to assume that the memory location of
 the beginning of a block can be determined by adding up the values of
 the blocks already allocated. The header information in each such
 block is omitted from the structure whose pointer is returned by
 _fmalloc(). In particular, the size of the header is omitted from the
 structure.



 85. Description of the /Or Switch

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 16-JAN-1990    ArticleIdent: Q48089

 Question:

 When I run CL with the /HELP option to get command-line help, there is
 listed an optimization flag, /Or, that is supposed to disable in-line
 returns. I can't find information about this switch documented
 anywhere else. What does this switch really do?

 Response:

 The term "in-line return" is misleading; there is not a call to the
 return function that is eliminated. The /Or switch affects the code
 that is produced for functions lacking local variables and/or formal
 parameters.

 If a function takes no formal parameters and has no local variables, a
 stack frame is not necessary. /Or prevents stack frame creation and
 clean-up code from being produced when possible. The code for
 preservation and restoration of the SI and DI registers is also
 eliminated.

 The typical instructions that are eliminated are as follows:

    push bp     ; This code is used on entry
    mov  bp, sp ; to establish a stack frame.
    ...
    push di     ; This code is used on entry
    push si     ; to preserve SI and DI.
    ...
    ...         ; The code to perform the function
    ...         ; would be here.
    ...
    pop  si     ; This code is used on exit to
    pop  di     ; restore SI and DI, and to
    mov  sp, bp ; clean up the established
    pop  bp     ; stack frame.


 86. Using 43-Line Mode with Hercules Card

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G880721-1772
 Last Modified: 27-JUL-1988    ArticleIdent: Q33403

    Currently, only 82x55 mode is supported for the Hercules card. It
 is possible to switch to 43-line mode if you first do a
 _setvideomode(_DEFAULTMODE), then immediately do a
 _setvideomode(_ERESCOLOR).



 87. Deeply Nested Blocks Cause C4073 Warning

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  2-AUG-1988    ArticleIdent: Q33526

    The following program produces a C4073 warning when compiled with
 the CL /Zi filename.c command line:

 #include <assert.h>
 #include <process.h>
 #include <stdio.h>

 void main(ac,av)
 int ac;
 char **av;
 { assert(av[ac] == NULL);}

    The warning C4073 is generated when the compiler cannot generate
 symbolic information for separate lines of code that recognize the
 distinction between different blocks. For example, you may encounter
 this error if you have many deeply nested blocks, each of which declares
 automatic variables.
    The warning means that when in CodeView, the symbolic information
 at the deeper levels will be merged and you will be able to see the
 value of variables at lower levels when normally you would not.
    In this example, the warning is encountered because you are nesting
 three levels on the same line of code. The assert function actually
 is a macro that is expanded to two nested levels.
    You can work around the warning by moving the closing brace of the
 function to the next line.



 88. Glockenspiel Turbo Pascal to C Translator Source Code

 Product Version(s): 3.00 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q33561

    The Irish company Glockenspiel writes the Turbo Pascal to C
 Translator. If you are interested in obtaining the source code, please
 contact Glockenspiel. The following is the company's address and phone
 number:

    19 Belvedere Place
    Dublin 1

    011-353-1-364515


 89. Multiple Calls to ctime before Printing Results

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  8-AUG-1988    ArticleIdent: Q33795

    The sample code below will print out the same time for the start and
 finish in the second printf statement; however, the statements should
 be printed two seconds apart. If ctime(&start) is taken out of the
 second printf statement, the finish time is later than the start time,
 as expected.
    As noted in the C Version 5.10 README.DOC, the ctime function uses
 a single static buffer to store the results of the call; i.e., when
 the second call to the function is made, the results of the first
 call are destroyed.  Therefore the behavior of the example is expected.

    The following sample code illustrates this behavior:

 time_t start, finish ;
 main() {
  time(&start) ;
  printf("the time is %s\n", ctime(&start) ) ;
  for ( i =0; i<1000; i++ )
     time(&finish) ;   /* start and finish should be about 2 sec apart */
  printf("ending time is %s and %s\n", ctime(&start), ctime(&finish) ) ;
 }


 90. C Version 5.10 LINK and Windows LINK4

 Product Version(s): 5.10    | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G880603-1453
 Last Modified:  8-AUG-1988    ArticleIdent: Q34029

    If you are developing Windows applications, you can use the
 Segemented Executable Linker provided with C Version 5.10.
    If you choose to use this linker for developing Windows
 applications, you must put the EXETYPE WINDOWS statement in your .DEF
 file. If you use LINK4, you do not have to put the EXETYPE WINDOWS
 statement in your .DEF file because the use of LINK4 causes the .EXE
 file to be identified as a Windows application.


 91. setvbuf with Buffer Greater than 32K Causes fwrite Failure

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 11-AUG-1988    ArticleIdent: Q34065

    The sample program below works correctly if the buffer size of the
 file is under 32K.  When the buffer size of the file is set higher
 than 32K (using setvbuf), the fwrite statement will fail and write
 "fwrite failed" to the screen. This problem occurs in Microsoft C
 Versions 5.00 and 5.10.
    Page 538 of the "Microsoft C 5.1 Optimizing Compiler Run Time
 Library Reference" manual indicates that the legal values for the size
 parameter are greater than zero and less than the maximum integer
 value (which is 32K). Therefore, even though the type for the
 size parameter is of type size_t (unsigned integer) only values
 less than 32K are correct for the size parameter to setvbuf().
    However, setvbuf should return an error for invalid size values.
 Microsoft is researching this problem and will post new information
 as it becomes available.

    The following sample code demonstrates this behavior:

 #include <stdio.h>

 char buf[35000] ;   /* size of file buffer */
 FILE *stream ;
 long result ;
 int err ;
 char i[10] = "abcdefghij" ;

 main() {
     stream = fopen("data1", "w+b") ;
     if ( err = setvbuf( stream, buf, _IOFBF, sizeof(buf) ) != 0)
         printf("failed to set buffer\n") ;
     else
         for ( result = 0; result < 5000; result++ )
             if (err = fwrite( i, sizeof(i), 1, stream )  != 1 ) {
                 printf("fwrite failed\n" ) ;
                 exit(-1) ;
                 }
 }


 92. Setting Size and Number of Internal Stacks

 Product Version(s): 3.x 4.x 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm s_quickpas s_pascal
 Last Modified:  9-FEB-1990    ArticleIdent: Q58436

 If an INTERNAL STACK OVERFLOW system error occurs, the number and/or
 size of internal stacks in DOS should be increased in the CONFIG.SYS
 file. The syntax for this is as follows

    STACKS=number,size

 where number = number of stacks (8-64, default 9) and size = size of
 the stacks (32-512,default 128).

 The following information was taken from the MS-DOS Encyclopedia, Page
 805:

    Each time certain hardware interrupts occur, ... , MS-DOS Version
    3.2 switches to an internal stack before transferring control to
    the handler that will service the interrupt. In the case of
    nested interrupts, MS-DOS checks to ensure that both interrupts
    do not get the same stack. After the interrupt has been processed,
    the stack is released. This protects the stacks owned by
    application programs or system device drivers from overflowing when
    several interrupts occur in rapid succession.
    .
    .
    .
    If too many interrupts occur too quickly and the pool of internal
    stack frames is exhausted, the system halts with the message
    INTERNAL STACK OVERFLOW. Increasing the number parameter in the
    stacks command usually corrects the problem.


 93. Graphic Adapters Supported by the Graphics Routines

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-AUG-1988    ArticleIdent: Q34068

    The following graphics adapters are supported by Microsoft C
 Version 5.10 and QuickC Version 1.01:

    Hercules card

    IBM adapters
    1. MDPA (Monochrome Display and Printer Adapter)
    2. CGA  (Color Graphics Adapter)
    3. EGA  (Enhanced Graphics Adapter)
    4. MCGA (Multi-Color Graphics Array)
    5. VGA (PS/2)  (Video Graphics Array)
       a. Analog monitors
    6. VGA (non-PS/2)
       a. Must be only adapter in system
       b. Use only monochrome modes with monochrome monitor
       c. Use only color modes with color monitor

    The Hercules card was not supported in previous versions of
 Microsoft C or QuickC.


 94. Putting Global Variables in the Default Data Segment

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 18-AUG-1988    ArticleIdent: Q34069

 Question:
    How can I tell the compiler to put my global variables in the
 default data segment when I am using the large- or huge-memory models?

 Response:
    In any memory model, if the near keyword is applied to global
 variables, they will be put in the default data segment. This action
 ensures that the variable is referenced with a 16-bit address, as
 opposed to the far 32-bit addresses, which will make variables defined
 with the near keyword faster to access.


 95. Converting from IEEE to MS binary format

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34070

 Question:

 How can I convert an IEEE number into Microsoft binary format?

 Response:

 The "Microsoft Run-Time Library Reference" manual contains
 documentation of four functions that are used to convert IEEE format
 to MS binary format and MS binary format to IEEE format.

 The four functions are as follows:

 fieeetomsbin: Converts a single precision floating-point
               number in IEEE format to MS binary format
 fmsbintoieee: Converts a single precision floating-point
               number in MS binary format to IEEE format
 dieeetomsbin: Converts a double precision number in IEEE
               format to MS binary format
 dmsbintoieee: Converts a double precision number in MS binary
               format to IEEE format


 96. Accessing Child Process Exit Code from Parent Process

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified:  9-FEB-1990    ArticleIdent: Q58437

 Question:

 I am using the spawn() function and I want to be able to find out
 whether or not the child program terminated normally or by entry of
 CTRL+C. Is there anyway I can get the system exit code from the child
 process?

 Response:

 There is no C run-time function that will return the system exit code
 from a child process. However, Interrupt 21h SubFunction 4Dh can be
 used to return it.

 Immediately after a child process terminates, the child exit code and
 the system exit code are in the AL and AH registers respectively.

 Example:

                     _________________________
                     |           |           |
       AX Register   |     |     |     |     |
                     |           |           |
                     -------------------------
                          AH     |    AL
                          /            \
                         /              \
          System Exit Code               Child Exit Code

 When the spawn() family of functions is called with a mode flag of
 P_WAIT, only the child exit code is returned. To read the system exit
 code, a call to Interrupt 21h SubFunction 4Dh is needed.

 It is important to get and store the return codes immediately upon
 returning from the child process, since another function may modify
 them.

 The following code samples demonstrate how to get the exit code from
 the child process within the parent process with C Version 5.10 and
 QuickC Versions 2.00 and 2.01.

 Code Example 1
 --------------

 /* Call this prog1.c  */
 #include <dos.h>
 #include <stdio.h>
 #include <process.h>

 union REGS inregs, outregs, tempreg;
 int retcode;
 unsigned char syscode;

 void main (void)
 {
    printf ("In program I\n");
    retcode = spawnl (P_WAIT, "sp2.exe", "sp2", NULL);

    /* Call int 21h function 4Dh to obtain exit codes */

    inregs.h.ah = 0x4d;
    intdos (&inregs, &outregs);

    /* System Exit Code will be in AH. */

    syscode = outregs.h.ah;

    printf ("Child exit code: %d\n", retcode);
    printf ("Child process ");
    switch (syscode)
    {
       case 0 : printf ("terminated normally\n");
                break;
       case 1 : printf ("exit with a Control-C\n");
                break;
       case 2 : printf ("exit with a hard error\n");
                break;
       case 3 : printf ("exit as a TSR program\n");
                break;
    }
 }

 Code Example 2
 --------------

 /* Call this sp2.c */
 #include <stdio.h>

 void main (void)
 {
    printf ("In program II\n");
    exit (77);
 }

 Since QuickC 2.00 and QuickAssembler 2.01 have the feature of using
 inline assembly, the AX register can be access directly without using
 any interrupts. The following line of code can be used in place of the
 interrupt call:

 _asm mov syscode, ah


 97. Link Error L1073

 Product Version(s): 5.01.21 5.01.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 11-AUG-1988    ArticleIdent: Q34142

    The linker error L1073 is documented in the CodeView and Utilities
 update section of the manuals for MASM Version 5.10, C Version 5.10,
 FORTRAN Version 4.10, and Pascal Version 4.00. The error message is as
 follows:

    L1073 file-segment limit exceeded.

    The number of physical file segments exceeds the limit of 254
 imposed by OS/2 protected mode and by Windows for each application or
 dynamic-link library. (A file segment is created for each group
 definition, nonpacked logical segment, and set of packed segments.)
    Reduce the number of segments or group more of them, making sure
 /PACKCODE is enabled.


 98. Clock: C Function -- Documentation Supplement

 Product Version(s): 5.10   |  5.10
 Operating System:   MS-DOS |  OS/2
 Flags: ENDUSER | S_QuickC S_QuickAsm docsup
 Last Modified: 17-JUL-1990    ArticleIdent: Q49729

 The clock function is documented as telling how much processor time
 has been used by the calling process. This definition is misleading.

 The clock function returns a clock_t (long) value, which is the
 difference between the time field (for seconds) and millitm field (for
 milliseconds) in the structure that is returned from two calls to the
 ftime function. The first call to ftime is made within the start-up
 code of the executing program, and the second call is made when the
 clock function is explicitly called in your code.

 This means that the value returned by clock is the number of CLK_TCKs
 (milliseconds) elapsed since the start-up code was executed, or -1 if
 the function was unsuccessful.

 Note: On most IBM PCs and compatibles, the clock speed is not fast
 enough to compute milliseconds, or indeed, hundredths of seconds. The
 ftime function calls interrupt 21, function 2Ch (under DOS), which
 returns, among other information, the seconds in hundredths. The
 hundredths information is an estimation from the clock speed, which is
 approximately 18.2 ticks per second on most PCs. This hundredths value
 is multiplied by 10 to get the millisecond value.

 Below is information on resetting the initial time value.

 The clock function references an external variable called _citime.
 This causes _cinitim.asm to get linked in to the .EXE, which in turn
 enters a function called _inittime into the start-up initialization
 table.

 The _inittime function, which is then called by the start-up code,
 simply makes a call to the ftime function, passing it a static timeb
 structure. Any further calls to the clock function subtract the values
 in this structure from the values in the structure returned by the
 ftime call in the clock function.

 In some cases, you might want to know the time elapsed between two or
 more internal points in a program. To reset the initial time value,
 make a call to the function _inittime, which makes a call to ftime,
 resetting the initial time structure to the current time. All
 subsequent calls to the clock function return the elapsed time since
 the last _inittime call.

 Other sources of information include the Version 5.10 "Microsoft C for
 the MS-DOS Operating System: Run-Time Library Reference," Page 167 and
 the clock function in the "C Run-Time Library Source Routines," which
 is available as a separate package.


 99. C4040 Occurs on Declaration of Huge Array

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | 5.10
 Flags: ENDUSER |
 Last Modified: 17-AUG-1988    ArticleIdent: Q34170

    The compiler warning "C4040 near/far/huge on identifier ignored"
 occurs on the declaration of a huge array if the array is not
 declared globally or statically. A huge or far array only can be
 declared at the global (or static) level because local (auto)
 variables are allocated on the stack and cannot be far or huge.
    To ensure that your arrays are allocated as huge or far arrays,
 declare them at the global level or declare them with the static
 storage class.


 100. Splitpath Document Error in readme.doc

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q34172

    The documentation in the C Version 5.10 readme.doc about the
 document error in the run-time library reference is incorrect. The
 documentation says the following:

         char * ext[4]

  should read

         char * ext[5]

    The documentation should say the following:

   should read

         char ext[5]

    In addition, drive, dir, fname, and ext should not have asterisks
 (stars, "*"'s) in front of them either.  A proper declaration is:

     char path_buffer[40], drive[3], dir[30], fname[9], ext[5];


 101. Path Strings Need Double Backslashes or fopen/open Fails

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 27-OCT-1988    ArticleIdent: Q34305

 Problem:

 According to Pages 444 and 274 of the "Microsoft C 5.10 Optimizing
 Compiler Run-Time Library Reference," I should be able to specify the
 path to the file that I want to open. However, I always receive a null
 pointer, indicating an error, when I attempt to open a file that is
 not in the current directory.

 I am using the following fopen statement:

 stream = fopen("d:\c\source\test.c", "r");

 Response:

 The following fopen statement will successfully open the file:

 stream = fopen("d:\\c\\source\\test.c", "r");

 Because the backslash has special meaning in C, it must be preceded by
 an additional backslash. In the case of the first (unsuccessful)
 example, a file named "d:csourcetest.c" actually is being searched for
 in the current directory. In the second example, the correct directory
 is searched for in the file "test.c".

 The following other functions are among those that use path names as
 input arguments:

 chdir, mkdir, rmdir, access, chmod, remove, rename, splitpath, stat,
 creat,  open, sopen, freopen, tempnam, execl, execle, execlp,
 execlpe, execv, execve, execvp, execvpe, spawnl, spawnle, spawnlp,
 spawnlpe, spawnv, spawnve, spawnvp, spawnvpe, system, _dos_creat,
 _dos_creatnew, _dos_findfirst, _dos_getfileattr, _dos_open,
 _dos_setfileattr, utime, putenv, _searchenv


 102. Manual-Setup Procedure for C

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JAN-1990    ArticleIdent: Q34310

 The following is a manual-setup procedure for C.

 Manual Setup Procedure For Microsoft C (DOS only) System
 Configurations:

 Directory:

 C:\MSC\BIN                  Executable file (*.EXE)
 C:\MSC\LIB                  Library and Object modules (*.LIB, *.OBJ)
 C:\MSC\INCLUDE              Include (or header) files (*.H)
 C:\MSC\SRC                  Sample C programs
 C:\MSC\UTILS                Utilities, such as LINK.EXE, CV.EXE ect.
 C:\MSC\INIT                 Initialization files (*.INI)
 C:\MSC\TEMP                 Temporary files for the C compiler only
                             No files copied into this directory

 Autoexec.bat:

 SET LIB=C:\MSC\LIB
 SET INCLUDE=C:\MSC\INCLUDE
 SET TMP=C:\MSC\TEMP
 SET INIT=C:\MSC\INIT
 SET PATH=C:\MSC\UTILS;C:\MSC\BIN;C:\MSC\SRC

 Config.sys:

 Files=20
 Buffers=20
 Shell=C:\Command.com /e: 1024 /p

 (Note that the above use of the Shell command is typically only
 supported for DOS Versions 3.20 and later.)

 Files to Copy:

 Copy the following files into the C:\MSC\BIN directory:

 C1.EXE      C1L.EXE
 C2.EXE      MOUSE.COM
 C3.EXE      QCL.HLP
 CL.EXE      C23.ERR
 QC.EXE      QC.HLP
 QCL.EXE

 Copy all the INCLUDE files with .H extensions into the C:\MSC\INCLUDE
 directory.

 Copy the following files into the C:\MSC\UTILS directory:

 LINK.EXE
 M.EXE
 LIB.EXE
 CV.EXE
 CV.HLP
 Any other utilities, such as EXEMOD.EXE

 Copy the following files into the C:\MSC\INIT directory:

 TOOLS.INI
 Any other .INI file

 Copy any C sample programs provided with the compiler into the
 C:\MSC\SRC directory.

 Running The Library Manager -- LIB.EXE:

 The following section assumes that the above configurations where
 followed and the operations completed. The following section is on
 libraries.

 The C linker searches the C:\MSC\LIB directory to find either C
 combined libraries or explicitly named libraries. The Microsoft naming
 convention for combined libraries is xLIByz.LIB. x is either S, M, C,
 or L for Small, Medium, Compact, or Large, respectively. y is the
 language, in this case C. z is the math libraries; A, E, 7 for
 Alternate, Emulation, or 87 coprocessor, respectively.

 The following is an example:

 MLIBCE.LIB  is the (M)edium model, (C) (E)mulation combined library

 Copy the following files into the C:\MSC\LIB directory:

 xLIBy.lib
 sDLIBC.LIB          Depending on what is desired
 mLIBC.LIB
 cLIBC.LIB
 lLIBC.LIB
 EM.LIB or 87.LIB    Depending on what is desired, none for alt. math
 xLIBFz.LIB          z is A for alternate or P for other
 sLIBFz.LIB          Depending on choice above
 mLIBFz.LIB
 cLIBFz.LIB
 lLIBFz.LIB
 LIBH.LIB
 GRAPHICS.LIB        ( Optional )

 The following is an example of how to run the library manager:

 1. At the operating system prompt, type LIB, then the name you
    want to call the library with the .LIB extension.

 2. Press the ENTER key. The prompt will say OPERATIONS.

 3. Enter the desired operations, such as appending stand alone .LIB
    or .OBJ files. If the number of modules is too many for one text
    line, the at sign, "@", can be used as a continuation character.

 4. A list ( *.LST ) file is asked for, which is optional.

 The following example demonstrates this process:

         C:\> LIB name.lib
              Operations: +mod1.lib + mod2.lib + ... +modk.lib@
              Operations: +...+ modn.lib
              List File: name.lst

 Name.lst contains a listing of all the functions that occur in
 name.lib.

 The following is an example of how to build the C Medium model,
 Emulation library with graphics:

    C:\> LIB mlibce.lib
    Operations: +mlibc.lib +em.lib +mlibfp.lib +libh.lib +graphics.lib
    List File: <ENTER>  ( pressing enter here will suppress the
                                    creation of a listing file. )

 The above example can be repeated with appropriate modifications to
 create the other C combined libraries.


 103. Documentation Error Regarding Precedence Operators

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q34360

    There is a documentation error regarding C Version 5.00 and Version
 5.10 operator precedence. Table 5.1 on Page 137 of the "Microsoft C
 Language Reference Manual" shows two curly braces. Both of these curly
 braces are over-extended in printing.
    The curly brace at the top should only extend from the second line
 to the third line; the curly brace at the bottom should start at the
 fourth-to-last line and stop at the second-to-last line.


 104. Unresolved Externals Link Errors for OS/2 Calls

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q34372

 Question:

 Why do I get unresolved externals for all of my API calls when I link
 object files produced by the C Version 5.10 compiler?

 Response:

 You can control the OS/2 files to include by defining certain symbols
 in your source code. A few of the more common ones are listed below:

 #define INCL_BASE        /*  all OS/2 base definitions        */
 #define INCL_DOS         /*  OS/2 DOS kernel                  */
 #define INCL_SUB         /*  VIO, keyboard, mouse functions   */
 #define INCL_DOSERRORS   /*  OS/2 errors                      */

 One or more of the above definitions should be followed by the
 following:

 #include <os2.h>

 The above #defines and #include preprocessor directives will start a
 chain reaction of #defines and #includes that will define the API
 functions in the respective categories of functions. You can follow
 this series to determine the minimum prototypes required for the API
 functions called by your application.

 If the proper constant is not defined in your source code above the
 line where you include OS2.H, there will be no prototypes for API
 functions.

 All of the API functions must be declared with the Pascal calling
 convention. If there are no prototypes to tell the compiler to use the
 Pascal calling convention, the compiler will use the default C calling
 convention. The C calling convention will place an underscore (_) in
 front of each function called; therefore, each function will be
 incorrectly named, resulting in unresolved externals at link time. The
 Pascal calling convention does not place an underscore in front of
 each function, so if the correct prototypes are given, the linker will
 resolve all of the references to the API functions in the DOSCALLS.LIB
 library.

 This information is documented in the README.DOC file that comes with
 Microsoft C Version 5.10.


 105. Maximum of 40 File Handles in C 5.10 Multi-Thread Programs

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34386

 Question:
    Can I increase the number of file handles to more than 40
 in a multi-threaded application produced by C Version 5.10?

 Response:
    The maximum number of file handles available for multiple-threaded
 applications is 40 by default; this number cannot be increased because
 the multi-threaded startup code is unavailable. Consequently, the C
 startup code constant _NFILE_, which is used to specify the number of
 available file handles, cannot be changed from its default of 40, even
 though the default number of file handles in OS/2 is 255.



 106. _getimage() Buffer Format is Proprietary

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-DEC-1989    ArticleIdent: Q34388

 Question:
    What is the internal representation of the screen image saved by
 the _getimage C run-time library function for DOS?

 Response:
    Microsoft does not currently release information on the internal
 representation of graphic images saved by _getimage.


 107. Far Pointer Comparisons Assume Same Segment

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34408

 When comparing Far pointers with the <, >, <=, or >= operators, the
 two pointers must be in the same segment. The equality operator (==)
 tests both segment and offset to prevent two pointers that have the
 same offset but different segments from being considered equal.

 The <, >, <=, and >= operators assume that the pointer share the same
 segment because according to the Draft proposed ANSI C standard,
 pointers can only be compared for precedence if they point to the same
 object. In a segmented architecture such as Intel's, two pointers to
 the same object must share the same segment value (unless the
 pointers are declared to point to a huge object, in which case
 the pointers are handled using 32-bit arithmetic).


 108. Far Pointer Comparisons Don't Account for Aliases

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34410

 The code generated to compare two far pointers for equality does not
 account for the possibility of the pointers having different segments
 and offsets, yet still pointing to the same location.

 This is correct behavior for the compiler. Only huge pointers are
 normalized. Near and Far pointers that point into the same segment are
 assumed to have the same segment values; any differences between them
 must be in the offset.

 Normalizing pointers would involve a tremendous performance penalty
 under MS-DOS and would be impossible under OS/2 due to the
 protected-mode addressing scheme.


 109. LINT_ARGS Is Predefined in C Versions 5.x

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 18-AUG-1988    ArticleIdent: Q34437

 The special identifier LINT_ARGS, which enables type checking, is
 predefined in Microsoft C Versions 5.00 and later. No preprocessor
 directive or compile option is needed to define this identifier.

 Microsoft C Version 4.00 provides the option to enable type checking
 on C run-time library function calls. To enable this option in C
 Version 4.00, define the special identifier LINT_ARGS either by
 placing a #define directive before any #include directives for include
 files that contain run-time library function declarations, or by using
 the /DLINT_ARGS (or /D LINT_ARGS) compilation option.

 Defining LINT_ARGS makes the function declarations available that are
 enclosed in preprocessor #ifdefined() blocks and that are included
 only if LINT_ARGS is defined.


 110. Installing C on a Network Violates License Agreement

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34445

 Installing software from the C, FORTRAN, Macro Assembler, Pascal, or
 Quick C retail packages on a network is prohibited by the Microsoft
 License Agreement.

 These applications are single-user products; network versions of them
 are unavailable at this time.



 111. Library Reference Defines Unused result Pointer

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q34520

 The program example for qsort on Page 476 in the "Microsoft C
 Optimizing Compiler Run-Time Library Reference" has a documentation
 error. The following first declaration within the main function, is
 unnecessary:

 char **result;

 The result pointer is never used in the program.


 112. "User's Guide" Index Reference for /F Is Page 122 Not Page 123

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q34567

 The "Microsoft C Optimizing Compiler User's Guide" index has a
 typographical error. The page reference for "/F option" is given as
 Page 123; however, it should be Page 122.


 113. Run-Time Limits for C Version 5.10

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34856

 The following is a table of run-time limits in the Microsoft C
 Compiler Version 5.10:

 Program Limits at Run Time

 Item            Description                 Limit

 Files           Maximum file size           (2**32) - 1 bytes
                                             (i.e., 4 gigabytes)
         (or limit imposed by DOS, 32 megabytes
         as of DOS 3.3)

                 Maximum number
                 of open files (streams)     20
                 (Five streams are opened automatically (stdin,
                 stdout, stdaux, and stdprn), leaving 15 files
                 available for the program to open.
         Instructions for increasing this limit up to 127 are
         included in the README.DOC of Version 5.10.)

 Command line    Maximum number of           128
                 characters(including
                 program name)

 Environment     Maximum size                32K
 table

 This table is listed on Page 286 of the user's guide contained
 in the "Microsoft C 5.1 Optimizing Compiler" manual.


 114. C4047 Occurs when Function Prototype Is Omitted or Misnamed

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 26-AUG-1988    ArticleIdent: Q34859

 The compiler warning message

 "C4047 'operator' : different levels of indirection"

 can occur when a function prototype declaration is not specified, when
 the header file that contains the declaration is not given in a
 #include directive, when a reference to a function is misspelled,
 or when a pointer is assigned a value of a different type without
 using an appropriate type cast.

 When the function declaration is omitted, a default prototype is
 created with a return type of int assumed. A later use of the function
 then may cause the C4047 warning, such as assigning the return value
 of the function to a non-int variable.

 If the call to the function is not spelled the same as the name of the
 prototype, the prototype will not be referred to, the default
 assumption for the function return type will be int, and the warning
 may occur.

 More information on function prototyping can be found beginning on
 Page 169 in Chapter 7 of the "Microsoft C Optimizing Compiler Language
 Reference" manual.


 115. Array Reference Gives "C4046 '&' on Function/Array, Ignored"

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 26-AUG-1988    ArticleIdent: Q34905

 The following compiler warning message occurs when an array is
 referred to incorrectly by the address-of operator (&).

 C4046 '&' on function/array, ignored

 The following program causes the warning C4046:

 void main(void);
 void main(void)
 {
  char array[10];
  char *ptr_to_array;
  ptr_to_array = &array;
 }

 To clear up the warning, make the assignment read either

 ptr_to_array = array;

 or

 ptr_to_array = &array[0];

 More information about arrays can be found in the last paragraph on
 Page 104 and in Example 1 on Page 119 of the "Microsoft C Optimizing
 Compiler Language Reference" manual.


 116. Run-Time Library Reference _getfillmask, _setfillmask docerrs

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | 5.10
 Flags: ENDUSER | docerr
 Last Modified: 26-AUG-1988    ArticleIdent: Q34906

 The program examples for _getfillmask and _setfillmask, on Pages
 325-326 and Pages 521-522 of the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" have an error. The fill mask array is
 incorrectly initialized. Back slashes are required prior to "x" for
 specifying hexadecimal constants for the char variables of the masks.

 The following sample code correctly initializes the char variables:

 #include <stdio.h>
 #include <graph.h>

 unsigned char *(style[6])={"\x78\x30\x30\x78\x30\x30\x78\x30",
                            "\x78\x32\x30\x78\x30\x38\x78\x32",
                            "\x78\x39\x38\x78\x63\x36\x78\x33",
                            "\x78\x65\x36\x78\x33\x38\x78\x62",
                            "\x78\x66\x63\x78\x65\x65\x78\x37",
                            "\x78\x66\x65\x78\x66\x65\x78\x66"};

 char *oldstyle = "12345678"; /* place holder for old style */

 main()
 {
  int loop;
  _setvideomode(_MRES4COLOR);
  _getfillmask( oldstyle );
  _setcolor( 2 ); /* draw an ellipse under the */
  /* middle few rectangles in a different color */
  _ellipse( _GFILLINTERIOR, 120, 75, 200, 125 );
  _setcolor( 3 );
  for ( loop = 0; loop < 6; loop++ ) {
  /* make 6 rectangles, the first background color */
  _setfillmask( (char far *)(style[ loop ]) );
  _rectangle(_GFILLINTERIOR,loop*40+5,90,(loop+1)*40,110);
  }
  _setfillmask( oldstyle ); /* restore old style */
  while ( !kbhit() ); /* Strike any key to continue */
  _setvideomode (_DEFAULTMODE);
 }


 117. Mixed Expressions Can Cause Unsigned Division

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34920

 The ANSI C standard specifies that when a signed and unsigned integer
 are involved in an arithmetic expression, the signed integer is to be
 converted to the type of the unsigned before expression evaluation. If
 the signed integer is negative, the sign will be lost and the value
 will change, even though the bit pattern will remain the same.

 This situation is especially a problem with functions that return a
 value of type size_t, which is an alias for unsigned int in our
 implementation. Note that this is not a problem or a code generation
 error, this is the expected behavior.

 For example, if the statement

 i = (4 - strlen("1234567890")) / 2;

 is executed, the value of i will be 32765 rather than -3 as one might
 expect because the expression (4 - strlen("1234567890")) is an
 unsigned integer expression with the value of 65530 rather than a
 signed expression with the value of -6. If you look at the code
 generated, you'll notice that an instruction that performs unsigned
 division is generated rather than a one that performs signed division.

 To avoid this behavior, use a typecast on the return value
 of strlen() so that it is treated as an int. For the example
 above, the statement

 i = (4 - (int) strlen("1234567890")) / 2;

 would have generated the desired value of -3. Note that even this code
 would have failed if the length of the string was greater than 32767;
 however, the incorrect code above fails if the length of the string is
 greater than four.

 Runtime functions that return values of type size_t, unsigned, or
 unsigned long include the following:

 strtoul, _getlinestyle, fread, fwrite, _clear87, _control87,
 _status87, _fmsize, _memavl, _memmax, _msize, _nmsize,
 stackavail, strcspn, strlen, strspn, _bios_disk,
 _bios_equiplist, _bios_keybrd, _bios_memsize, _bios_printer,
 _bios_serialcom, _bios_timeofday, _dos_allocmem, _dos_close,
 _dos_creat, _dos_creatnew, _dos_findfirst, _dos_findnext,
 _dos_freemem, _dos_getdate, _dos_getdiskfree,
 _dos_getfileattr, _dos_getftime, _dos_gettime, _dos_open,
 _dos_read, _dos_setblock, _dos_setdate, _dos_setfileattr,
 _dos_setftime, _dos_settime, _dos_write, FP_OFF, FP_SEG,
 long_lrotl, long_lrotr, _rotl, and _rotr


 118. The Proper Type for Pointer To jmp_buf Is void *

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34921

 The setjmp() and longjmp() functions use a parameter of type jmp_buf.
 (The type jmp_buf is declared in setjmp.h.) Using the & operator
 ("address of") on a variable of type jmp_buf generates the following
 message:

 warning C4046: '&' on function/array, ignored

 Leaving the ampersand (&) off and assigning the value to a
 variable badptr declared, as follows

 set_jmp *bad_ptr;

 generates the following message:

 warning C4047: '=' : different levels of indirection

 To solve the problem, declare the pointer to be of type void *,
 as follows:

 void *goodptr;

 Then, assign it without using the ampersand, as follows:

 goodptr = buf;

 Because the header file setjmp.h defines a jmp_buf as an array of
 integers, using the ampersand operator generates the warning described
 above. The reason for choosing an array type rather than a structure
 has to do with common C coding practices and is described in section
 4.6 of the Rationale for the ANSI C Standard.

 Basically, the setjmp() function must change the jmp_buf parameter in
 order to record where to come back to when longjmp() is executed.
 Elsewhere, the standard defines setjmp() as taking a single parameter
 of type jmp_buf, NOT of type "pointer to jmp_buf." The jmp_buf cannot
 be a structure because structures are passed by value and therefore
 could not receive changes made by setjmp(). Since arrays are passed by
 reference (i.e. by their address), setjmp() can change a parameter
 that is passed as an array.

 The declaration for badptr (below) declares it to be of type "pointer
 to array of integer," not "pointer to integer." Doing an assignment
 with different pointer types gives the C4047 warning error. (In order
 to do the assignment without a warning, badptr would have to be
 "pointer to integer" because that's the compatible pointer type for
 "array of integer.")

 Instead, using goodptr, declared "pointer to void," allows the
 assignment to be made without generating a warning. This is also
 portable code. Note that you cannot use indirection (or subscripting,
 which is a form of indirection) on void pointers.

 However, because you don't know what's in the jump buffer anyway, this
 should be no problem. (The contents of the jump buffer are
 implementation-dependent and could even differ from version to version
 of the same compiler. Any code that directly manipulates jump buffers
 is also implementation-dependent and non-portable.)

 A brief example program follows:

 #include <stdio.h>
 #include <setjmp.h>

 jmp_buf buf;
 jmp_buf *badptr;
 void *goodptr;

 main()
 {
     badptr = &buf;
         /*  warning C4046: '&' on function/array, ignored        */
         /*  warning C4047: '=' : different levels of indirection */

     badptr = buf;
         /*  warning C4047: '=' : different levels of indirection  */

     goodptr = buf;
         /*    this works and is the proper way to do this!!!      */

     exit(0);
 }


 119. Corrections to the _setbkcolor Example

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q34923

 Problem:

 The example program on Page 515 of the "Microsoft C 5.0 (and 5.1)
 Optimizing Compiler Run-Time Library Reference" and the "Microsoft
 QuickC Run-Time Library Reference" is supposed to run through 20
 different background colors, displaying the use of _setbkcolor. When I
 try to run the program, my screen flickers and I am returned to the
 DOS prompt.

 Response:

 The example is incorrect. The following example changes the background
 color in graphics mode (this example can be found on the Libraries 1
 disk of the QuickC Version 1.01 compiler, in PROGRAMS\SBKCOL.C):

 #include <stdio.h>
 #include <graph.h>

 long color[16] = {_BLACK,_BLUE,_GREEN,_CYAN,_RED,_MAGENTA,
      _BROWN,_WHITE,_GRAY,_LIGHTBLUE,_LIGHTGREEN,_LIGHTCYAN,
      _LIGHTRED,_LIGHTMAGENTA,_LIGHTYELLOW,_BRIGHTWHITE};

 main()
 {
  int loop;
  long i;
  _setvideomode(_HRES16COLOR);
  for (loop = 0; loop < 16; loop++ ) {
  _setbkcolor(color[loop]);
  for (i=0; i < 50000; i++)     /* null loop */
     ;
  _setvideomode (_DEFAULTMODE);
 }

 The next example changes the background color in text mode:

 #include <stdio.h>
 #include <graph.h>

 main()
 {
   long loop;
   for (loop = 0; loop < 16; loop++)
     {
       _setbkcolor(loop);
       _outtext("    hello    \n");
     }
 }


 120. Errors R6012 to R6015 Documented in QuickC 1.01 Guide

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-MAR-1990    ArticleIdent: Q34988

 The C Run-Time error messages below are not included in
 "Appendix E -- Error Messages" in the "Microsoft C Optimizing Compiler
 User's Guide"; nor are they located in ERRMSG.DOC. They are documented
 in the "Microsoft QuickC Compiler Programmer's Guide" on Page 363, as
 follows:

 R6012 invalid near pointer reference
 R6013 invalid far pointer reference
 R6014 control-BREAK encountered
 R6015 unexpected interrupt

 According to the README.DOC found on the Product Disk for QuickC
 Version 1.00 and on the Setup Disk for QuickC Version 1.01, the
 run-time error messages R6012 and R6013 have changed as follows:

 1. R6012 illegal near pointer use

    A null near pointer was used in the program.

    This error only occurs if pointer checking is in effect (i.e.,
    if the program was compiled in the QuickC environment
    with the Pointer Check option in the Compile dialog box, the
    /Zr option on the QCL command line, or the pointer_check
    pragma in effect).

 2. R6013 illegal far pointer use

    An out-of-range far pointer was used in the program.

    This error only occurs if pointer checking is in effect (i.e. if
    the program was compiled in the QuickC environment with the
    Pointer Check option in the Compile dialog box, the /Zr option
    on the QCL command line, or the pointer_check pragma in effect).

 In addition, the following new error messages are documented:

 1. R6014 control-BREAK encountered

    You pressed CTRL+BREAK to stop the execution of a program within
    the QuickC environment.

 2. R6015 unexpected interrupt

    The program could not be run because it contained unexpected
    interrupts.

 When you create an in-memory program from a program list, QuickC
 automatically creates object files and passes them to the linker. If
 you compile with the Debug option turned on, the object files that
 QuickC passes to the linker contain interrupts that are required
 within the QuickC environment. However, you cannot run a program
 created from such object files outside of the QuickC programming
 environment.


 121. Unresolved Externals when Linking for Protected Mode

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35031

 Problem:

 I am compiling my C program for protected-mode with the command:

 cl /Lp demo.c

 I'm using the Microsoft Segmented-Executable Linker Version
 5.01.04, but at link-time I get about 10 unresolved externals,
 all of which are OS/2 API calls such as DOSWRITE, DOSCLOSE,
 DOSEXIT.

 If I link in the library DOSCALLS.LIB, as follows, the problem is
 corrected:

 cl /Lp demo.c doscalls.lib

 The manual does not state that DOSCALLS.LIB must be explicitly linked.

 Response:

 This problem occurs because you are using the wrong version of the
 Microsoft Segmented-Executable Linker. You should be using Version
 5.01.21, which was distributed with C Version 5.10. Version 5.01.04 is
 the OS/2 linker.

 You must link in DOSCALLS.LIB with Version 5.01.04 because this
 version of LINK does not have the ability to bring in libraries that
 are themselves requested by a library.

 The library xLIBCyP.LIB (where x is the memory model and y is the math
 package) contains a request for DOSCALLS.LIB. Link Version 5.01.21
 understands this request and searches for DOSCALLS.LIB in the
 directories specified in the LIB environment variable; LINK Version
 5.01.04 does not understand this request.


 122. Don't Place Communal Data in Libraries

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | S_LIB S_LINK  lib link
 Last Modified:  8-SEP-1988    ArticleIdent: Q35032

 Do not declare unitialized (communal) data in modules that will
 be placed in libraries. Doing so may result in the module not
 being included at link time.

 This information is documented in the last paragraph on Page 84 of the
 "Microsoft C Language Reference" manual, which states the following:

 "Unitialized variable declarations at the external level are
 not recommended for any file that might be placed in a library."

 Microsoft C supports four different storage classes for variables
 declared at the external level, as follows:

 1.  Static variables are local to the module and do not generate
     external references or public definitions, i.e., no other modules
     may reference these variables.

 2.  Initialized variables, without static, are allocated storage
     and generate public definitions, i.e., other modules may share
     these variables.

 3.  Uninitialized variables, with extern, are not allocated
     storage and they generate external references, i.e, this module
     isn't declaring the data, but it wants to share the data that other
     modules declare.

 4.  Communal variables are global variables that are not initialized
     or given the extern modifier. A communal variable is one that is
     used by everybody but not necessarily declared public by anybody;
     the linker will allocate storage for it, if needed.

     Communal variables do not have external references or public
     definitions. When the program is linked, if a public definition
     with the same name is found, all communal declarations are treated
     as external references. If no definition is found, the linker will
     allocate storage and again the communal declarations are treated
     like references. When a module is added to a library, the librarian
     takes all public definitions and adds them to the dictionary to be
     searched when the linker resolves references to the library.

 Note: Communal variables are NOT added to the dictionary. To do so
 would cause conflicts with other communal declarations and a possible
 public definition.

 A good way to declare data in a multi-module program is to use a
 single module that contains public definitions while every other
 module uses the extern modifier. You do not need to actually
 initialize all variables in this one module as long as one of them is
 initialized. This process is sufficient to force the module to be
 brought in while linking.


 123. How C Interprets Integer Constants with Leading Zeroes

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 18-OCT-1988    ArticleIdent: Q35037

 Question:

 Why do the assignments "a = 20" and "a = 020" return different results
 when the values are printed? Why aren't 020 and 20 the same?

 The following is an example:

 a = 20;
 printf("%d", a);   /* this prints "20" */
 a = 020;
 printf("%d", a);   /* but this prints "16" */

 Response:

 In C, any number preceded by a 0 is handled as an octal number (base
 8). Therefore, "a = 20" is handled as you would expect; however, "a =
 020" is handled as an octal number and therefore represents the
 decimal value 16.

 Note also that ALL character constants of the form '\o', '\oo',
 '\ooo', and the string equivalents are always octal as well.  (Hex
 character constants start with "\x".)  For instance, '\33' or '\033'
 are both the ESCape character (decimal 27, hex 1B).  There is no way
 to use decimal numbers to specify a character constant; however, you
 may use decimal integer constants instead (example: ch = 27;  ).


 124. Weitek WTL 1167 Math Coprocessor Support

 Product Version(s): 5.x    | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35142

 The Weitek WTL 1167 is found on Compaq's Weitek Coprocessor Board. The
 WTL 1167 is a set of three chips used as a replacement for the Intel
 80387. Benchmarks in the 1988 March BYTE, show the WTL 1167 with a 7
 percent to 68 percent speed increase over the 80387 on processing of
 double-precision numbers. ("Real-World" speed increase is more like 30
 percent.) Compaq's Weitek Coprocessor Board was designed with an 80387
 socket.

 Microsoft only has Math Coprocessor support for Intel chips. If you
 have the WTL 1167 on a Compaq Weitek Coprocessor Board, you also must
 have an 80387 to use our Math Coprocessor Library. Without the 80387
 you will have to use our Emulator or Alternate Math Libraries, or link
 with a third-party library.



 125. Monochrome Display Adapter Normal Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35285

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Normal Text, No Blinking, No
 Underlining, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(2);            /* foreground color Green */
  _setbkcolor(0L);             /* background color Black */
  _outtext("Normal Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 126. MDA Bright Underlined Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35286

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Bright Text, No Blinking,
 Underlined, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(9);            /* foreground color Intence Blue */
  _setbkcolor(0L);             /* background color Black */
  _outtext("Bright Underlined Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 127. MDA Normal Inverse Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35287

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Normal Text, No Blinking, No
 Underlining, and Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(0);            /* foreground color Black */
  _setbkcolor(7L);             /* background color White */
  _outtext("Normal Inverse Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 128. MDA Blinking Normal Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 27-OCT-1988    ArticleIdent: Q35288

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Normal Text, Blinking, No
 Underlining, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(18);           /* foreground color Green + 16 */
  _setbkcolor(0L);             /* background color Black */
  _outtext("Blinking Normal Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 129. MDA Blinking Bright Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35289

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Bright Text, Blinking, No
 Underlining, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(26);       /* foreground color Intense Green + 16 */
  _setbkcolor(0L);         /* background color Black */
  _outtext("Blinking Bright Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 130. MDA Blinking Normal Underlined Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35290

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Normal Text, Blinking,
 Underlined, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(17);           /* foreground color Blue + 16 */
  _setbkcolor(0L);             /* background color Black */
  _outtext("Blinking Normal Underlined Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 131. MDA Blinking Bright Underlined Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35291

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Bright Text, Blinking,
 Underlined, and No Inverse on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(25);           /* foreground color Intence Blue + 16 */
  _setbkcolor(0L);             /* background color Black */
  _outtext("Blinking Bright Underlined Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 132. MDA Blinking Normal Inverse Text Example

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35292

 On a monochrome display adapter, there is no way to display colors.
 However, you can display Normal Text, Bright Text, Reverse Video,
 Underline, and Blinking.

 The following program shows how to get Normal Text, Blinking, No
 Underlining, and Inverse, on a monochrome display adapter:

 #include<graph.h>
 int     oldcolor;
 long    oldbkcolor;

 main()
 {
  _clearscreen(_GCLEARSCREEN);
  oldcolor=_gettextcolor();
  oldbkcolor=_getbkcolor();
  _settextposition(12,0);
  _settextcolor(16);            /* foreground color Black + 16 */
  _setbkcolor(7L);             /* background color White */
  _outtext("Blinking Normal Inverse Text, on Mono\n");
  _settextcolor(oldcolor);
  _setbkcolor(oldbkcolor);
 }


 133. Directory Listing of C 5.10 for OS/2 Distribution Disks

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35293

 Below is a listing of the directories for each of the Microsoft C
 Version 5.10 Optimizing Compiler distribution disks for the OS/2 and
 DOS dual mode (5.25-inch disks). The information is the resulting
 output when the DOS command "dir" is performed on each directory and
 subdirectory.

 A line of colons (:::::) separates each disk; subdirectories are
 listed below their parent directory. The first line of each disk
 description is the name of the disk as it is printed on the label.
 Information in parentheses is supplemental and not contained on the
 disk label.

 The following is a listing of directories for C Version 5.10
 distribution disks:

 (Disk 1 of 14)  -  Setup

  Volume in drive A has no label
  Directory of  A:\

 README   DOC    63360   3-07-88   5:10a
 UTILITY  DOC    17794   3-07-88   5:10a
 PACKING  LST    11814   3-07-88   5:10a
 CL       EXE    31329   3-07-88   5:10a
 CL       HLP     2169   3-07-88   5:10a
 CL       ERR     2276   3-07-88   5:10a
 C1       EXE   114521   3-07-88   5:10a
 C23      ERR     3272   3-07-88   5:10a
 SETUP    EXE    93033   3-07-88   5:10a
 SETUP    DOC    15179   3-07-88   5:10a
        10 File(s)      3072 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 2 of 14)  -  Include Files and Startup Source Code

  Volume in drive A has no label
  Directory of  A:\

 STARTUP      <DIR>      3-07-88   5:10a
 INCLUDE      <DIR>      3-07-88   5:10a
         2 File(s)     29696 bytes free

  Volume in drive A has no label
  Directory of  A:\INCLUDE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SYS          <DIR>      3-07-88   5:10a
 ASSERT   H        699   3-07-88   5:10a
 BIOS     H       4866   3-07-88   5:10a
 CONIO    H        952   3-07-88   5:10a
 CTYPE    H       2465   3-07-88   5:10a
 DIRECT   H        690   3-07-88   5:10a
 DOS      H       5917   3-07-88   5:10a
 ERRNO    H       1283   3-07-88   5:10a
 FCNTL    H       1255   3-07-88   5:10a
 FLOAT    H       6011   3-07-88   5:10a
 GRAPH    H       7480   3-07-88   5:10a
 IO       H       1294   3-07-88   5:10a
 LIMITS   H       1553   3-07-88   5:10a
 MALLOC   H       3097   3-07-88   5:10a
 MATH     H       3324   3-07-88   5:10a
 MEMORY   H       1065   3-07-88   5:10a
 SEARCH   H       1025   3-07-88   5:10a
 SETJMP   H        907   3-07-88   5:10a
 SHARE    H        554   3-07-88   5:10a
 SIGNAL   H       1905   3-07-88   5:10a
 STDARG   H        614   3-07-88   5:10a
 STDDEF   H       1100   3-07-88   5:10a
 STDIO    H       4500   3-07-88   5:10a
 STDLIB   H       4900   3-07-88   5:10a
 STRING   H       2209   3-07-88   5:10a
 TIME     H       2342   3-07-88   5:10a
 VARARGS  H        642   3-07-88   5:10a
 PROCESS  H       1988   3-07-88   5:10a
 OS2      H        707   3-07-88   5:10a
 OS2DEF   H       5891   3-07-88   5:10a
 BSE      H       1139   3-07-88   5:10a
 BSEDOS   H      17730   3-07-88   5:10a
 BSEERR   H      20940   3-07-88   5:10a
 BSESUB   H      11512   3-07-88   5:10a
        36 File(s)     29696 bytes free

  Volume in drive A has no label
  Directory of  A:\INCLUDE\SYS

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 LOCKING  H        573   3-07-88   5:10a
 STAT     H       1497   3-07-88   5:10a
 TIMEB    H        844   3-07-88   5:10a
 TYPES    H        849   3-07-88   5:10a
 UTIME    H       1061   3-07-88   5:10a
         7 File(s)     29696 bytes free

  Volume in drive A has no label
  Directory of  A:\STARTUP

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 DOS          <DIR>      3-07-88   5:10a
 OS2          <DIR>      3-07-88   5:10a
 FILE2    H       1027   3-07-88   5:10a
 MSDOS    H       6849   3-07-88   5:10a
 REGISTER H        922   3-07-88   5:10a
 STARTUP  BAT     1663   3-07-88   5:10a
 MAKEFILE         4148   3-07-88   5:10a
 CHKSTK   ASM     2044   3-07-88   5:10a
 CHKSUM   ASM     3524   3-07-88   5:10a
 NULBODY  C         13   3-07-88   5:10a
 README   DOC     3199   3-07-88   5:10a
 MSDOS    INC     6181   3-07-88   5:10a
 CMACROS  INC    12066   3-07-88   5:10a
 BRKCTL   INC      784   3-07-88   5:10a
 VERSION  INC      503   3-07-88   5:10a
 WILD     C       7182   3-07-88   5:10a
 _FILE    C       1691   3-07-88   5:10a
 CRT0FP   ASM     2223   3-07-88   5:10a
 FMSGHDR  ASM     2429   3-07-88   5:10a
 SETARGV  ASM      971   3-07-88   5:10a
        22 File(s)     29696 bytes free

  Volume in drive A has no label
  Directory of  A:\STARTUP\DOS

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 NULBODY  LNK      149   3-07-88   5:10a
 STDENVP  ASM     3780   3-07-88   5:10a
 CRT0     ASM     7612   3-07-88   5:10a
 CRT0DAT  ASM    14175   3-07-88   5:10a
 CRT0MSG  ASM     2840   3-07-88   5:10a
 EXECMSG  ASM     1337   3-07-88   5:10a
 NMSGHDR  ASM     3010   3-07-88   5:10a
 STDALLOC ASM     2825   3-07-88   5:10a
 STDARGV  ASM    13852   3-07-88   5:10a
        11 File(s)     29696 bytes free

  Volume in drive A has no label
  Directory of  A:\STARTUP\OS2

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 NULBODY  LNK      168   3-07-88   5:10a
 CRT0     ASM    10312   3-07-88   5:10a
 STDENVP  ASM     5362   3-07-88   5:10a
 CRT0DAT  ASM    10496   3-07-88   5:10a
 CRT0MSG  ASM     2891   3-07-88   5:10a
 EXECMSG  ASM     2231   3-07-88   5:10a
 NMSGHDR  ASM     3486   3-07-88   5:10a
 STDALLOC ASM     3245   3-07-88   5:10a
 STDARGV  ASM    13623   3-07-88   5:10a
        11 File(s)     29696 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 3 of 14)  -  Compiler 1

  Volume in drive A has no label
  Directory of  A:\

 PATCH        <DIR>      3-07-88   5:10a
 C1       ERR    14393   3-07-88   5:10a
 C1L      EXE   149303   3-07-88   5:10a
 C3       EXE   125221   3-07-88   5:10a
 ERRMSG   DOC    17293   3-07-88   5:10a
 FPEXCEPT DOC    16254   3-07-88   5:10a
         6 File(s)     15360 bytes free

  Volume in drive A has no label
  Directory of  A:\PATCH

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 PATCH87  DOC     3937   3-07-88   5:10a
 PATCH87  EXE     4206   3-07-88   5:10a
 SETRHS   EXE      543   3-07-88   5:10a
 RMRHS    EXE      543   3-07-88   5:10a
 STKPAT   BAT       94   3-07-88   5:10a
 STKPAT   SCR       30   3-07-88   5:10a
 PTRACE87 PAT      188   3-07-88   5:10a
 PATCH320 DOC     2169   3-07-88   5:10a
 OS2PATCH EXE     1069   3-07-88   5:10a
 OS2PATCH DOC     1401   3-07-88   5:10a
        12 File(s)     15360 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 4 of 14)  -  Compiler 2

  Volume in drive A has no label
  Directory of  A:\

 FIXSHIFT COM      688   3-07-88   5:10a
 MSHERC   COM     6749   3-07-88   5:10a
 QLIB     DOC    12047   3-07-88   5:10a
 QLIB     EXE    24557   3-07-88   5:10a
 QLIB     INI     2905   3-07-88   5:10a
 C2       EXE   202919   3-07-88   5:10a
 QC       HLP    50649   3-07-88   5:10a
 SETENV   EXE    10870   3-07-88   5:10a
 MTDYNA   DOC    43542   3-07-88   5:10a
         9 File(s)      4096 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 5 of 14)  -  Utilities 1

  Volume in drive A has no label
  Directory of  A:\

 ERROUT   EXE    10729   3-07-88   5:10a
 EXEHDR   EXE    29942   3-07-88   5:10a
 EXEMOD   EXE    12336   3-07-88   5:10a
 EXEPACK  EXE    14803   3-07-88   5:10a
 IMPLIB   EXE    30166   3-07-88   5:10a
 LIB      EXE    49661   3-07-88   5:10a
 LINK     EXE   117001   3-07-88   5:10a
 MAKE     EXE    38613   3-07-88   5:10a
 MOUSE    COM    14545   3-07-88   5:10a
 README   QC     30360   3-07-88   5:10a
        10 File(s)      8192 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 6 of 14)  -  Utilities 2

  Volume in drive A has no label
  Directory of  A:\

 EXT          <DIR>      3-07-88   5:10a
 INI          <DIR>      3-07-88   5:10a
 BIND     EXE    36946   3-07-88   5:10a
 CALLTREE EXE    31233   3-07-88   5:10a
 ECH      EXE    19351   3-07-88   5:10a
 EXP      EXE    32220   3-07-88   5:10a
 M        EXE    94821   3-07-88   5:10a
 MEGREP   EXE    31915   3-07-88   5:10a
 RM       EXE    24884   3-07-88   5:10a
 UNDEL    EXE    30046   3-07-88   5:10a
        10 File(s)      8192 bytes free

  Volume in drive A has no label
  Directory of  A:\EXT

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 EXT      DOC    15877   3-07-88   5:10a
 EXT      H       8730   3-07-88   5:10a
 EXTHDR   OBJ     1893   3-07-88   5:10a
 EXTHDRP  OBJ     2021   3-07-88   5:10a
 SKEL     C       2457   3-07-88   5:10a
 SKEL     DEF      211   3-07-88   5:10a
 WS       DLL     2609   3-07-88   5:10a
 WS       ZXT     2084   3-07-88   5:10a
        10 File(s)      8192 bytes free

  Volume in drive A has no label
  Directory of  A:\INI

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 BRIEF    INI     2094   3-07-88   5:10a
 EPSILON  INI      978   3-07-88   5:10a
 QUICK    INI     1058   3-07-88   5:10a
         5 File(s)      8192 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 7 of 14)  -  Libraries (Small and Medium Models)

  Volume in drive A has no label
  Directory of  A:\

 SLIBCR   LIB   132047   3-07-88   5:10a
 SLIBFA   LIB    46089   3-07-88   5:10a
 SVARSTCK OBJ      507   3-07-88   5:10a
 MLIBCR   LIB   133071   3-07-88   5:10a
 MLIBFA   LIB    46601   3-07-88   5:10a
 MVARSTCK OBJ      507   3-07-88   5:10a
         6 File(s)      1024 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 8 of 14)  -  Libraries (Large and Compact Models)

  Volume in drive A has no label
  Directory of  A:\

 CLIBCR   LIB   141301   3-07-88   5:10a
 CVARSTCK OBJ      487   3-07-88   5:10a
 LLIBCR   LIB   142837   3-07-88   5:10a
 LLIBFA   LIB    47625   3-07-88   5:10a
 LVARSTCK OBJ      487   3-07-88   5:10a
         5 File(s)     27648 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 9 of 14)  -  Floating-Point Libraries

  Volume in drive A has no label
  Directory of  A:\

 FORTRAN      <DIR>      3-07-88   5:10a
 EM       LIB    16921   3-07-88   5:10a
 87       LIB     4121   3-07-88   5:10a
 DOSCALLS LIB    29184   3-07-88   5:10a
 GRAPHICS LIB    59357   3-07-88   5:10a
 LIBH     LIB    14209   3-07-88   5:10a
 QUICKLIB OBJ     7917   3-07-88   5:10a
 SETARGV  OBJ      143   3-07-88   5:10a
 BINMODE  OBJ      127   3-07-88   5:10a
 SLIBFP   LIB    37281   3-07-88   5:10a
 MLIBFP   LIB    38305   3-07-88   5:10a
 CLIBFA   LIB    47113   3-07-88   5:10a
 CLIBFP   LIB    38307   3-07-88   5:10a
 LLIBFP   LIB    39331   3-07-88   5:10a
        14 File(s)     15360 bytes free

  Volume in drive A has no label
  Directory of  A:\FORTRAN

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 MDBGMSG  OBJ      540   3-07-88   5:10a
 LDBGMSG  OBJ      544   3-07-88   5:10a
 F4COMPAT BAT     3107   3-07-88   5:10a
         5 File(s)     15360 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 10 of 14)  -  Microsoft QuickC for MS-DOS

  Volume in drive A has no label
  Directory of  A:\

 QC       EXE   326656   3-07-88   5:10a
 QCL      EXE    28065   3-07-88   5:10a
 QCL      HLP     1456   3-07-88   5:10a
         3 File(s)      5120 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 11 of 14)  -  Microsoft CodeView for MS-DOS with Tutorial

  Volume in drive A has no label
  Directory of  A:\

 SAMPLE       <DIR>      3-07-88   5:10a
 CV       EXE   232896   3-07-88   5:10a
         2 File(s)      3072 bytes free

  Volume in drive A has no label
  Directory of  A:\SAMPLE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 CODEVIEW DOC    12928   3-07-88   5:10a
 ADAPT    BAT      133   3-07-88   5:10a
 DEMOB    BAT      254   3-07-88   5:10a
 LIFEB    BAT      336   3-07-88   5:10a
 LIFEEB   BAT      402   3-07-88   5:10a
 MENU     BAT      550   3-07-88   5:10a
 SAMPLE   BAT     1059   3-07-88   5:10a
 LIFE     C      14713   3-07-88   5:10a
 LIFE     EXE    33237   3-07-88   5:10a
 LIFE     R       5282   3-07-88   5:10a
 C_AUTO   CV      3571   3-07-88   5:10a
 E_AUTO   CV      6788   3-07-88   5:10a
 L_AUTO   CV     13272   3-07-88   5:10a
 M_AUTO   CV       733   3-07-88   5:10a
 Q_AUTO   CV        15   3-07-88   5:10a
 S_AUTO   CV      9091   3-07-88   5:10a
 RESPOND  COM      124   3-07-88   5:10a
 S1       @@@      230   3-07-88   5:10a
 S12      @@@      926   3-07-88   5:10a
 S13      @@@      368   3-07-88   5:10a
 S14      @@@      520   3-07-88   5:10a
 S2       @@@      752   3-07-88   5:10a
 S3       @@@      276   3-07-88   5:10a
 S4       @@@      354   3-07-88   5:10a
 S5       @@@      554   3-07-88   5:10a
 S6       @@@      432   3-07-88   5:10a
 S7       @@@      427   3-07-88   5:10a
 S8       @@@      479   3-07-88   5:10a
 S9       @@@      865   3-07-88   5:10a
        31 File(s)      3072 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 12 of 14)  -  Utilities 3

  Volume in drive A has no label
  Directory of  A:\

 SOURCE       <DIR>      3-07-88   5:10a
 ILINK    EXE    88929   3-07-88   5:10a
 LINK     EXE    65539   3-07-88   5:10a
 EXEC     EXE     9299   3-07-88   5:10a
 CV       HLP    21552   3-07-88   5:10a
 CVPACK   EXE    49400   3-07-88   5:10a
         6 File(s)     10240 bytes free

  Volume in drive A has no label
  Directory of  A:\SOURCE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SAMPLES  DOC     1760   3-07-88   5:10a
 CFLOW    C      44796   3-07-88   5:10a
 CFLOW    DOC     3764   3-07-88   5:10a
 DEMO     C        419   3-07-88   5:10a
 EMOEM    ASM    12129   3-07-88   5:10a
 GRDEMO   C      20907   3-07-88   5:10a
 SIEVE    C        788   3-07-88   5:10a
 SORTDEMO C      25399   3-07-88   5:10a
        10 File(s)     10240 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 13 of 14)  -  Microsoft Codeview for MS OS/2

  Volume in drive A has no label
  Directory of  A:\

 INCLMT       <DIR>      3-07-88   5:10a
 CVP      EXE   222505   3-07-88   5:10a
 CVP      HLP    21552   3-07-88   5:10a
 MEP      EXE    97063   3-07-88   5:10a
 CL       EXE    33900   3-07-88   5:10a
 CL       ERR     2276   3-07-88   5:10a
 CL       HLP     2169   3-07-88   5:10a
 C1       EXE   118643   3-07-88   5:10a
 C1L      EXE   158625   3-07-88   5:10a
 C1       ERR    14393   3-07-88   5:10a
 C23      ERR     3272   3-07-88   5:10a
 C2       EXE   222515   3-07-88   5:10a
 C3       EXE   129609   3-07-88   5:10a
 BINDC    BAT     2784   3-07-88   5:10a
 BINDC    CMD     2712   3-07-88   5:10a
        15 File(s)     41984 bytes free

  Volume in drive A has no label
  Directory of  A:\INCLMT

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SYS          <DIR>      3-07-88   5:10a
 ASSERT   H        703   3-07-88   5:10a
 BIOS     H       4866   3-07-88   5:10a
 CONIO    H       1024   3-07-88   5:10a
 CTYPE    H       2952   3-07-88   5:10a
 DIRECT   H        726   3-07-88   5:10a
 DOS      H       5917   3-07-88   5:10a
 ERRNO    H       1283   3-07-88   5:10a
 FCNTL    H       1255   3-07-88   5:10a
 FLOAT    H       6027   3-07-88   5:10a
 IO       H       1438   3-07-88   5:10a
 LIMITS   H       1553   3-07-88   5:10a
 MALLOC   H       3370   3-07-88   5:10a
 MATH     H       3709   3-07-88   5:10a
 MEMORY   H       1149   3-07-88   5:10a
 SEARCH   H       1137   3-07-88   5:10a
 SETJMP   H        915   3-07-88   5:10a
 SHARE    H        554   3-07-88   5:10a
 SIGNAL   H       1941   3-07-88   5:10a
 STDARG   H        622   3-07-88   5:10a
 STDDEF   H       1217   3-07-88   5:10a
 STDIO    H       5046   3-07-88   5:10a
 STDLIB   H       5335   3-07-88   5:10a
 STRING   H       2629   3-07-88   5:10a
 TIME     H       2693   3-07-88   5:10a
 VARARGS  H        650   3-07-88   5:10a
 PROCESS  H       2370   3-07-88   5:10a
 OS2      H        707   3-07-88   5:10a
 OS2DEF   H       5891   3-07-88   5:10a
 BSE      H       1139   3-07-88   5:10a
 BSEDOS   H      17730   3-07-88   5:10a
 BSEERR   H      20940   3-07-88   5:10a
 BSESUB   H      11512   3-07-88   5:10a
        35 File(s)     41984 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 14 of 14)  -  MS OS/2 Libraries

  Volume in drive A has no label
  Directory of  A:\

 EXAMPLE      <DIR>      3-07-88   5:10a
 SLIBCP   LIB   119999   3-07-88   5:10a
 MLIBCP   LIB   121535   3-07-88   5:10a
 CLIBCP   LIB   129257   3-07-88   5:10a
 LLIBCP   LIB   130793   3-07-88   5:10a
 APILMR   OBJ      105   3-07-88   5:10a
 API      LIB    81408   3-07-88   5:10a
 CDLLSUPP LIB     9475   3-07-88   5:10a
 LLIBCDLL LIB   178143   3-07-88   5:10a
 LLIBCMT  LIB   198913   3-07-88   5:10a
 CDLLOBJS LIB   203063   3-07-88   5:10a
 CDLLOBJS DEF     4397   3-07-88   5:10a
 CDLLOBJS CMD     2048   3-07-88   5:10a
 CRTEXE   OBJ     1089   3-07-88   5:10a
 CRTDLL   OBJ      577   3-07-88   5:10a
 CRTLIB   OBJ     1177   3-07-88   5:10a
        16 File(s)         0 bytes free

  Volume in drive A has no label
  Directory of  A:\EXAMPLE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 MHELLO   C       2990   3-07-88   5:10a
 MKMHELLO CMD      433   3-07-88   5:10a
 STMAIN   C        825   3-07-88   5:10a
 STMAIN   DEF       41   3-07-88   5:10a
 STDLL    C        393   3-07-88   5:10a
 STDLL    DEF      124   3-07-88   5:10a
 MKSTDLL  CMD      714   3-07-88   5:10a
 MTMAIN   C        735   3-07-88   5:10a
 MTMAIN   DEF       41   3-07-88   5:10a
 MTDLL    C        393   3-07-88   5:10a
 MTDLL    DEF      124   3-07-88   5:10a
 MKMTDLL  CMD     1587   3-07-88   5:10a
 SNAP     C      13083   3-07-88   5:10a
 MAKESNAP CMD     2148   3-07-88   5:10a
        16 File(s)         0 bytes free


 134. Getting the Address of a Function with FP_SEG and FP_OFF

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35295

 To get the address of a function, you may set a pointer to the
 function by using FP_SEG and FP_OFF to get the segment and offset
 for the function.

 The following sample code demonstrates this process:

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

 int foo();
 int (*foo_ptr)();
 unsigned int seg_val;
 unsigned int off_val;

 void main(void);
 void main(void)
 {
     /* set the pointer to the function */
     foo_ptr = foo;

     /* use FP_SEG() and FP_OFF() to get segment and offset */
     seg_val = FP_SEG(foo_ptr);
     off_val = FP_OFF(foo_ptr);
     printf("Segment is %d; Offset is %d\n", seg_val, off_val);
 }

 int foo()
     {}


 135. Differences between C signal() Function and DosSetSigHandler

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35297

 Question:

 I have some questions concerning signal handling in OS/2, and
 differences between the C run-time library signal() function and the
 OS/2 API routine DosSetSigHandler. What are the differences; what are
 the results of using these routines?

 Response:

 Under OS/2, the C run-time library signal() function has fewer options
 and different behavior than the OS/2 API DosSetSigHandler function.
 The signal() function is described in the next few paragraphs, then
 the features of DosSetSigHandler are explained.

 Features of the C Run-Time Library Signal() Function in OS/2

 The C run-time library signal() function only is for use in
 single-thread applications, and for floating-point exception handling
 in Dynamic Link Libraries.

 Using strictly C run-time functions, such as signal() and spawnlp(),
 signal handling in OS/2 is accomplished (or not, by default) by thread
 1 of each process. This behavior occurs whether the process was invoked
 from the operating system or was spawned by another process.

 As a result, while this process is running, a child process is
 unaffected by how its parent handles signals; if a signal is generated
 during the execution of the child, the child either handles it with
 its own signal handler, or if it was spawned with P_WAIT or P_NOWAIT,
 control returns to the parent process. (However, no control returns to
 the parent process's signal handler, which is unlike the
 DosSetSigHandler's effect.) Once the parent resumes execution, its
 signal handler once again will be in effect for any newly generated
 signals.

 For example, say a parent process sets up a signal handler, then
 spawns MAKE. While running MAKE, if a CTRL+C signal occurs, either the
 process spawned by MAKE such as the CL driver, or MAKE itself will be
 interrupted. If CL is interrupted by CTRL+C, it returns an error to
 MAKE and MAKE terminates. If MAKE itself is interrupted, it
 terminates. In either case, control will be returned to the parent
 process after the point where it spawned MAKE, and the parent resumes
 execution. The parent's signal handler will handle signals generated
 after it starts executing again, but none of the signals generated by
 the child are kept by the system and returned to the parent.

 If both the parent and child have no signal handler, if the child is
 spawned with P_WAIT or P_NOWAIT and it is terminated without hanging
 the system, then control goes back to the parent. The parent continues
 executing until it is terminated.

 Features of OS/2's DosSetSigHandler

 The OS/2 API routine DosSetSigHandler has more options than the C
 run-time library signal() function. A child process will inherit
 (i.e., use) the parent's signal handler, or the closest ancestor's
 defined signal handler if its immediate parent didn't create one.

 If the parent called DosSetSigHandler to handle CTRL+C with Action = 0
 (install the system default action, in this case to terminate the
 process), a CTRL+C issued in the parent or child will use the parent's
 handler. If the CTRL+C occurred in the child, the child will be
 terminated (by default) when the parent's signal handler is called.
 The parent will resume execution after its signal handler function is
 completed in a similar manner to DOS. However, the child may install
 its own signal handler rather than using the parent's.

 If you use Action = 2 (install the specified signal handler
 for the given signal) for handling CTRL+C in the parent process,
 hitting CTRL+C in its child causes the child to pause while the
 handler is executed; however, the child won't terminate. For Action =
 1 (ignore signal) in a DosSetSigHandler call by the parent for CTRL+C,
 CTRL+C is ignored in the child as well as the parent.

 If neither parent nor child sets up a signal handler, CTRL+C will kill
 them all regardless of which process gets the CTRL+C. This action
 occurs because signal handlers are being inherited, and signals are
 either handled in the current process if it has a handler, or
 effectively passed back up the process subtree (from child to parent)
 until a process is reached that has a CTRL+C signal handler.

 Because the default action for CTRL+C is to terminate the process, a
 process without a CTRL+C handler gets terminated, and the CTRL+C
 signal effectively gets passed up to its parent. If the parent doesn't
 have a CTRL+C handler, it terminates and passes control to its parent.
 If no one set up a signal handler, the original parent at the root of
 the process subtree handles the signal, and the default action is to
 return to the system.

 Some precautions for signal handling are recommended. After setting up
 a signal handler, avoid making system calls from thread 1, especially
 time-consuming calls such as waiting for keyboard input or some other
 event. If OS/2 is executing code for a system call at Ring 0, it
 cannot run a signal handler at Ring 3. Instead, executing the system
 code is completed, or aborted if it is a time-consuming call (which
 could result in incomplete I/O), and then the signal is handled.

 Another particularly bad scenario is if thread 1 blocks a critical
 section of code with a RAM semaphore, is interrupted and handles a
 signal, and then the signal handler resumes execution elsewhere so
 that the RAM semaphore is not cleared and the critical section remains
 blocked. If thread 1 must run critical sections of code, it should
 call DosHoldSignal to disable the signal prior to entering the
 critical section.


 136. Using PRINT SCREEN Key to Print CGA Graphics

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 27-OCT-1988    ArticleIdent: Q35303

 To print graphics generated by a C program using the PRINT SCREEN key,
 you must first install GRAPHICS.COM (supplied by your DOS). This
 process only will work with the CGA modes. Hercules, EGA, and VGA modes
 will not print with this method; you must obtain a third party, public
 domain, or shareware program to print graphics from these modes.

 In the DOS environment, PRINT SCREEN prints any text screen to an
 attached printer hooked to PRN. This function isn't able to interpret
 a graphic screen to the printer because a graphic screen is defined
 and produced differently than a text screen.

 A unit of area is defined by a pixel rather than a character. (This
 can be noticed by the way a text screen is described "80 columns by 25
 rows" as opposed to a graphics screen "640 pixels by 200 pixels.")

 DOS supplies a TSR that allows the PRINT SCREEN to interpret a graphic
 screen. This is called GRAPHICS.COM. When it is installed, it will
 interpret a CGA graphic screen to a printer attached to PRN. This
 utility must be installed before running a C program that draws a
 graphic screen in the CGA modes, i.e., the program must have specified
 a _setvideomode to _MRES4COLOR, _MRESNOCOLOR, or _HRESBW. Any of the
 other video modes will require some other utility to interpret the
 screen for the printer.

 It also should be noted that GRAPHICS.COM was written to write to an
 IBM Personal Graphics or IBM Personal Color Printer. It may be
 necessary on some other printers to set some switch settings, if
 available, to emulate either of these printers. The printer manual for
 the specific printer should be consulted in these cases.


 137. Libraries Created by IMPLIB Are Different than those from LIB

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S880908-4
 Last Modified: 26-SEP-1988    ArticleIdent: Q35539

 The only similarity between Libraries created by IMPLIB and libraries
 created by LIB is the filename extension ".LIB".

 Libraries created by IMPLIB only contain the names of functions and
 modules to satisfy the linker. The actual code is brought in later by
 loading Dynamic Link Libraries (DLL).

 Regular libraries contain all the code for the functions. One or more
 functions are contained in a module (e.g. object file). The code for
 the entire module containing a called function is statically linked
 into the executable file.

 You cannot use LIB to get any information about libraries created by
 IMPLIB. You cannot combine IMPLIB and LIB libraries. To see what
 modules are in an IMPLIB library, use the type command to display the
 .LIB file; it is a text file.


 138. Example Incorrect for the write() Function

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 26-SEP-1988    ArticleIdent: Q35545

 The example for the write() function on Page 641 of the "Microsoft C
 5.1 Optimizing Compiler Run-Time Library Reference" is incorrect; it
 causes OS/2 to generate a General Protection (GP) fault.

 This example fails in OS/2 because it attempts to write 60,000 bytes
 from a buffer of size 6,000 bytes. In effect, it is attempting to read
 beyond the buffer of size 6000, causing the GP fault. In DOS, this
 error may go undetected, but an extra 54,000 bytes of random garbage
 may be written to the file.

 To work around this problem, change the number of bytes to write from
 60,000 bytes to 6000 bytes.


 139. The Total Bytes in MAP File Differs from Load Size in EXEMOD

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S880908-4
 Last Modified: 19-SEP-1988    ArticleIdent: Q35628

 Question:

 When I run EXEMOD on my executable file and look at the minimum load
 size, it always is greater than or equal to the size of my executable
 listed in my MAP file. Why?

 Response:

 EXEMOD reflects the minimum load size of a program that is rounded up
 to the 16-byte paragraph level. As a result, the minimum load size
 will be up to 15-bytes larger than the size of the program indicated
 in your MAP file.


 140. Process "exit" Values Must Lie Between 0 and 255 Inclusive

 Product Version(s): 4.00 5.00 5.10 | 4.00 5.00 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 29-DEC-1988    ArticleIdent: Q39469

 Problem:

 I am testing the exit value of a process. This value is not accurate
 for values above 255.

 Response:

 Exit values must range between 0 and 255 inclusive. This limitation
 has its roots in the "terminate with return code" interrupt function
 (interrupt 21H, function 4CH). Using this function, exit values are
 specified in the AL register. The AL register allows values from 0 to
 255. All Microsoft C programs under DOS terminate using this function.

 Under OS/2, the same limitation exists. Although OS/2 does not use
 interrupts as DOS does, the reasoning is analogous.

 Exit values can be tested using the functions spawnl, spawnle, spawnlp,
 spawnlpe, spawnv, spawnve, spawnvp, and spawnvpe. Also, batch files may
 test exit values using the IF ERRORLEVEL statement.


 141. Incorrect Function Declaration

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr h_fortran h_masm s_pascal
 Last Modified: 23-SEP-1988    ArticleIdent: Q35730

 On Page 66 of the "Microsoft Mixed-Language Programmer's Guide"
 provided with C Versions 5.00 and 5.10, FORTRAN Versions 4.0x and
 4.10, MASM Versions 5.00 and 5.10, and Pascal Version 4.00, the
 example program given in section 5.4.2 "Calling C from Pascal --
 Function Call" is incorrect. If the Pascal source code in the manual
 is compiled, the following errors will occur on the function
 declaration line:

                    function Fact (n : integer)  [C]; extern;
                                               ^ ^          ^
  Warning 173  Insert:     ____________________| |          |
     (the compiler is expecting a colon)         |          |
                                                 |          |
  315  Type unknown or invalid assumed integer __|          |
       Begin Skip                                           |
                                                            |
  187  End Skip    _________________________________________|

 The function declaration in the Pascal program is missing its return
 value. If the line is corrected to look as follows the program works
 properly:

 function Fact (n : integer) : integer  [C]; extern;


 142. Directory Listing for C 5.10 Distribution Disks (3.5-Inch)

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 23-SEP-1988    ArticleIdent: Q35753

 The following is a listing of the directories for each of the
 Microsoft C Version 5.10 Optimizing Compiler distribution disks
 (3.5-inch disks). The information is the resulting output when the DOS
 command "dir" is performed on each directory and subdirectory.

 A line of colons (:::::) separates each disk, and subdirectories are
 listed below their parent directory. The first line of each disk
 description is the name of the disk as it is printed on the label;
 however, information in parentheses is supplemental and not contained
 on the disk label.

 :::::::::::::::::::::::::::::::::::::::
 C 5.10 distribution disks, 3.5-inch disks
 :::::::::::::::::::::::::::::::::::::::

 (Disk 1 of 10)  -  Setup, Include Files, and Startup Source Code

  Volume in drive B has no label.
  Directory of B:\

 STARTUP      <DIR>      3-07-88   5:10a
 INCLUDE      <DIR>      3-07-88   5:10a
 README   DOC    63358   3-07-88   5:10a
 UTILITY  DOC    17794   3-07-88   5:10a
 PACKING  LST    11504   3-07-88   5:10a
 CL       EXE    31329   3-07-88   5:10a
 CL       HLP     2169   3-07-88   5:10a
 CL       ERR     2276   3-07-88   5:10a
 C1       EXE   114521   3-07-88   5:10a
 C23      ERR     3272   3-07-88   5:10a
 SETUP    EXE    93033   3-07-88   5:10a
 SETUP    DOC    15179   3-07-88   5:10a
      12 File(s)   37888 bytes free

  Volume in drive B has no label.
  Directory of B:\INCLUDE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SYS          <DIR>      3-07-88   5:10a
 ASSERT   H        699   3-07-88   5:10a
 BIOS     H       4866   3-07-88   5:10a
 CONIO    H        952   3-07-88   5:10a
 CTYPE    H       2465   3-07-88   5:10a
 DIRECT   H        690   3-07-88   5:10a
 DOS      H       5917   3-07-88   5:10a
 ERRNO    H       1283   3-07-88   5:10a
 FCNTL    H       1255   3-07-88   5:10a
 FLOAT    H       6011   3-07-88   5:10a
 GRAPH    H       7480   3-07-88   5:10a
 IO       H       1294   3-07-88   5:10a
 LIMITS   H       1553   3-07-88   5:10a
 MALLOC   H       3097   3-07-88   5:10a
 MATH     H       3324   3-07-88   5:10a
 MEMORY   H       1065   3-07-88   5:10a
 SEARCH   H       1025   3-07-88   5:10a
 SETJMP   H        907   3-07-88   5:10a
 SHARE    H        554   3-07-88   5:10a
 SIGNAL   H       1905   3-07-88   5:10a
 STDARG   H        614   3-07-88   5:10a
 STDDEF   H       1100   3-07-88   5:10a
 STDIO    H       4500   3-07-88   5:10a
 STDLIB   H       4900   3-07-88   5:10a
 STRING   H       2209   3-07-88   5:10a
 TIME     H       2342   3-07-88   5:10a
 VARARGS  H        642   3-07-88   5:10a
 PROCESS  H       1988   3-07-88   5:10a
 OS2      H        707   3-07-88   5:10a
 OS2DEF   H       5891   3-07-88   5:10a
 BSE      H       1139   3-07-88   5:10a
 BSEDOS   H      17730   3-07-88   5:10a
 BSEERR   H      20940   3-07-88   5:10a
 BSESUB   H      11512   3-07-88   5:10a
      36 File(s)   37888 bytes free

  Volume in drive B has no label.
  Directory of B:\INCLUDE\SYS

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 LOCKING  H        573   3-07-88   5:10a
 STAT     H       1497   3-07-88   5:10a
 TIMEB    H        844   3-07-88   5:10a
 TYPES    H        849   3-07-88   5:10a
 UTIME    H       1061   3-07-88   5:10a
      7 File(s)   37888 bytes free

  Volume in drive B has no label.
  Directory of B:\STARTUP

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 DOS          <DIR>      3-07-88   5:10a
 OS2          <DIR>      3-07-88   5:10a
 FILE2    H       1027   3-07-88   5:10a
 MSDOS    H       6849   3-07-88   5:10a
 REGISTER H        922   3-07-88   5:10a
 STARTUP  BAT     1663   3-07-88   5:10a
 MAKEFILE         4148   3-07-88   5:10a
 CHKSTK   ASM     2044   3-07-88   5:10a
 CHKSUM   ASM     3524   3-07-88   5:10a
 NULBODY  C         13   3-07-88   5:10a
 README   DOC     3199   3-07-88   5:10a
 MSDOS    INC     6181   3-07-88   5:10a
 CMACROS  INC    12066   3-07-88   5:10a
 BRKCTL   INC      784   3-07-88   5:10a
 VERSION  INC      503   3-07-88   5:10a
 WILD     C       7182   3-07-88   5:10a
 _FILE    C       1691   3-07-88   5:10a
 CRT0FP   ASM     2223   3-07-88   5:10a
 FMSGHDR  ASM     2429   3-07-88   5:10a
 SETARGV  ASM      971   3-07-88   5:10a
      22 File(s)   37888 bytes free

  Volume in drive B has no label.
  Directory of B:\STARTUP\DOS

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 NULBODY  LNK      149   3-07-88   5:10a
 STDENVP  ASM     3780   3-07-88   5:10a
 CRT0     ASM     7612   3-07-88   5:10a
 CRT0DAT  ASM    14175   3-07-88   5:10a
 CRT0MSG  ASM     2840   3-07-88   5:10a
 EXECMSG  ASM     1337   3-07-88   5:10a
 NMSGHDR  ASM     3010   3-07-88   5:10a
 STDALLOC ASM     2825   3-07-88   5:10a
 STDARGV  ASM    13852   3-07-88   5:10a
      11 File(s)   37888 bytes free

  Volume in drive B has no label.
  Directory of B:\STARTUP\OS2

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 NULBODY  LNK      168   3-07-88   5:10a
 CRT0     ASM    10312   3-07-88   5:10a
 STDENVP  ASM     5362   3-07-88   5:10a
 CRT0DAT  ASM    10496   3-07-88   5:10a
 CRT0MSG  ASM     2891   3-07-88   5:10a
 EXECMSG  ASM     2231   3-07-88   5:10a
 NMSGHDR  ASM     3486   3-07-88   5:10a
 STDALLOC ASM     3245   3-07-88   5:10a
 STDARGV  ASM    13623   3-07-88   5:10a
      11 File(s)   37888 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 2 of 10)  -  Compiler

  Volume in drive B has no label.
  Directory of B:\

 PATCH        <DIR>      3-07-88   5:10a
 C1       ERR    14393   3-07-88   5:10a
 C1L      EXE   149303   3-07-88   5:10a
 C3       EXE   125221   3-07-88   5:10a
 ERRMSG   DOC    17293   3-07-88   5:10a
 FPEXCEPT DOC    16254   3-07-88   5:10a
 FIXSHIFT COM      688   3-07-88   5:10a
 MSHERC   COM     6749   3-07-88   5:10a
 QLIB     DOC    12047   3-07-88   5:10a
 QLIB     EXE    24557   3-07-88   5:10a
 QLIB     INI     2905   3-07-88   5:10a
 C2       EXE   202919   3-07-88   5:10a
 QC       HLP    50649   3-07-88   5:10a
 SETENV   EXE    10870   3-07-88   5:10a
 MTDYNA   DOC    43542   3-07-88   5:10a
      15 File(s)   24576 bytes free

  Volume in drive B has no label.
  Directory of B:\PATCH

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 PATCH87  DOC     3937   3-07-88   5:10a
 PATCH87  EXE     4206   3-07-88   5:10a
 SETRHS   EXE      543   3-07-88   5:10a
 RMRHS    EXE      543   3-07-88   5:10a
 STKPAT   BAT       94   3-07-88   5:10a
 STKPAT   SCR       30   3-07-88   5:10a
 PTRACE87 PAT      188   3-07-88   5:10a
 PATCH320 DOC     2169   3-07-88   5:10a
 OS2PATCH EXE     1069   3-07-88   5:10a
 OS2PATCH DOC     1401   3-07-88   5:10a
      12 File(s)   24576 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 3 of 10)  -  Utilities

  Volume in drive B has no label.
  Directory of B:\

 EXT          <DIR>      3-07-88   5:10a
 INI          <DIR>      3-07-88   5:10a
 ERROUT   EXE    10729   3-07-88   5:10a
 EXEHDR   EXE    29942   3-07-88   5:10a
 EXEMOD   EXE    12336   3-07-88   5:10a
 EXEPACK  EXE    14803   3-07-88   5:10a
 IMPLIB   EXE    30166   3-07-88   5:10a
 LIB      EXE    49661   3-07-88   5:10a
 LINK     EXE   117001   3-07-88   5:10a
 MAKE     EXE    38613   3-07-88   5:10a
 MOUSE    COM    14545   3-07-88   5:10a
 README   QC     30351   3-07-88   5:10a
 BIND     EXE    36946   3-07-88   5:10a
 CALLTREE EXE    31233   3-07-88   5:10a
 ECH      EXE    19351   3-07-88   5:10a
 EXP      EXE    32220   3-07-88   5:10a
 M        EXE    94821   3-07-88   5:10a
 MEGREP   EXE    31915   3-07-88   5:10a
 RM       EXE    24884   3-07-88   5:10a
 UNDEL    EXE    30046   3-07-88   5:10a
      20 File(s)   21504 bytes free

  Volume in drive B has no label.
  Directory of B:\EXT

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 EXT      DOC    15877   3-07-88   5:10a
 EXT      H       8730   3-07-88   5:10a
 EXTHDR   OBJ     1893   3-07-88   5:10a
 EXTHDRP  OBJ     2021   3-07-88   5:10a
 SKEL     C       2457   3-07-88   5:10a
 SKEL     DEF      211   3-07-88   5:10a
 WS       DLL     2609   3-07-88   5:10a
 WS       ZXT     2084   3-07-88   5:10a
      10 File(s)   21504 bytes free

  Volume in drive B has no label.
  Directory of B:\INI

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 BRIEF    INI     2094   3-07-88   5:10a
 EPSILON  INI      978   3-07-88   5:10a
 QUICK    INI     1058   3-07-88   5:10a
      5 File(s)   21504 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 4 of 10)  -  Libraries (Small, Medium, Compact, and Large
                               Models)

  Volume in drive B has no label.
  Directory of B:\

 SLIBCR   LIB   132047   3-07-88   5:10a
 SLIBFA   LIB    46089   3-07-88   5:10a
 SVARSTCK OBJ      507   3-07-88   5:10a
 MLIBCR   LIB   133071   3-07-88   5:10a
 MLIBFA   LIB    46601   3-07-88   5:10a
 MVARSTCK OBJ      507   3-07-88   5:10a
 CLIBCR   LIB   141301   3-07-88   5:10a
 CVARSTCK OBJ      487   3-07-88   5:10a
 LLIBCR   LIB   142837   3-07-88   5:10a
 LLIBFA   LIB    47625   3-07-88   5:10a
 LVARSTCK OBJ      487   3-07-88   5:10a
      11 File(s)   33792 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 5 of 10)  -  Floating-Point Libraries and Microsoft QuickC for
                    MS-DOS

  Volume in drive B has no label.
  Directory of B:\

 FORTRAN      <DIR>      3-07-88   5:10a
 EM       LIB    16921   3-07-88   5:10a
 87       LIB     4121   3-07-88   5:10a
 DOSCALLS LIB    29184   3-07-88   5:10a
 GRAPHICS LIB    59357   3-07-88   5:10a
 LIBH     LIB    14209   3-07-88   5:10a
 QUICKLIB OBJ     7917   3-07-88   5:10a
 SETARGV  OBJ      143   3-07-88   5:10a
 BINMODE  OBJ      127   3-07-88   5:10a
 SLIBFP   LIB    37281   3-07-88   5:10a
 MLIBFP   LIB    38305   3-07-88   5:10a
 CLIBFA   LIB    47113   3-07-88   5:10a
 CLIBFP   LIB    38307   3-07-88   5:10a
 LLIBFP   LIB    39331   3-07-88   5:10a
 QC       EXE   326656   3-07-88   5:10a
 QCL      EXE    28065   3-07-88   5:10a
 QCL      HLP     1456   3-07-88   5:10a
      17 File(s)   25600 bytes free

  Volume in drive B has no label.
  Directory of B:\FORTRAN

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 MDBGMSG  OBJ      540   3-07-88   5:10a
 LDBGMSG  OBJ      544   3-07-88   5:10a
 F4COMPAT BAT     3107   3-07-88   5:10a
      5 File(s)   25600 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 6 of 10)  -  Microsoft CodeView for MS-DOS with Tutorial

  Volume in drive B has no label.
  Directory of B:\

 SAMPLE       <DIR>      3-07-88   5:10a
 SOURCE       <DIR>      3-07-88   5:10a
 CV       EXE   232896   3-07-88   5:10a
 ILINK    EXE    88929   3-07-88   5:10a
 LINK     EXE    65539   3-07-88   5:10a
 EXEC     EXE     9299   3-07-88   5:10a
 CV       HLP    21552   3-07-88   5:10a
 CVPACK   EXE    49400   3-07-88   5:10a
      8 File(s)   18432 bytes free

  Volume in drive B has no label.
  Directory of B:\SAMPLE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 CODEVIEW DOC    12928   3-07-88   5:10a
 ADAPT    BAT      133   3-07-88   5:10a
 DEMOB    BAT      254   3-07-88   5:10a
 LIFEB    BAT      336   3-07-88   5:10a
 LIFEEB   BAT      402   3-07-88   5:10a
 MENU     BAT      550   3-07-88   5:10a
 SAMPLE   BAT     1059   3-07-88   5:10a
 LIFE     C      14713   3-07-88   5:10a
 LIFE     EXE    33237   3-07-88   5:10a
 LIFE     R       5282   3-07-88   5:10a
 C_AUTO   CV      3571   3-07-88   5:10a
 E_AUTO   CV      6788   3-07-88   5:10a
 L_AUTO   CV     13272   3-07-88   5:10a
 M_AUTO   CV       733   3-07-88   5:10a
 Q_AUTO   CV        15   3-07-88   5:10a
 S_AUTO   CV      9091   3-07-88   5:10a
 RESPOND  COM      124   3-07-88   5:10a
 S1       @@@      230   3-07-88   5:10a
 S12      @@@      926   3-07-88   5:10a
 S13      @@@      368   3-07-88   5:10a
 S14      @@@      520   3-07-88   5:10a
 S2       @@@      752   3-07-88   5:10a
 S3       @@@      276   3-07-88   5:10a
 S4       @@@      354   3-07-88   5:10a
 S5       @@@      554   3-07-88   5:10a
 S6       @@@      432   3-07-88   5:10a
 S7       @@@      427   3-07-88   5:10a
 S8       @@@      479   3-07-88   5:10a
 S9       @@@      865   3-07-88   5:10a
      31 File(s)   18432 bytes free

  Volume in drive B has no label.
  Directory of B:\SOURCE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SAMPLES  DOC     1760   3-07-88   5:10a
 CFLOW    C      44796   3-07-88   5:10a
 CFLOW    DOC     3764   3-07-88   5:10a
 DEMO     C        419   3-07-88   5:10a
 EMOEM    ASM    12129   3-07-88   5:10a
 GRDEMO   C      20907   3-07-88   5:10a
 SIEVE    C        788   3-07-88   5:10a
 SORTDEMO C      25399   3-07-88   5:10a
      10 File(s)   18432 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 7 of 10)  -  MS OS/2 Compiler

  Volume in drive B has no label.
  Directory of B:\

 CL       EXE    33900   3-07-88   5:10a
 CL       ERR     2276   3-07-88   5:10a
 CL       HLP     2169   3-07-88   5:10a
 C1       EXE   118643   3-07-88   5:10a
 C1L      EXE   158625   3-07-88   5:10a
 C1       ERR    14393   3-07-88   5:10a
 C23      ERR     3272   3-07-88   5:10a
 C2       EXE   222515   3-07-88   5:10a
 C3       EXE   129609   3-07-88   5:10a
 BINDC    BAT     2784   3-07-88   5:10a
 BINDC    CMD     2712   3-07-88   5:10a
      11 File(s)   32768 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 8 of 10)  -  Microsoft CodeView for MS OS/2, Microsoft Editor,
                    and Include Files

  Volume in drive B has no label.
  Directory of B:\

 INCLMT       <DIR>      3-07-88   5:10a
 CVP      EXE   222505   3-07-88   5:10a
 CVP      HLP    21552   3-07-88   5:10a
 MEP      EXE    97063   3-07-88   5:10a
      4 File(s)   242688 bytes free

  Volume in drive B has no label.
  Directory of B:\INCLMT

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 SYS          <DIR>      3-07-88   5:10a
 ASSERT   H        703   3-07-88   5:10a
 BIOS     H       4866   3-07-88   5:10a
 CONIO    H       1024   3-07-88   5:10a
 CTYPE    H       2952   3-07-88   5:10a
 DIRECT   H        726   3-07-88   5:10a
 DOS      H       5917   3-07-88   5:10a
 ERRNO    H       1283   3-07-88   5:10a
 FCNTL    H       1255   3-07-88   5:10a
 FLOAT    H       6027   3-07-88   5:10a
 IO       H       1438   3-07-88   5:10a
 LIMITS   H       1553   3-07-88   5:10a
 MALLOC   H       3370   3-07-88   5:10a
 MATH     H       3709   3-07-88   5:10a
 MEMORY   H       1149   3-07-88   5:10a
 SEARCH   H       1137   3-07-88   5:10a
 SETJMP   H        915   3-07-88   5:10a
 SHARE    H        554   3-07-88   5:10a
 SIGNAL   H       1941   3-07-88   5:10a
 STDARG   H        622   3-07-88   5:10a
 STDDEF   H       1217   3-07-88   5:10a
 STDIO    H       5046   3-07-88   5:10a
 STDLIB   H       5335   3-07-88   5:10a
 STRING   H       2629   3-07-88   5:10a
 TIME     H       2693   3-07-88   5:10a
 VARARGS  H        650   3-07-88   5:10a
 PROCESS  H       2370   3-07-88   5:10a
 OS2      H        707   3-07-88   5:10a
 OS2DEF   H       5891   3-07-88   5:10a
 BSE      H       1139   3-07-88   5:10a
 BSEDOS   H      17730   3-07-88   5:10a
 BSEERR   H      20940   3-07-88   5:10a
 BSESUB   H      11512   3-07-88   5:10a
      35 File(s)   242688 bytes free

  Volume in drive B has no label.
  Directory of B:\INCLMT\SYS

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 LOCKING  H        573   3-07-88   5:10a
 STAT     H       1517   3-07-88   5:10a
 TIMEB    H        852   3-07-88   5:10a
 TYPES    H        849   3-07-88   5:10a
 UTIME    H       1073   3-07-88   5:10a
      7 File(s)   242688 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 9 of 10)  -  MS OS/2 Libraries 1

  Volume in drive B has no label.
  Directory of B:\

 SLIBCP   LIB   119999   3-07-88   5:10a
 MLIBCP   LIB   121535   3-07-88   5:10a
 CLIBCP   LIB   129257   3-07-88   5:10a
 LLIBCP   LIB   130793   3-07-88   5:10a
 APILMR   OBJ      105   3-07-88   5:10a
 API      LIB    81408   3-07-88   5:10a
      6 File(s)   143360 bytes free

 :::::::::::::::::::::::::::::::::::::::

 (Disk 10 of 10)  -  MS OS/2 Libraries 2

  Volume in drive B has no label.
  Directory of B:\

 EXAMPLE      <DIR>      3-07-88   5:10a
 CDLLSUPP LIB     9475   3-07-88   5:10a
 LLIBCDLL LIB   178143   3-07-88   5:10a
 LLIBCMT  LIB   198913   3-07-88   5:10a
 CDLLOBJS LIB   203063   3-07-88   5:10a
 CDLLOBJS DEF     4397   3-07-88   5:10a
 CDLLOBJS CMD     2048   3-07-88   5:10a
 CRTEXE   OBJ     1089   3-07-88   5:10a
 CRTDLL   OBJ      577   3-07-88   5:10a
 CRTLIB   OBJ     1177   3-07-88   5:10a
      10 File(s)   93184 bytes free

  Volume in drive B has no label.
  Directory of B:\EXAMPLE

 .            <DIR>      3-07-88   5:10a
 ..           <DIR>      3-07-88   5:10a
 MHELLO   C       2990   3-07-88   5:10a
 MKMHELLO CMD      433   3-07-88   5:10a
 STMAIN   C        825   3-07-88   5:10a
 STMAIN   DEF       41   3-07-88   5:10a
 STDLL    C        393   3-07-88   5:10a
 STDLL    DEF      124   3-07-88   5:10a
 MKSTDLL  CMD      714   3-07-88   5:10a
 MTMAIN   C        735   3-07-88   5:10a
 MTMAIN   DEF       41   3-07-88   5:10a
 MTDLL    C        393   3-07-88   5:10a
 MTDLL    DEF      124   3-07-88   5:10a
 MKMTDLL  CMD     1587   3-07-88   5:10a
 SNAP     C      13083   3-07-88   5:10a
 MAKESNAP CMD     2148   3-07-88   5:10a
      16 File(s)   93184 bytes free


 143. Quick Reference Documentation Error with _setbkcolor

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 23-SEP-1988    ArticleIdent: Q35805

 In the Library Routines section of the C Versions 5.00 and 5.10
 "Microsoft Quick Reference Guide," the function _setbkcolor has the
 incorrect argument type. Instead of a short type argument, the
 argument should be a long type.


 144. Sample Pascal Program Documentation Error: function Fact

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | h_masm S_PASCAL h_fortran
 Last Modified: 23-SEP-1988    ArticleIdent: Q35812

 In the Microsoft Mixed-Language Programming Guide in section 5.4.2 on
 Page 64, the Pascal function declaration is stated as follows:

 function Fact (n: integer) [C]; extern;

 The Pascal function declaration should be the following:

 function Fact (n: integer) : integer [C]; extern;



 145. Source Not Available for MS Binary to IEEE Conversion

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER   |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35988

 The following functions are not included in the C Run-Time Library
 Source Routines:

 dieeetomsbin
 dmsbintoieee
 fieeetomsbin
 fmsbintoieee

 These functions are incorrectly listed in a flier called "Microsoft C
 Run-Time Library Source Runtime" as included in the product.


 146. C: Automatic Casting from Near Pointer to Far Pointer

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q43486

 In Microsoft C, the automatic type casting from a near pointer to a
 far pointer that is performed by the compiler will make the segment
 address of the resulting pointer the same as that of DGroup. In those
 cases, no explicit type casting is needed.

 Two of the cases of the automatic casting are shown in the following
 sample program:

 #include <malloc.h>

 void foo (char far *) ;
 void main (void)
 {
 char far *lpChar ;
 char * npChar ;
 lpChar = malloc( 100 );   /* malloc is mapped to _nmalloc,
                           ** and returns near pointer, automatic type
                           ** casting is performed with assignment */

 foo( npChar ) ;           /* npChar is converted to a far pointer
                           ** with the segment address to be DS */
 }

 void foo (char far * p)
 {
 }


 147. IEEE Floating-Point Representation and MS languages

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm b_quickbas
 Last Modified:  8-MAR-1989    ArticleIdent: Q36068

 The following information discusses how real*4 (single precision) and
 real*8 (double precision) numbers are stored internally by Microsoft
 languages that use the IEEE floating-point format. The Microsoft
 Binary Format (MBF) for floating-point storage, which is used by the
 BASIC interpreter for MS-DOS and by QuickBASIC up through Versions
 3.x, is NOT discussed in this article.

 This information applies to all versions of Microsoft languages that
 use IEEE floating-point format, including the following:

 1. C Versions 3.00, 4.00, 5.00, and 5.10

 2. FORTRAN Versions 3.1x, 3.20, 3.30, 4.0x, and 4.10

 3. MASM Versions 1.25, 1.27, 3.0x, 4.00, 5.00, and 5.10

 4. Pascal Versions 3.1x, 3.20, 3.30, 3.31, 3.32, and 4.00

 5. The coprocessor version of QuickBASIC Version 3.00 (QB87.EXE), and
    QuickBASIC Versions 4.00, 4.00b, and 4.50

 There are three internal varieties of real numbers. Microsoft is
 consistent with the IEEE numeric standards. Real*4 and real*8 are used
 in all of our languages. Real*10 is used only with MASM. Real*10 is
 also what any 8087, 80287, or 80387 coprocessor and the emulator math
 package use when performing floating-point calculations.

 In FORTRAN, real*4 is declared using the words "REAL" or "REAL*4."
 The words "DOUBLE PRECISION" or "REAL*8" are used to declare a real*8
 number.

 In C, real*4 is declared using the word "float." Real*8 is declared
 using the word "double" or "long double."

 In Pascal, real*4 is declared using the word "real4," and real*8 is
 declared using the word "real8."  The word "real" defaults to real*4,
 but this can be changed to real*8 with the $real:8 metacommand.

 In MASM, real*4 is declared with the "DD" directive, real*8 is
 declared with the "DQ" directive, and real*10 is declared with the
 "DT" directive.

 In QuickBASIC, the default variable type is real*4. Variables that
 have an exclamation point ("!") as their last character are also
 real*4. Variables that have a cross-hatch (also called pound-sign,
 "#" as the last character of its name are double precision (real*8).
 The DEFSNG and DEFDBL statements can be used to declare that variables
 whose names begin with certain letters and are of a certain type.
 These types can also be declared with the keywords SINGLE and DOUBLE.

 The values are stored as follows:

 real*4  sign bit, 8  bit exponent, 23 bit mantissa
 real*8  sign bit, 11 bit exponent, 52 bit mantissa
 real*10 sign bit, 15 bit exponent, 64 bit mantissa

 In real*4 and real*8 formats, there is an assumed leading one in the
 mantissa that is not stored in memory, so the mantissas are actually
 24 or 53 bits, even though only 23 or 52 bits are stored.  The
 real*10 format stores actually stores this bit.

 The exponents are biased by half of their possible value. This means
 you subtract this bias from the stored exponent to get the actual
 exponent. If the stored exponent is less than the bias, it is actually
 a negative exponent.

 The exponents are biased as follows:

 8-bit  (real*4)  exponents are biased by 127
 11-bit (real*8)  exponents are biased by 1023
 15-bit (real*10) exponents are biased by 16383

 These exponents are not powers of ten; they are powers of two, i.e.,
 8-bit stored exponents can be up to 127. 2**127 is roughly equivalent
 to 10**38, which is the actual limit of real*4.

 The mantissa is stored as a binary fraction of the form 1.XXX... .
 This fraction has a value greater than or equal to 1 and less than 2.
 Note that real numbers are always stored in normalized form, i.e., the
 mantissa is left-shifted such that the high-order bit of the mantissa
 is always one. Because this bit is always one, it is assumed (not
 stored) in the real*4 and real*8 formats. The binary (not decimal)
 point is assumed to be just to the right of the leading one.

 The format, then, for the various sizes is as follows:

            BYTE 1    BYTE 2    BYTE 3    BYTE 4   ...  BYTE n
 real*4    SXXX XXXX XMMM MMMM MMMM MMMM MMMM MMMM
 real*8    SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM
 real*10   SXXX XXXX XXXX XXXX 1MMM MMMM MMMM MMMM ... MMMM MMMM

 S represents the sign bit, the X's are the exponent bits, and the M's
 are the mantissa bits. Note that the leftmost one is assumed in real*4
 and real*8 formats, but present as "1" in BYTE 3 of the real*10
 format.

 To shift the binary point properly, you first un-bias the exponent and
 then move the binary point to the right or left the appropriate number
 of bits.

 The following are some examples in real*4 format:

                     SXXX XXXX XMMM MMMM ... MMMM MMMM
 2   =  1  * 2**1  = 0100 0000 0000 0000 ... 0000 0000 = 4000 0000
     Note the sign bit is zero, and the stored exponent is 128, or
     100 0000 0 in binary, which is 127 plus 1.  The stored mantissa
     is (1.) 000 0000 ... 0000 0000, which has an implied leading
     1 and binary point, so the actual mantissa is one.
 -2  = -1  * 2**1  = 1100 0000 0000 0000 ... 0000 0000 = C000 0000
     Same as +2 except that the sign bit is set.  This is true for
         all IEEE format floating-point numbers.
  4  =  1  * 2**2  = 0100 0000 1000 0000 ... 0000 0000 = 4080 0000
     Same mantissa, exponent increases by one (biased value is
     129, or 100 0000 1 in binary.
  6  = 1.5 * 2**2  = 0100 0000 1100 0000 ... 0000 0000 = 40C0 0000
     Same exponent, mantissa is larger by half--it's
     (1.) 100 0000 ... 0000 0000, which, since this is a binary
     fraction, is 1 1/2 (the values of the fractional digits are
     1/2, 1/4, 1/8, etc.).
  1  = 1   * 2**0  = 0011 1111 1000 0000 ... 0000 0000 = 3F80 0000
     Same exponent as other powers of two, mantissa is one less
     than two at 127, or 011 1111 1 in binary.
 .75 = 1.5 * 2**-1 = 0011 1111 0100 0000 ... 0000 0000 = 3F40 0000
     The biased exponent is 126, 011 1111 0 in binary, and the
     mantissa is (1.) 100 0000 ... 0000 0000, which is 1 1/2.
 2.5 = 1.25 * 2**1 = 0100 0000 0010 0000 ... 0000 0000 = 4020 0000
     Exactly the same as two except that the bit which represents
     1/4 is set in the mantissa.
 0.1 = 1.6 * 2**-4 = 0011 1101 1100 1100 ... 1100 1101 = 3DCC CCCD
     1/10 is a repeating fraction in binary. The mantissa is
     just shy of 1.6, and the biased exponent says that 1.6 is to
     be divided by 16 (it is 011 1101 1 in binary, which is 123 in
     decimal). The true exponent is 123 - 127 = -4, which means
     that the factor by which to multiply is 2**-4 = 1/16. Note
     that the stored mantissa is rounded up in the last bit--an
     attempt to represent the unrepresentable number as accuartely
     as possible. (The reason that 1/10 and 1/100 are not exactly
     representable in binary similar to the reason that 1/3 is not
     exactly representable in decimal.)
  0  = 1.0 * 2**-128 = all zero's--a special case.


 148. Different Results between Alternate and Coprocessor/Emulator Math

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm
 Last Modified: 12-OCT-1988    ArticleIdent: Q36069

 There may be differences between the floating point values you get
 when using coprocessor/emulator math and the alternate math packages.

 This behavior applies to C Versions 3.00, 4.00, 5.00, and 5.01, Pascal
 Versions 3.1x, 3.20, 3.30, 3.31, 3.32, and 4.00, FORTRAN Versions
 3.1x, 3.20, 3.30, 3.31, 4.0x, and 4.10, and MASM Versions 1.25, 1.27,
 3.0x, 4.00, 5.00, and 5.10.

 When you do any floating point arithmetic with the coprocessor all
 values are pushed onto the coprocessor stack. The coprocessor stack
 only holds 10-byte reals. This means that all real*4 and/or real*8
 (real/double) are expanded to 10-byte reals, then all of the
 arithmetic is done on these 10-byte reals. The emulator package does
 this same expansion. The results of floating point calculations are
 then rounded back down to real*4 or real*8 format.

 Alternate math calculations are performed using real*4 or real*8
 format which can result in less precision than that available with
 coprocessor/emulator math.


 149. Share Problems Using sopen and Incorrect oflag

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 12-OCT-1988    ArticleIdent: Q36611

 The "important" note on Page 550 of the "Microsoft Optimizing 5.1
 Compiler Run-Time Library Reference" manual has an error in the second
 condition listed as causing problems when opening a new file with the
 sopen function under DOS Versions 3.00, 3.10, or 3.20 with SHARE
 installed.

 "With oflag set to any combination that includes O_FLAG..." is
 incorrect. There is no O_FLAG setting available. The oflag setting
 should be O_CREAT | O_RDWR. This oflag setting with pmode set to
 S_IREAD requires that shflag be set to SH_COMPAT to avoid problems
 with the new file created by sopen.

 The problems that can occur when the wrong sopen options are used
 include not opening the new file, or opening the new file but not
 being able to write to it resulting in a file of zero length.

 These problems may also occur in DOS Version 3.30.


 150. Filename from tmpnam Has Prefix from P_tmpdir

 Product Version(s): 4.00 5.00 5.10  | 5.10
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER |
 Last Modified: 18-OCT-1988    ArticleIdent: Q36675

 The tmpnam function generates a temporary filename that can be used as
 a temporary file. The character string that tmpnam creates consists of
 the path prefix defined by the P_tmpdir entry in stdio.h, followed by
 a sequence consisting of the digit characters "0" through "9".

 This information is in the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" manual on Page 611. The "Microsoft C 4.00
 Run-Time Library Reference" manual does not describe this naming
 behavior.

 In Version 5.00 and 5.10, the P_tmpdir entry is defined in stdio.h
 as follows:

 #define P_tmpdir "\\"

 In Version 4.00, the P_tmpdir entry is defined in stdio.h as follows:

 #define P_tmpdir "\\TMP"

 Thus, a string for a temporary filename created under Version 4.00
 will have the form \TMP\x (where x is the generated number), and it
 will be necessary to have a TMP subdirectory.


 151. Warning C4000 Unknown Warning

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36695

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 The messages listed in this section indicate potential problems but do
 not hinder compilation and linking. The number in parentheses at the
 end of an error-message description gives the minimum warning level
 that must be set for the message to appear.

 The following is the warning:

 C4000    Unknown Warning
          The compiler detected an unknown error condition.

          Please report this condition to Microsoft Corporation, using
          the Product Assistance Request form at the back of this
          manual.

 The occurance of this warning indicates a problem with the compiler.
 Please include the smallest possible example of source code which
 demonstrates the problem when sending the Software Problem Report to
 Microsoft.


 152. Warning C4017 Cast of int Expression to far Pointer

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36706

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4017       cast of int expression to far pointer

             A far pointer represents a full segmented address.  On
             an 8086/8088 processor, casting an 'int' value to a
             far pointer may produce an address with a meaningless
             segment value.  (1)

 A possible cause for this warning is that a function that returns a far
 pointer was not prototyped and the compiler assumed the return type of
 the function to be "int" instead of a far pointer as was actually
 intended.

 The followin is a code example:

 main()
 {
   char far *address ;

   address = foo () ;
 }

 Since foo was not prototyped, the compiler will assume that foo
 returns an integer. If the warning level is set at 2, this code would
 receive the warning C4016 "foo : no function return type" (if the
 warning level were set to 1).


 153. Warning C4028 Parameter 'n' Declaration Different

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36710

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4028       parameter 'n' declaration different

             The type of the given parameter did not agree with the
             corresponding type in the argument-type list or with
             the corresponding formal parameter. (1)

 Note: this message may appear when it should actually have produced
 the warning C4074 if an ellipsis is used in the prototype.

 The call of the function gave a parameter type that did not match up
 with prototype and function definition, as in the following code
 fragment:

 void foo (int) ;

 main ()
 {
   float fp ;
   foo (fp) ;
 }

 void foo (int)
 {
 }


 154. Warning C4037 'identifier' : Formal Parameters Ignored

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36722

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and section E.3.3 (Page 269) of the
 Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4037       'identifier' : formal parameters ignored

             No storage class or type name appeared before the
             declarators of formal parameters in a function
             declaration, as in the following example:

             int *f(a,b,c);

             The formal parameters are ignored. (1)

 The prototype for this function, f, did not declare the types of
 arguments that the function receives. You could correct the above
 example as follows:

 int *f (int a, int b, int c) ;


 155. Warning C4040 near/far/huge on 'identifier' Ignored

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36725

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide and section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4040       near/far/huge on 'identifier' ignored

             The 'near' or 'far' keyword has no effect in the
             declaration of the given identifier and is ignored.

 You cannot declare an array to be huge if it is declared within a
 function because this array will reside on the stack that is limited
 to the default data segment. You can move the declaration of the array
 with the huge keyword outside of all functions, use the "static" or
 "extern" keywords to move the array into a far data segment, or use a
 huge or far pointer.

 QuickC Versions 1.00 and 1.01 do not support the huge keyword or the
 huge-memory model.



 156. Warning C4047 'operator': Different Levels of Indirection

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q36729

 This information is from section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Version 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning message:

 C4047       'operator' : different levels of indirection

             An expression involving the specified operator had
             inconsistent levels of indirection. (1)

 The following example illustrates this condition:

             char **p ;
             char  *q ;
             .
             .
             p = q ;

 You will commonly get this warning if you do not cast MALLOC() to your
 pointer type. The following code fragment will produce the C4047
 message:
             char *string ;
             string = malloc (5) ;

 To eliminate this warning message in this example, cast MALLOC() as
 follows:
             string = (char *) malloc (5) ;

 This is a result of the fact that MALLOC()'s default return type is
 "void *".


 157. C2086 Error When Compiling with /Oi and #include <mt\math.h>

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 16-JAN-1990    ArticleIdent: Q36782

 When using the multithreaded version of <math.h>, error C2086
 "identifier redefinition" occurs if -Oi (or -Ox) intrinsic
 optimization is enabled. The cause of the error is the fact that the
 compiler has built-in prototypes for intrinsic functions. Because
 <mt\math.h> declares these functions differently, the C2086 error is
 generated.

 This conflict arises for the following floating-point routines:

    acos  asin  atan  atan2  cos  exp  fabs  fmod  log  log10  pow
    sin   sinh  sqrt  tan    tanh

 The conflict occurs because the compiler has built-in function
 prototypes for routines for which it is generating intrinsics. When
 you compile with the normal include files, the compiler's internal
 prototype is the same as the one in <math.h>, so there is no conflict.
 However, when you use <mt\math.h>, the prototypes are changed from
 "_CDECL" to "far pascal", which causes the redefinition error.

 One workaround is to use the following

    #pragma function ({func1} {func2} {etc})

 at the start of the module to force functions to be used instead of
 intrinsics. This will also work if you are using the alternate math
 library with multithreaded and/or DLL modules and the link fails with
 unresolved externals.

 A second workaround to this conflict is to use the C preprocessor's
 conditional-compilation facility, as in the following fragment of
 <mt\math.h>:

 ----------------------------------------------------------------------
     last part of <mt\math.h>
 ----------------------------------------------------------------------

 /* function prototypes */

 #ifndef INTRINSICS    /* this is the modification */

 double far pascal acos(double);
 double far pascal asin(double);
 double far pascal atan(double);
 double far pascal atan2(double, double);
 double far pascal cos(double);
 double far pascal cosh(double);
 double far pascal exp(double);
 double far pascal fabs(double);
 double far pascal fmod(double, double);
 double far pascal log(double);
 double far pascal log10(double);
 double far pascal pow(double, double);
 double far pascal sin(double);
 double far pascal sinh(double);
 double far pascal sqrt(double);
 double far pascal tan(double);
 double far pascal tanh(double);

 #endif  /* INTRINSICS; end of modification */

 int    far _CDECL abs(int);
 double far pascal atof(const char far *);
 double far pascal cabs(struct complex);
 double far pascal ceil(double);
 int    far _CDECL dieeetomsbin(double far *, double far *);
 int    far _CDECL dmsbintoieee(double far *, double far *);
 int    far _CDECL fieeetomsbin(float far *, float far *);
 double far pascal floor(double);
 int    far _CDECL fmsbintoieee(float far *, float far *);
 double far pascal frexp(double, int far *);
 double far pascal hypot(double, double);
 double far pascal j0(double);
 double far pascal j1(double);
 double far pascal jn(int, double);
 long   far _CDECL labs(long);
 double far pascal ldexp(double, int);
 int    far _CDECL matherr(struct exception far *);
 double far pascal modf(double, double far *);
 double far pascal y0(double);
 double far pascal y1(double);
 double far pascal yn(int, double);

 In this version of <mt\math.h>, the intrinsic math routines have been
 pulled out of the main block of function prototypes and conditionally
 compiled; the preprocessor will include them only if the symbol
 "INTRINSICS" is not defined. This way, under normal circumstances,
 nothing is different; when you #include <mt\math.h>, all the
 prototypes are included. But when you want to optimize with /Ox or
 /Oi, you can use the following command-line option so that the
 preprocessor will remove those prototypes from the compilation:

 cl  ... /D INTRINSICS ...


 158. Microsoft OS/2 Languages Use Virtual Memory

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | h_fortran 4.10 h_masm 5.10 S_PASCAL 4.00
 Last Modified: 18-OCT-1988    ArticleIdent: Q36791

 Question:

 Will Microsoft's OS/2 languages use virtual memory under OS/2?

 Response:

 OS/2 will make use of virtual memory if memman=MOVE is set in the
 CONFIG.OS2 or CONFIG.SYS file, physical RAM becomes full, and there is
 enough free disk space to swap to. OS/2 is generally not dependent on
 the nature of the application for using virtual memory, except for
 device drivers that may require fixed segments of physical RAM.


 159. Error C2106 when Assigning a String Literal to a char Array

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 18-OCT-1988    ArticleIdent: Q36870

 A common error in C is to attempt to fill a character array, defined
 as char arrayname[somelength], with a string constant by use of the
 simple-assignment operator (i.e., the equal sign, = ). This error
 causes the compiler error "error C2106: '=' : left operand must be
 lvalue."

 Example 1, which does not compile and causes this error, follows
 immediately. An extended example (Example 2), which compiles and runs
 and demonstrates some concepts, is given below along with its output.

 The following is Example 1:

 /* This code gives compiler error C2106. */
 #include <string.h>
 char string1[10];

 void main(void);
 void main(void)
 {
         string1 = "String1";
 }

 As another way to fill an array, non-auto (i.e. global) char arrays
 and char pointers (starting with C Version 5.00) may be initialized
 when declared as in the following two lines:

 char string1[10] = "String1";
 char *string2 = "String2";

 The following is Example 2:

 /* This example demonstrates some string usage principles. */
 #include <stdio.h>
 #include <string.h>
 #include <malloc.h>

 char string1[40];       /* string1 is an array of char  */
 char *string2;          /* string2 is a pointer to char */
         /* Important: Know when to malloc space for string2. */

 void main(void);
 void main(void)
 {
             /* This shows the correct way to achieve the   */
             /* assignment intended by string1 = "String1"; */
         strcpy(string1, "Contents of string1");
         printf("1:%s\n\n", string1);

             /* These two assignments show two ways to     */
             /* use a char pointer with a string literal.  */
         string2 = "Contents of string2"; /* point to the literal */
         printf("2:%s\n", string2);
             /* allocate memory for char *string2 to point at */
         string2 = (char *) malloc(sizeof(string1));
         strcpy(string2, "Contents of string2, again");
         printf("3:%s\n\n", string2);
         free(string2);

         /* This shows a failed attempt to fill a char  */
             /* array by assignment through a char pointer. */
         string2 = string1;
         string2 = "Contents of string2, but not string1";
         printf("4:%s\n", string1);
         printf("5:%s\n\n", string2);

             /* This shows how correctly to use a pointer   */
             /* to fill a char array with a string literal. */
         string2 = string1;
         strcpy(string2, "Contents of string2, and also string1");
         printf("6:%s\n", string1);
         printf("7:%s\n\n", string2);
 }

 The output of this example is as follows:

 1:Contents of string1

 2:Contents of string2

 3:Contents of string2, again

 4:Contents of string1
 5:Contents of string2, but not string1

 6:Contents of string2, and also string1
 7:Contents of string2, and also string1


 160. _Settexwindow() and Scrolling

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 21-DEC-1988    ArticleIdent: Q36947

 Problem:

 The _settextwindow() function specifies a window where the text output
 to the screen is displayed. When the text window is full, the
 uppermost line scrolls up and out of the window. This scrolling occurs
 in most cases, but not all. The _settextwindow function knows to
 scroll the text in the window if the current line being written to is
 the last line in the window and one of either the following situations
 occurs:

 1. The string being printed ends with a carriage control
    character, '\n'.

 2. The string wraps onto the next line. (In this case, the
    wrapping is enabled by a _wrapon(_GWRAPON) call.)

 The text in the window will not scroll if these conditions are not
 met. More than likely, the last line in the window will be
 over-written.

 This is expected behavior for the _settextwindow and related
 functions.

 The examples below assume that the text window is defined by the
 coordinates (1,1, 14,80).

 The following example causes the text window to scroll because the
 second _outtext call (which prints to the last line in the window)
 ends in a carriage return character, '\n':

         _settextposition (13,1) ;       /* set cursor to 2nd to    */
                                         /* last line in the window.*/

         _outtext ("This will appear on line 13\n") ;
         _outtext ("This will appear on the last line (14)\n") ;
         _outtext ("The text window has now scrolled.") ;

 The following example also scrolls because the text output on the
 final line in the window wraps around to the next line:

         _wrapon (_GWRAPON) ;            /* enable wrapping of text.*/
         _settextposition (14,1) ;       /* set cursor to last line.*/
         _outtext ("This will be forty characters in length..") ;
         _outtext ("This will wrap around the right window border") ;

 The example below will not scroll the text window. The second
 _outtext() will just over-write the first. It will not scroll because
 wrapping has been disabled, and there is no carriage control character
 to signal the window to scroll.

 The following example demonstrates this behavior:

         _wrapon (_GWRAPOFF) ;           /* disable wrapping of text*/
         _settextposition (14,1) ;       /* set cursor to last line.*/
         _outtext ("This will appear on the last line (line 14)...") ;
         _settextposition (14,1) ;       /* set cursor to last line.*/
         _outtext ("This will over-write, not scroll.") ;



 161. Warning C1015 May be Caused by Lack of Available File Handles

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JAN-1990    ArticleIdent: Q36953

 Compiler error C1015, which is not documented in the text, is often
 caused by an error finding or opening an include file. This new error
 message is noted in the C Version 5.10 file ERRMSG.DOC.

 This error can occur if the INCLUDE environment variable has
 not been set correctly for your include file directory or the TMP
 variable is set to a Ram Disk.

 Especially under DOS, this error also can be generated by not having
 enough file handles available. (A file handle is an integer used by
 the operating system to keep track of every open file.) The number of
 file handles available to DOS can be increased from the default of
 eight to a number up to 20 (or higher with some OEM adaptations of
 MS-DOS versions later than Version 3.20) by placing the following line
 in CONFIG.SYS and rebooting your computer:

 FILES=20

 It  has been reported that if you do not set files above the default
 of eight, error C1015 appears soon after compilation begins. Setting
 files to 20 corrects the problem.

 File handles will typically be used during compilation and linkage by
 the CL driver, the compiler passes, your C source code file, include
 files, the linker, libraries, and temporary files created by the
 compiler or linker.

 Closing a file makes its handle available to the operating system
 again, so the lack of available file handles refers to the number of
 files open at any one time.


 162. C2086, C2061 on CFLOW.C when Language Extentions Not Enabled

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 12-DEC-1988    ArticleIdent: Q36955

 Compiling the sample program CFLOW.C with language extensions disables
 results in the following errors:

 cflow.c(4) : error C2086: 'size_t' : redefinition
 cflow.c(934) : error C2061: syntax error : identifier 'c'

 The Microsoft extensions to C can be disabled by compiling with
 the option /Za (enforce ANSI compatibility) or, when in QuickC,
 clearing the X from the Language Extensions check box in the Compile
 dialog box.

 The C2086 error occurs because both CFLOW.C and STDIO.H have the following:

 typedef unsigned int size_t;

 Redefinition of a typedef is a language extension. This information is
 stated in the "Microsoft C Optimizing Compiler User's Guide" on Page
 100.

 The C2061 error occurs on the line

 static int near c;

 because the keyword "near" is an extension to C, and so is understood
 by the compiler to be the simple identifier being defined, leaving the
 now-surplus "c" to be flagged as syntactically incorrect. This
 information is documented in the user's guide on Page 99.


 163. Warning C4067 Unexpected Characters Following 'directive'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QUICKC S_ERROR
 Last Modified: 12-DEC-1988    ArticleIdent: Q36992

 The warning below is from Section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and Section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4067       unexpected characters following 'directive' directive-
             newline expected

             Extra characters followed a preprocessor directive, as
             in the following example:

             #endif  NO_EXT_KEYS

             This is accepted in Version 3.0, but not in Versions
             4.0 and 5.0.  Versions 4.0 and 5.0 require comment
             delimeters, such as the following:

             #endif  /* NO_EXT_KEYS */

 As with Versions 4.00, 5.00, and 5.10 of the C optimizing compiler,
 QuickC Versions 1.00 and 1.01 do not accept the extra characters
 unless surrounded by comment delimeters.


 164. Warning C4077 Unknown check_stack Option

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QUICKC S_ERROR
 Last Modified: 12-DEC-1988    ArticleIdent: Q37001

 The warning below is from Section D.1.3 (Page 349) of the "Microsoft
 QuickC Programmer's Guide" and Section E.3.3 (Page 278) of the
 "Microsoft C Optimizing Compiler User's Guide" for Versions 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 C4077       unkown check_stack option

             An unknown option was given with the old form of the
             'check_stack' pragma, as in the following example:

             #pragma check_stack yes

             In the old form of the check_stack pragma, the argument
             to the argument to the pragma must be empty, +, or -. (1)

 The following is an example of using the check_stack pragma:

       syntax           Compiled with /Gs       Action
                         (Pointer Check)

 #pragma check_stack()        yes            Turns off Stack checking
                                             for routines that follow.
 #pragma check_stack()        no             Turns on Stack checking
                                             for routines that follow.
 #pragma check_stack(on)      yes or no      Turns on Stack checking
                                             for routines that follow.
 #pragma check_stack(off)     yes or no      Turns off Stack checking
                                             for routines that follow.

 Note: for earlier versions of Microsoft C, the check_stack pragma had
 a different format. check_stack+ was to enable stack checking and
 check_stack- was to disable stack checking. Although the Microsoft
 Optimizing compiler still accepts this format, its use is discouraged
 because it may not be supported in future versions.

 This information was taken from Page 98 of the C user's guide and
 Page 169 of the QuickC programmer's guide.


 165. Warning C4086 Expected

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QUICKC S_ERROR
 Last Modified: 12-DEC-1988    ArticleIdent: Q37004

 The warning below is from Section D.1.3 (Page 340) of the "Microsoft
 QuickC Programmer's Guide" and Section E.3.3 (Page 269) of the
 "Microsoft C Optimizing Compiler User's Guide" for Version 5.00 and
 5.10.

 This message indicates potential problems but does not hinder
 compilation and linking. The number in parentheses at the end of a
 warning-message description gives the minimum warning level that must
 be set for the message to appear.

 The following is the warning:

 C4086       expected [1|2|4]

             An invalid argument was given for a "pack" pragma, as
             in the following example:

             #pragma pack (yes)

 The "pack" pragma is used when you want to specify packing other than
 the packing specified on the command line for particular structures.
 The /Zp option and the "pack" pragma control how structure data are
 packed into memory.

 For detailed information on the /Zp option and the "pack" pragma, see
 Page 210 of the QuickC programmer's guide and Page 100 of the C user's
 guide.


 166. How to Determine the Amount of Available DOS Memory

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-DEC-1988    ArticleIdent: Q37022

 Question:

 Is there a C run-time function that I can use to determine how much
 RAM is available under DOS?

 Response:

 No function exists that specifically performs this task. Functions
 "_freect" or "_memavl" only return available memory for dynamic
 allocation in the near heap. The near heap is located above the stack
 within the 64K byte or smaller default data segment called DGROUP.
 Function _memavl indicates the amount of near space that never has
 been allocated, whereas _freect allows you to detect what has been
 freed.

 However, you may use the function "_dos_allocmem" defined below
 to determine the amount of far heap above the default data segment:

     #include <dos.h>
     unsigned _dos_allocmem(size, segment) ;
     unsigned size ;
     unsigned *segment ;

 If the attempted memory allocation is NOT successful, _dos_allocmem
 puts the maximum possible free memory size (in 16-byte paragraphs)
 in the word pointed to by "segment". If you request to allocate
 0xFFFF paragraphs of memory (which will fail in any case), you should
 be able to find out the amount of available memory. (DOS function
 call 48h performs the same task.)

 Note: the value returned to *segment is in paragraphs too. If other
 memory allocation functions are going to use this value, it should be
 converted to bytes.

 Refer to the "Microsoft C Version 5.10 Optimizing Compiler Run-time
 Library Reference" for specific information on using _dos_allocmem.


 167. Link Error No Stack Segment after Using Windows SDK Install

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-DEC-1988    ArticleIdent: Q37023

 If a C program generates linker errors stating that no stack segment
 exists and that there are several unresolved externals references made
 by the startup code, the program may have been linked with libraries
 modified by the Windows SDK Install program.

 The Windows install program modifies C libraries, upon your request,
 so that when linking Window applications it can look for the standard
 library names with no other linker options specified. A more detailed
 explanation can be found in the README.WRI on the Development
 Utilities Disk 1 that comes with Windows SDK Version 2.00.

 The install program retains the original C library. The library will
 have its same name with a "C" appended. For instance, SLIBCE.LIB will
 be copied to SLIBCEC.LIB. When you link with this library, make sure
 to use the /NOD option and specify the library by name.


 168. Setup Won't Accept Drive on Novell Network

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-NOV-1988    ArticleIdent: Q37198

 Setup on Novell network Versions 2.0x gives "cannot create subdirectory
 G:\(etc.)" when trying to specify a destination for bound executables
 (i.e., the first question about paths that the setup program asks).

 It will not install on a network because it is illegal to do so
 without a special licensing agreement with Microsoft. If you have this
 agreement you receive a setup program that installs on the network.

 This scenario should not be confused with the situation of someone
 installing Microsoft software on their immediate machine and using
 network drives to store files they have created. This process is
 allowed.


 169. Coordinates Incorrect in Run-Time Library Manual

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 18-NOV-1988    ArticleIdent: Q37199

 Page 51 of the "Microsoft C Run-Time Library Manual" states that the
 range of physical coordinates is (0,0) to (640, 350). This information
 is incorrect. The correct range of physical coordinates is (0,0) to
 (639, 349).


 170. Redirection with spawn() or exec()

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S880925-1 s_quickc
 Last Modified: 18-NOV-1988    ArticleIdent: Q37200

 Question:

 There is a problem when you use spawnvp or spawnlp to invoke the
 SORT.EXE that usually comes with DOS. When you run the program, it
 seems that SORT.EXE starts, but then it does nothing. The behavior is
 similar to starting SORT.EXE from the DOS prompt without any arguments.

 How do I do any redirection with spawn() or exec()?

 Response::

 Use the system() function. For example, you can make a run SORT.EXE
 by executing the following:

    system("SORT <INFILE >OUTFILE");

 This process has the minor disadvantage of taking up extra memory for
 another copy of COMMAND.COM. This behavior shouldn't be a problem
 unless you're short on available memory. If you do not have very much
 memory, the following information may help.

 Because COMMAND.COM, and NOT the EXEC loader, handles redirection,
 this behavior is expected. Child processes inherit the handles of
 their parents; therefore, to redirect the input and output of the
 child, change the definitions of STDIN and STDOUT in the
 parent process. The proper way to redirect input for a filter is
 described starting on Page 441 of the "MS-DOS Encyclopedia," along with
 a complete MASM example.

 Note: the dup and dup2 functions in the C Version 5.10 run-time
 library are the same as the INT 21h functions 45h and 46h,
 respectively.

 There also are partial examples of this technique on Page 230 of the
 "Microsoft C 5.1 Run-Time Library Reference" manual and on page 353 of
 "Advanced MS-DOS Programming" (by Duncan, published by Microsoft
 Press).

 It is possible to use freopen() to redefine STDIN and STDOUT; however,
 doing so causes any redirection that may have been performed on the
 parent process to be lost.


 171. System Memory Allocation Error after Using halloc or malloc

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S880914-27
 Last Modified: 18-NOV-1988    ArticleIdent: Q37201

 After running a program you have created that uses malloc or
 halloc functions, DOS may print the following message:

 Memory Allocation Error
 Cannot Load COMMAND.COM.

 You are able to allocate, use, write, read, and free memory, but when
 your program finishes, you receive the error. If you remove halloc()
 from your program, it terminates normally.

 Your program is probably writing outside of a memory block you
 allocated using halloc or malloc. DOS maintains information about
 memory usage in blocks immediately preceding the area you're given.
 This error is usually are result of overwriting these information
 blocks. The solution is to find out where you're overwriting DOS's
 memory and avoid doing it.

 Note: this error can also be the result of writing PAST the end of a
 block because you could corrupt the list entry for the NEXT block.

 You can determine where the overwrite occurs by using CodeView to set
 a tracepoint on the space after the allocated block. If you don't have
 enough memory to run CodeView, you can narrow down the problem by
 using a pointer to check those bytes at selected points in your
 program.


 172. Operator sizeof Returns Type size_t, Defined as unsigned int

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 21-NOV-1988    ArticleIdent: Q37205

 The sizeof operator returns a value that is of type size_t. The
 definition of size_t is implementation-dependent, according to the
 ANSI standard. In Microsoft C, the size_t type is defined in STDEF.H
 and in MALLOC.H as an unsigned int. This information is documented in
 the "Microsoft C Optimizing Compiler Run-Time Library Reference" on
 Pages 38 and 98.

 To use sizeof on huge items, which can be larger than 64K, you will
 need to use a typecast on the sizeof expression as follows:

    char huge a[95000];
    unsigned long sizea;

    sizea = (unsigned long) sizeof(a);

 Note: the Index entry for "size_t type" lists Pages 38 and 97; it
 should say Pages 38 and 98.

 The "Microsoft C Optimizing Compiler Language Reference" manual
 describes the sizeof operator on Pages 120-121, section 5.3.4, but
 does not give the return type.


 173. No Such Thing as a static auto Variable.

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER   | S_QUICKC docerr
 Last Modified: 21-NOV-1988    ArticleIdent: Q37219

 Page 86 (section 4.6.2, third paragraph) of the "Microsoft QuickC and
 Optimizing C Language Reference" states "A static auto variable can
 be initialized..."

 However, the storage classes static and auto are mutually exclusive --
 there is no "static auto" class. The text should read, "A static OR
 auto variable can be initialized..."


 174. Domain Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc h_fortran s_pascal
 Last Modified: 21-NOV-1988    ArticleIdent: Q37223

 A domain error occurs when you pass an invalid value to a function.
 "Domain" refers to arguments to a function; "range" refers to the
 return values.

 For example, if you pass a -1 to sqrt(), you receive the math error
 "M6201 Domain Error" because -1 is not in the domain of the square
 root function (i.e., you can't take the square root of -1).

 This error also can occur if an incorrect type is passed to the
 function. (For example, passing an int to a function that expects
 double.) You should receive warnings in these cases if you have
 declared proper function prototypes (perhaps by including the math.h
 file).

 Make sure the value you pass to a function is of the proper type and
 the value is within that function's domain.


 175. Why "CDECL" Is Everywhere in Your Include Files

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 26-OCT-1988    ArticleIdent: Q37233

 Question:

 When I look at the include files provided with the Microsoft C
 compiler, I see all the function prototypes prefixed with "_CDECL".
 Why?

 Response:

 When Microsoft extensions are enabled, the manifest constant "_CDECL"
 takes the value "cdecl", which says that the associated function takes
 standard C calling conventions. (C calling conventions are used by
 default except when the /Gc switch is specified during compilation.
 The /Gc switch tells the compiler to default to FORTRAN/Pascal-style
 function calling and naming conventions.)

 Thus, the _CDECL's on the function prototypes tell the compiler to
 generate the runtime library function calls using C calling and naming
 conventions always--even if the /Gc option is used.

 For more information, see the "Mixed Language Programming Guide" and
 the "Microsoft C Language Reference."


 176. Loadtime DLL Initialization for C 5.10

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | softlib CRTDLL.ARC S12104.EXE
 Last Modified: 21-SEP-1989    ArticleIdent: Q37355

 Question:

 How do I implement load-time DLL initialization without losing C
 run-time support for my DLL?

 Response:

 Single-Threaded DLLs (that use LLIBCDLL.LIB)

 There is an object module DLLINIT.OBJ that must be linked with your
 routine. You must make an explicit call to C_INIT() to bring in
 the C run-time startup code. If you are going to use DosLoadModule()
 and DosFreeModule() to bring in and remove your DLL, then you must also
 link in DLLTERM.OBJ. No explicit calls are necessary to use this
 routine.

 Multi-Threaded DLLs

 There is an object module CRTDLL_I.OBJ that replaces the CRTDLL.OBJ
 that comes with the C package. You should use CRTDLL_I.OBJ in the
 exact same manner you would use CRTDLL.OBJ. You must also make a
 reference to C_INIT() in your initialization routine. The prototype is
 as follows:

    void far
    pascal C_INIT();.

 All three object modules are in the Software Library archive file
 CRTDLL.ARC. This file can be found in the Software Library by
 searching on the filename CRTDLL.ARC, the Q number of this article, or
 S12104.


 177. "pascal" Attribute for Multi-Thread Functions Returning Double

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 22-NOV-1988    ArticleIdent: Q37459

 Although it is not documented, an important requirement for returning
 floating-point values from functions in a multi-thread environment is
 defining and prototyping functions with the "pascal" function
 attribute as we have done for all functions prototyped to return a
 double in \include\mt\math.h.

 When you use the pascal attribute on floating-point functions, the
 floating-point return value is placed on the calling thread's stack,
 providing each thread with its own return value as desired.

 When using the default of the C function call/return convention
 instead of pascal, we use a global variable __fac (floating-point
 accumulator) for returning floating-point values. For multi-thread
 applications or DLL's using CRTLIB.DLL, the global variable __fac
 could be unintentionally modified by another thread, so it is not
 contained in CRTEXE.OBJ, CRTDLL.OBJ, or CRTDLL.LIB. Consequently,
 references to __fac will be unresolved at link time.


 178. Scan Codes for IBM and Compatible Keyboards

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified:  8-NOV-1988    ArticleIdent: Q37617

 Below are the scan codes for IBM and compatible keyboards. All scan
 codes are in hexadecimal. See the "IBM PC Technical Reference" for more
 details.

 The scan codes are as follows:

 83 key (PC,PC/XT)       84 key (PC/AT)        101/102 key (PC/AT PS/2)

 Key     Scan Code       Key     Scan Code       Key     Scan Code

 ESC         01          KP ESC      01          ESC         01
 1           02          1           02          1           02
 2           03          2           03          2           03
 3           04          3           04          3           04
 4           05          4           05          4           05
 5           06          5           06          5           06
 6           07          6           07          6           07
 7           08          7           08          7           08
 8           09          8           09          8           09
 9           0A          9           0A          9           0A
 0           0B          0           0B          0           0B
 -           0C          -           0C          -           0C
 =           0D          =           0D          =           0D
 BACKSPACE   0E          BACKSPACE   0E          BACKSPACE   0E
 TAB         0F          TAB         0F          TAB         0F
 Q           10          Q           10          Q           10
 W           11          W           11          W           11
 E           12          E           12          E           12
 R           13          R           13          R           13
 T           14          T           14          T           14
 Y           15          Y           15          Y           15
 U           16          U           16          U           16
 I           17          I           17          I           17
 O           18          O           18          O           18
 P           19          P           19          P           19
 [           1A          [           1A          [           1A
 ]           1B          ]           1B          ]           1B
 RETURN      1C          RETURN      1C          RETURN      1C
 CTRL        1D          CTRL        1D          L CTRL      1D
 A           1E          A           1E          A           1E
 S           1F          S           1F          S           1F
 D           20          D           20          D           20
 F           21          F           21          F           21
 G           22          G           22          G           22
 H           23          H           23          H           23
 J           24          J           24          J           24
 K           25          K           25          K           25
 L           26          L           26          L           26
 ;           27          ;           27          ;           27
 '           28          '           28          '           28
 `           29          ESC         29          `           29
 L SHIFT     2A          L SHIFT     2A          L SHIFT     2A
 Z           2C          Z           2C          Z           2C
 X           2D          X           2D          X           2D
 C           2E          C           2E          C           2E
 V           2F          V           2F          V           2F
 B           30          B           30          B           30
 N           31          N           31          N           31
 M           32          M           32          M           32
 ,           33          ,           33          ,           33
 .           34          .           34          .           34
 /           35          /           35          /           35
 R SHIFT     36          R SHIFT     36          R SHIFT     36
 PRT SCR     37          PRT SCR     37          KP *        37
 ALT         38          ALT         38          ALT         38
 Space       39          Space       39          Space       39
 CAPS LOCK   3A          CAPS LOCK   3A          CAPS LOCK   3A
 F1          3B          F1          3B          F1          3B
 F2          3C          F2          3C          F2          3C
 F3          3D          F3          3D          F3          3D
 F4          3E          F4          3E          F4          3E
 F5          3F          F5          3F          F5          3F
 F6          40          F6          40          F6          40
 F7          41          F7          41          F7          41
 F8          42          F8          42          F8          42
 F9          43          F9          43          F9          43
 F10         44          F10         44          F10         44
 NUM LOCK    45          NUM LOCK    45          NUM LOCK    45
 SCROLL LOCK 46          SCROLL LOCK 46          SCROLL LOCK 46
 KP 7        47          KP 7        47          KP 7        47
 KP 8        48          KP 8        48          KP 8        48
 KP 9        49          KP 9        49          KP 9        49
 KP -        4A          KP -        4A          KP -        4A
 KP 4        4B          KP 4        4B          KP 4        4B
 KP 5        4C          KP 5        4C          KP 5        4C
 KP 6        4D          KP 6        4D          KP 6        4D
 KP +        4E          KP +        4E          KP +        4E
 KP 1        4F          KP 1        4F          KP 1        4F
 KP 2        50          KP 2        50          KP 2        50
 KP 3        51          KP 3        51          KP 3        51
 KP 0        52          KP 0        52          KP 0        52
 KP .        53          KP .        53          KP .        53
                         Sys Req     54          F11         57
                                                 F12         58
                                                 R CTRL      E0 10
                                                 KP /        E0 36
                                                 R ALT       E0 38
                                                 RIGHT ARROW E0 40
                                                 HOME        E0 47
                                                 UP ARROW    E0 48
                                                 PAGE UP     E0 49
                                                 LEFT ARROW  E0 4B
                                                 END         E0 4F
                                                 DOWN ARROW  E0 50
                                                 PAGE DOWN   E0 51
                                                 INSERT      E0 52
                                                 DELETE      E0 53
                                                 KP ENTER    E0 1C
                                                 PAUSE       E1 10 45
                                                 PRINT SCR   E0 2A E037

 (Source : Norton's Guide to the IBM PC and PS/2)


 179. Backslash Character Interpreted In /Ss and /St Options

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q37619

 When specifying the /St and /Ss for titles and subtitles in your
 source listing, you must use double-backslash (\\) marks if you want
 your title or subtitle to contain a single backslash. If you do not
 include the second backslash, the next character will be interpreted
 as an escape character.


 180. EOH Is Not a Defined Constant for getch or getche

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q37620

 The "Microsoft C 5.10 Optimizing Compiler Run-Time Library Reference"
 manual for the functions getch and getche states that when reading a
 function or cursor key, the first call to either function will return
 0 or EOH. This is misleading; EOH appears to be a constant that is
 defined in an include file, though it is not. These functions actually
 return 0 or 0xE0. The 0x convention is followed throughout the manual
 for hexadecimal numbers, except in this case.


 181. Amount of Disk Space Needed for Minimum C 5.10 Setup for DOS

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q37621

 Question:

 How much disk space will I need to set up the Microsoft C Version 5.10
 Compiler in a minimum configuration for DOS?

 Response:

 In a minimum configuration, you will need to have about 1.45 megabytes
 of disk space available. This includes the small, medium, and graphics
 libraries and all include files and passes of the compiler.

 This does not include any user source code, temporary files, the
 Microsoft editor, CodeView or any utilities.

 Although you will be able to use the compiler in this minimum setup,
 we recommend that you have about 2.5 megabytes of disk space and do a
 complete setup.


 182. Using Function Name Without "()" Produces No Code

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 17-JUL-1990    ArticleIdent: Q50234

 When a function name declared in your program is used without
 parentheses, the compiler does not produce any code. The compiler does
 not produce error messages or warnings as long as the function has
 been prototyped. This occurs regardless of whether or not the function
 takes parameters because the compiler calculates the function address,
 but because the function call operator "()" is not present, no call is
 made. This result is similar to the following:

    int a;

    a;      /* no code generated here either */

 Code Example
 ------------

 void foo(int a, int b);
 void main(void)
 {
      foo;               /* Using foo without function call operator () */
 }

 The above code compiles and links correctly without errors or warnings
 but produces no code in reference to foo(). For this to work
 correctly, add the function call operator "()".


 183. Using a Logical AND Operation && and OR Operation ||

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 16-NOV-1988    ArticleIdent: Q37624

 Question:

 Why does the statement for the integers a, b, c, and d result in
 values of 1 for a, 2 for b, but 0 for c and d in the following
 example?

    a = (b = 2) || (c = 3) && (d = 4)

 I thought that the logical AND operation && would be performed before
 the logical OR operation ||, so that c and d would be assigned 3 and
 4. The "Microsoft C 5.1 Optimizing Compiler Reference," Page 137
 states "Expressions with higher-precedence operators are evaluated
 first."

 Response:

 While it's true that logical AND has a higher precedence than logical
 OR, precedence in C means how operands are grouped, not necessarily
 the order in which they are evaluated. The documentation is incorrect
 on this point.

 The following

    lvalue = operand1 || operand2 && operand3;

 will be grouped as follows:

    lvalue = operand1 || (operand2 && operand3);

 However, this does not mean (operand2 && operand3) will be evaluated
 first in the above statement. In fact, this statement is a logical OR
 expression with two operands: operand1 and (operand2 && aoperand3).
 Operands are defined as an entity on which an operator acts; in this
 case the logical OR operator || acts on operand1 and (operand2 &&
 operand3). Logical OR expressions are evaluated in left-to-right
 order, so operand1 will be evaluated first.

 As noted in the proposed ANSI C standard, section 3.3.14 of both the
 November 1987 and May 1988 drafts for the logical OR operator, "If the
 first operand compares unequal to 0, the second operand is not
 evaluated." In this case, if operand1 != 0, (operand2 && operand3)
 will not be evaluated. This is the behavior of both the C Version 5.10
 and QuickC Version 1.01 compilers. This behavior has been a feature
 of C since the original K & R, and is so handy that many modern
 Pascal compilers now provide this functionality.

 The following example demonstrates this behavior:

 #include <stdio.h>
 int a,b,c,d;
 main() {
     a = (b = 2) || (c = 3) && (d = 4);
     printf("a = %d, b = %d, c = %d, d = %d\n",a,b,c,d);
     }

 The following is an example of output resulting from a program

    a = 1, b = 2, c = 0, d = 0

 Because (b = 2) is not 0, no further evaluations are performed, and c
 and d are not assigned 3 and 4. If the intent is to assign values to
 variables, then separate assignment statements should be made.

 As noted in "The C Programming Language", second edition by Kernighan
 and Ritchie, Page 54, "The moral is that writing code that depends on
 the order of evaluation is a bad programming practice in any
 language."


 184. MKTEMP() Function Example Clarification

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 14-NOV-1988    ArticleIdent: Q37625

 The mktemp() function example in the "Microsoft C Optimizing Compiler
 Run-Time Library Reference" manual is correct. However, it is not
 clear that the following code statements are required:

    strcpy (names[i], template) ;
    result = mktemp(names[i]) ;

 These statements ensure that mktemp() is given the original template
 for each successive call. In the example, the template is defined
 as "fnXXXXXX". The first call to mktemp() will produce a file
 name of "fn000001". If you submit such a filename instead of
 the template, "fnXXXXXX", mktemp() will fail because it is unable
 to generate another unique name.

 The following example demonstrates this behavior:

 /*****************************************************************/
 /* This is the mktemp example in the "Microsoft QuickC Run-Time  */
 /* Library Reference" manual on Page 433. The example copies the */
 /* template to temporary storage so as not to destroy the        */
 /* original template.                                            */
 /*****************************************************************/

 #include <io.h>
 #include <stdio.h>

 char *template = "fnXXXXXX";
 char *result;
 char names[5][9];

 main()
 {
     int i;

     for (i=0;i<5;i++) {
         strcpy(names[i], template);      /* Save the template...   */
         result = mktemp(template);       /* Get another file name. */
         if (result == NULL)
             printf("Problem creating the tempfile");
         else{
             printf("the unique file name is %s\n",result);
             fopen(result, "w");
             }
                        }
 )

 Without the two commented lines in this example, this code fragment
 generates one unique name, then terminates as the pointer "result"
 becomes NULL because mktemp() cannot generate another unique name with
 the template given.


 185. _malloc Should Be malloc in Reference Manual

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  8-NOV-1988    ArticleIdent: Q37626

 The "Microsoft C Optimizing Compiler Run-Time Library Reference"
 manual has a documentation error on Page 410, in the "malloc,
 _fmalloc, _nmalloc" entry. The third paragraph in the Return Value
 section states the following:

    The _malloc and _nmalloc functions...

 It should state the following:

    The malloc and _nmalloc functions...


 186. How errno Is Handled in Multi-Threaded Programs

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-NOV-1988    ArticleIdent: Q37633

 The "Microsoft C for MS OS/2 and MS-DOS Operating Systems: Version 5.1
 Update" manual does not explain how errno is handled in multi-threaded
 programs. The following explains this information.

 In single-threaded programs, errno is a function returning an int, as
 can be observed by looking at the header file errno.h in the default
 include subdirectory. In the multi-thread case, errno is a function
 returning a pointer representing an array (as usual). This array has
 32 entries, one for each thread. OS/2 API routine calls are used to
 manage the assignation of threads to entries in this array. For the
 multi-thread libraries, errno is defined as follows:

  #define errno  *(__errno())

      where __errno is

  int far * far __errno( void );

      so "errno = EDOMAIN;" becomes "*(__errno()) = EDOMAIN;".

 You can determine the behavior at compile time because errno will be
 defined in the multi-thread case, i.e.,  "#ifdef  errno".


 187. Different OS/2 Libraries: DOSCALLS.LIB OS2.LIB API.LIB

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JAN-1989    ArticleIdent: Q37641

 Question:

 What are the differences between DOSCALLS.LIB, OS2.LIB, and API.LIB?

 Response:

 DOSCALLS.LIB has the OS/2 Version 1.00 systems calls in it.

 OS2.LIB is a superset of DOSCALLS.LIB, this library came with the
 OS/2 SDK not with the retail version of C 5.1. It has the OS/2
 Version 1.10 systems calls in it (PM calls have been added to the
 OS/2 Version 1.00 calls).

 API.LIB is the library used for programs that are going to be bound to
 run in both OS/2 and DOS. They are the FAPI ( Family API) routines.

 You can use OS2.LIB in place of DOSCALLS.LIB because it contains all
 of the routines. Only use API.LIB if you are binding.


 188. EMULATOR_TEXT and EMULATOR_DATA Segments in Small Model

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified:  8-NOV-1988    ArticleIdent: Q37664

 Small-model C programs compiled with the floating-point emulator
 library (/FPi or /FPc option) may produce two segments of code and
 data each. If there are floating-point operations in your program, the
 compiler will generate these extra segments. The map file shows these
 segments as EMULATOR_TEXT and EMULATOR_DATA.

 EMULATOR_TEXT is the code segment for the emulator. In some cases,
 small-model programs can have two code segments. Because the code in
 the emulator only is accessed through far calls and interrupts, this
 is not a problem. Both EMULATOR_TEXT and EMULATOR_DATA are in separate
 segments from DGROUP and _TEXT in all memory models.


 189. cl /Fs Filename Fails to Generate Symbol Table on Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  8-NOV-1988    ArticleIdent: Q37665

 When compiling with the /Fs option to produce a source listing, it
 will provide you with tables for global and local symbols. However, if
 the compiler generates error messages, then a list file will not
 contain the symbol tables.


 190. Additional Causes of Error C2152

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QUICKC docerr
 Last Modified: 14-NOV-1988    ArticleIdent: Q37666

 Page 267 of the "Microsoft C 5.1 Optimizing Compiler User's Guide"
 (Page 337 of the "Microsoft QuickC Programmer's Guide") states that
 error C2152 (pointers to functions with different attributes) is
 caused when the following occurs:

    An attempt was made to assign a pointer to a function
    declared with one calling convention (cdecl, fortran, or
    pascal) to a pointer to a function declared with a
    different calling convention.

 This is correct, but incomplete. Additional causes are mixing near
 and far function pointers and mixing interrupt and non-interrupt
 function pointers.


 191. Error C2170 Identifier : Intrinsic Not Declared as a Function

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error docerr
 Last Modified: 14-NOV-1988    ArticleIdent: Q37719

 The error below is from "Compilation-Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.3.2, Page
 268. It is not documented in either the "Microsoft QuickC Compiler
 Programmer's Guide," or in the README.DOC file, for the Microsoft
 QuickC Compiler Versions 1.00 and 1.01.

 The following is the error:

 C2170       identifier : intrinsic not declared as a function

         You tried to use the intrinsic pragma for an item other
             than a function, or for a function that does not have an
             intrinsic form. (The section titled "Generating Intrinsic
             Functions" in Section 3.3.15 lists the functions that have
             intrinsic forms.)

 The section reference given in the error explanation is wrong. It is
 found in Section 3.3.13.1 beginning on Page 93 of the "Microsoft C
 Optimizing Compiler User's Guide."

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.


 192. Error C2172 Function : Actual Is Not a Pointer...

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q37721

 The following error is from "Compilation-Error Messages" in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.2, Page
 339, and from "Compiler and Run-Time Errors -- New Messages" in the
 Microsoft C Optimizing Compiler file ERRMSG.DOC, on Version 5.00's
 Setup Disk and on Version 5.10's Compiler Disk 1, but not in the
 "Microsoft C Optimizing Compiler User's Guide" for those versions:

 C2172       function : actual is not a pointer, parameter number

             An attempt was made to pass a non-pointer argument to a
             function that expected a pointer. The given number
             indicates which argument was in error.

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.


 193. Error C2174 Function : Actual Has Type Void : Parameter...

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q37723

 The following error is from "Compilation-Error Messages" in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.2, Page
 340, and from "Compiler and Run-Time Errors -- New Messages" in the
 Microsoft C Optimizing Compiler file ERRMSG.DOC, on Version 5.00's
 Setup Disk and on Version 5.10's Compiler Disk 1, but not in the
 "Microsoft C Optimizing Compiler User's Guide" for those versions:

 C2174       function : actual has type void : parameter number,
             parameter list number

             An attempt was made to pass a void argument to a function.
             Formal parameters and arguments to functions cannot have
             type void; however, they can have type void * (pointer
             to void). This error occurs in calls that return a pointer
             to a function. The first number indicates which argument
             was in error; the second number indicates which argument
             list contained the invalid argument.

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.


 194. Error C2173 Function : Actual Is Not a Pointer...

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q37724

 The following error is from "Compilation-Error Messages" in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.2, Page
 339, and from "Compiler and Run-Time Errors -- New Messages" in the
 Microsoft C Optimizing Compiler file ERRMSG.DOC, on Version 5.00's
 Setup Disk and on Version 5.10's Compiler Disk 1, but not in the
 "Microsoft C Optimizing Compiler User's Guide" for those versions.

 C2173       function : actual is not a pointer : parameter number :
             parameterlist number

             An attempt was made to pass a non-pointer argument to a
             function that expected a pointer. This error occurs in
             calls that return a pointer to a function. The first
             number indicates which argument was in error; the second
             number indicates which argument list contained the invalid
             argument.

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.


 195. Error C2143 Syntax Error : Missing 'token1' before 'token2'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q37726

 The following error is from "Compilation-Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.3.2, Page
 265, and in the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.1.2, Page 336:

 C2143       syntax error : missing 'token1' before 'token2'

             The compiler expected token1 to appear before token2. This
             message may appear if a required closing brace (}), right
             parenthesis ()), or semicolon (;) is missing.

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.

 This error can occur when a semicolon (;) is missing at the end of a
 function prototype. The following program demonstrates this:

 void foo(void)
 void main(void)
 {
 }

 When this code is compiled, the following errors occur:

 error C2085: 'main' : not in formal parameter list
 error C2143: syntax error : missing ';' before '{'

 With no semicolon to mark the end of the prototype, the compiler
 interprets the prototype as the start of a function definition, and
 the next line to follow the prototype as if it were the first
 declaration within a function definition.


 196. Error C2152 Identifier : Pointers to Functions...

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 14-NOV-1988    ArticleIdent: Q37727

 The following error is from "Compilation-Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.3.2, Page
 267, and in the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.1.2, Page 337:

 C2152       identifier : pointers to functions with different
             attributes

             An attempt was made to assign a pointer to a function
             declared with one calling convention (cdecl, fortran, or
             pascal) to a pointer to a function declared with a
             different calling convention.

 When the compiler encounters any of the errors listed in this section,
 it continues parsing the program (if possible) and outputs additional
 error messages. However, no object file is produced.

 Additional causes for this error include mixing near and far function
 pointers and mixing interrupt and non-interrupt function pointers.


 197. Share Problems Documentation Error for open

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-NOV-1988    ArticleIdent: Q37758

 The important note on Page 446 of the "Microsoft Optimizing 5.1
 Compiler Run-Time Library Reference" manual has an error in the second
 possible work around described in the second paragraph of the note.

 "Another work around is to open the file with pmode set to S_IREAD and
 omode..." is incorrect. The word omode should be replaced with the
 word oflag.


 198. Emulator Math Operations in My DLL that Uses LLIBCDLL

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q37778

 Question:

 I am using LLIBCDLL.LIB for my DLL. This library is supposed to use
 the alternate math package; however, when I compile and link, it
 appears to get emulator instructions in the code and my DLL does not
 act correctly. Where are these emulator instructions coming from, and
 how do I get rid of them?

 Response:

 Most likely the problem is that you are not using the /FPa switch on
 the compile line. You need this switch or the compiler assumes the
 emulator math package (default) and puts emulator math commands in
 your code. When this emulator math code is linked with LLIBCDLL.LIB,
 which uses alternate math, it will not work correctly.


 199. Reading the ESC Key from the Keyboard with _gets

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-NOV-1988    ArticleIdent: Q38023

 When the ESC key is pressed when entering a keyboard string to be read
 with the run-time library function _gets, it clears the keyboard
 buffer, and the only characters that are read by the _gets function
 are those pressed after the ESC key.

 This is a DOS command line feature. The _gets function does not
 receive the input of the command line until the ENTER key is pressed.
 Pressing the ESC key clears the keyboard buffer. If you need to accept
 the ESC key stroke, use the _getc function.


 200. A Case where BUFF

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-NOV-1988    ArticleIdent: Q38024

 When the variable buff has been declared in an assembly-language
 program, such as the following

         .data
         public buff
 _buff   db 200 dup (0xab)
         .data ends

 there is a difference between the two following C declarations:

    extern unsigned char buff[];

    extern unsigned *buff;

 The difference is that the first declaration says that there
 is a block of memory that is named buff; the second says
 that there is something called buff that is a pointer.

 This difference can be seen by referencing buff as follows:

    buff[x]

 If buff is declared as an array, the referencing is correct.

 However, if buff is declared as a pointer, the referencing is
 incorrect. The data pointed to by buff (ab in this example) is
 translated into a memory address, then x bytes is added to it
 generating an incorrect reference.


 201. Signed char Type Converted to int Type at Function Call

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 15-NOV-1988    ArticleIdent: Q38025

 Question :

 Any char value equal to or greater than 0x80 is printed with 0xff
 preceding it when I do the following:

 1. Declare an array of char and initialize it with hexadecimals.

 2. Later in the program, use printf to display the values of the
    array element.

 3. Use "%2x" as format string. (See sample program below.)

 Why does this behavior occur?

 Response:

 Use "unsigned char" to declare the array "bit", or use the /J compiler
 option to change the char type from its default of signed char to
 unsigned char.

 This is not a problem of Microsoft C Compiler. In the sample program
 below, the element of array "bits" has char type, which is a signed
 type in the Microsoft C compiler. In C when a variable is used as an
 actual argument in a function call, usual unary data type conversion is
 automatically performed before the argument is passed to the function.

 In particular, signed char type is converted to int type using sign
 extension (see the "Microsoft C Optimizing Compiler Language
 Reference" manual for data conversion rules.) Because signed char type
 can represent values from -128 to 127 (in our compiler -128 is not
 defined), and a negative value is represented in two's complement form,
 any hexadecimal number greater than 0x80, which is a negative value in
 signed char type, will be converted to signed int type in
 corresponding two's complement form.

 For example, 0x80 (-128) is converted to 0xff80; 0x81 (-127) is
 converted to 0xff81.

 When using "printf" with unsigned hexadecimal integer control
 character "%x", the values are displayed in its unsigned hexadecimal
 format. If "%d" is used, the values are displayed in signed decimal
 format.

 The following is a sample program:

 #include <stdio.h>
 char bits[8] = {0x80, 0x81, 0x91, 0x00, 0x7f, 0x20, 0x40, 0x08} ;
 main()
 {  int i ;
    for (i=0; i<8 ; i++)
       printf("%2x ", bits[i]) ;
    printf("\n") ;
    for (i=0; i<8 ; i++)
       printf("%d ", bits[i]) ;
 }

 Output :
   ff80 ff81 ff91 00 7f 20 08
   -128 -127 -111 0  127 32 8


 202. Minimum Range Values in the Include File limits.h

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 15-NOV-1988    ArticleIdent: Q38026

 Question:

 Why is the minimum value of CHAR and INT off by one in the include
 file limits.h?

 Response:

 This behavior occurs because there is no corresponding positive value
 for the SIGNED CHAR's minimum value. For example, the range of a
 SIGNED CHAR is -128 to 127. The range specified in limits.h is -127 to
 127. The range of a signed int is -32768 to 32767, but limits.h
 specifies the range as -32767 to 32767.

 If you were to take the absolute value of -128 with the ABS() function,
 you would expect to get +128. This is correct; however, you must
 ensure that you store the result in a variable that has a storage
 class that can represent the value.

 For example, it does not make sense, and is not possible, to take the
 absolute value of -128 and try and store it in a SIGNED CHAR. 127 is
 the maximum positive value for a this storage class.

 The return value from the ABS() function is undefined if you try
 to store the result in a storage class that cannot represent the
 value.


 203. Two's Complement

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 16-NOV-1988    ArticleIdent: Q38027

 Question:

 What is two's complement?

 Response:

 In most of the C compilers, including Microsoft C Compiler, negative
 values are represented internally in two's complement format. Two's
 complement can be obtained by negating each bit of the value, then
 adding 1. Performing two's complement twice generates the original
 value.

 The following is an example:

 Original value           | Two's complement
 -------------------------|------------------------------
 (dec)   (hex)  (binary)  | (dec)   (hex)   (binary)
 127     0x7f   01111111  | -127    0x81    10000001
 111     0x6f   01101111  | -111    0x91    10010001
 -111    0x91   10010001  | 111     0x6f    01101111


 204. Turning Off Cursor in Text Mode

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 17-NOV-1988    ArticleIdent: Q38124

 Question:

 How do I turn off the cursor in text mode? I can do it in graphics
 mode but that doesn't work in text mode.

 Response:

 There is no function in the run-time library to do that; however, you
 can do it with a bios function call.

 Use INT 10 FUNCTION 1. Set the CH register to 20h and call the
 interrupt to turn off the cursor. The following is a sample program:

  #include <dos.h>

  void main(void)
  {
      union REGS regs;

      regs.h.ah = 1;
      regs.h.ch = 20;
      int86 ( 0x10, &regs, &regs );

  }


 205. SDK C Documentation Incorrect for memcpy

 Product Version(s): 4.50   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 18-NOV-1988    ArticleIdent: Q38189

 Page 339 of the "Microsoft Operating System/2 Software Development
 Kit/ Microsoft C Optimizing Compiler Run-Time Library Reference"
 incorrectly states that the memcpy function ensures proper copying of
 source bytes to the destination if both regions overlap. Microsoft C
 Optimizing Compiler Versions 4.50 or later do not guarantee that
 source bytes in the overlapping area are copied before being
 overwritten.

 The memcpy function in Version 4.00 of the Microsoft C compiler
 ensures that copying worked for overlapping regions. Starting with the
 Microsoft C Compiler Version 4.50, this was no longer true. The OS/2
 SDK was first released with C Version 4.50 without the new Microsoft C
 run-time library reference documentation. When the OS/2 SDK package
 was updated to C Versions 5.00 and 5.10, the old Microsoft C run-time
 library reference was not updated. The separate retail packages of the
 Microsoft C Optimizing Compiler Versions 5.00 and 5.10 has the new C
 run-time library reference.

 The change was made because ANSI requires that the memmove function,
 not the memcpy function, be used to copy overlapping regions. Because
 no memmove function exists in the Microsoft C Compiler Version 4.00,
 and Microsoft follows ANSI standards, the function memcpy included
 overlapping checking. The added memmove function in C Version 5.00
 prompted the change in the memcpy function. The memmove was added to
 handle overlapping regions while memcpy (the old handler of overlapped
 regions) was implemented as the "fast" copy.


 206. C: _acrtused Must Be Defined When Not Including Start-Up Code

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc acrtused __acrtused ROM
 Last Modified: 26-JAN-1990    ArticleIdent: Q43646

 The object modules created by the Microsoft C Optimizing Compiler,
 Versions 5.10 and earlier, contain a reference to the variable
 _acrtused. This variable causes the linker to bring in the C start-up
 code. To not link the C start-up code, it is necessary to define
 _acrtused as follows:

    int _acrtused = 0;


 207. P_NOWAIT Is Not Implemented in DOS Version 4.00

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-NOV-1988    ArticleIdent: Q38191

 The include file process.h states that P_NOWAIT is enabled in DOS
 Version 4.00. This is incorrect. P_NOWAIT is NOT enabled in the
 current version of DOS Version 4.00. P_NOWAIT is a modeflag as used in
 SPAWNxx functions. P_NOWAIT is used to continue executing the parent
 process concurrently with the child process. P_NOWAIT is implemented in
 OS/2.

 Original DOS Version 4.00 was a multitasking, real-mode only MS-DOS.
 The limitations of the real-mode environment made DOS Version 4.00 a
 specialized product. Although MS-DOS Version 4.00 supports full preemtive
 multitasking, system memory is limited to the 640 kilobytes available
 in real mode. This means that all processes have to fit into the
 single 640-kilobyte memory area. Because of these restrictions, MS-DOS
 Version 4.00 was not intended for general release, but as a platform
 for specific OEMs to support extended architectures. Therefore, MS-DOS
 Version 4.00 was released as a special OEM product only.


 208. Run-Time Functions remove and unlink both Delete a File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 21-NOV-1988    ArticleIdent: Q38198

 The Microsoft C Optimizing Compiler Run-Time Library contains two
 routines that delete a file. The remove function is documented on Page
 490, and the unlink function is documented on Page 628 of the
 "Microsoft C Optimizing Compiler Run-Time Library Reference" manual.
 Both routines take the same argument and perform the same operation.

 The unlink function exists for Unix/XENIX compatibility. This
 information is documented in Sections B.2.1, B.2.3, and B.5.4 of the
 same manual.


 209. Why pointer1++ = pointer2 Is Illegal

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 21-NOV-1988    ArticleIdent: Q38218

 Question:

 Why is the following statement

    pointer1++ = pointer2 ;

 illegal, causing error 2106 : left operand must be lvalue,
 when the following statement is legal?

    *pointer1++ = *pointer2 ;

 Both pointer1 and pointer2 are declared as pointers to the same type.

 Response:

 Because the post-increment operator ++ has higher precedence than the
 assignment operator =, the following statement

    pointer1++ = pointer2 ;

 is equivalent to the following statement:

    (pointer1++) = pointer2 ;

 As defined by the post-increment operation, the result of evaluating
 the expression (pointer1++) is NOT a lvalue. So (pointer1++) cannot
 be used as a left operand of the assignment operator.

 However, a statement such as the following, which is equivalent to
 *(pointer1++) = *pointer2 ;, is legal:

     *pointer1++ = *pointer2 ;

 This statement is legal because although (pointer1++) is not a lvalue,
 it can be used for indirection and *(pointer1++) is a lvalue.

 It is very important to understand the difference between the value of
 the expression (pointer1++) and the value of pointer1. Although
 (pointer1++) has higher precedence in the above statements, the result
 of evaluating (pointer1++) has the old value that pointer1 had before
 the evaluation of the expression (pointer1++). Because of the side
 effect of the post-increment operator, the evaluation of (pointer1++)
 causes the value of pointer1 to be incremented by 1 only after the
 rest of the statement has been evaluated. In other words, as an
 address, (pointer1++) points to the same memory location as pointer1
 used to. Therefore, *pointer1++ or *(pointer1++) represents the same
 object as *pointer1 used to.

 The following example has the effect of assigning "a" to memory
 offset location 0x100, then incrementing ptr1 to point to memory
 offset 0x101:

 char * ptr1 = 0x100; /* ptr1 points to memory offset 0x100
                         in the current data segment
                         for small or medium memory models */
 *ptr1++ = 'a';


 210. /Au Switch Loads DS for Each Function, Not Module

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 21-NOV-1988    ArticleIdent: Q38221

 Page 1 of the the "Microsoft C 5.10 (and 5.00) Quick Reference Guide"
 states the following under the /Au switch:

    "SS not equal to DS; DS loaded for each module"

 This should read as follows:

    "SS not equal to DS; DS loaded for each function"

 This message is correctly noted on Page 154 of the "Microsoft C 5.1
 Optimizing Compiler User's Guide."


 211. Error C1053 Compiler Limit : Struct/union Nesting

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error docerr
 Last Modified: 19-DEC-1988    ArticleIdent: Q38225

 The following error is from "Fatal-Error Messages" in the "Microsoft C
 Optimizing Compiler User's Guide," Section E.3.1, Page 250, and in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.1, Page
 319:

 C1053       compiler limit : struct/union nesting

             Structure and union definitions were nested to more than
             10 levels.

 The error message and explanation given for C1053 in the "Microsoft
 QuickC Compiler Programmer's Guide" is incorrect. It has been switched
 with the message and description for C1027.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.


 212. Error C1015 Cannot Open Include File 'filename'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38266

 The error below is from "Fatal-Error Messages" in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.1.1, Page 315, and in
 the file ERRMSG.DOC found on the Compiler Disk 1 for Microsoft C
 Optimizing Compiler Version 5.10 and on the Setup Disk for Version
 5.00. It is not in the "Microsoft C Optimizing Compiler User's Guide."

 The following is the error:

 C1015       cannot open include file 'filename'

             The given file either did not exist, could not be opened,
             or was not found. Make sure your environment settings are
             valid and that you have given the correct path name for
             the file.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 Some causes of this error include the following:

 1. Incorrectly set environment variables, especially TMP and INCLUDE.
    This error can occur if the INCLUDE environment variable has not
    been set correctly for your include file directory, or if spaces or
    other syntax errors are in the setting.

 2. Improper file handles setting. If the files= line in CONFIG.SYS is
    not high enough, this error will occur. If not set at all, the
    default is usually 8, which is too few. If it is set to greater
    than 20 and the DOS version cannot support that number, it will
    default to 8. File handles will typically be used during
    compilation and linkage by the CL driver, the compiler passes, the
    C source code file, the include files, the linker, libraries, and
    temporary files created by the compiler or linker.


 213. Error C1033 Cannot Open Assembly-Language Output 'filename'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38267

 The following error is from "Fatal-Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.3.1, Page
 247, and in the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.1.1, Page 316:

 C1033       cannot open assembly-language output file 'filename'

             One of the conditions listed under error message C1032
             prevents the given file from being opened.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 The following is the information listed under error message C1032:

    One of the following statements about the file name or path name
    given (filename) is true:

    1.  The given name is not valid.

     2.  The file with the given name cannot be opened for lack of
         space.

    3.  A read-only file with the given name already exists.


 214. Error C1034 Cannot Open Source File 'filename'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38268

 The following error is from "Fatal-Error Messages" in the "Microsoft C
 Optimizing Compiler User's Guide," Section E.3.1, Page 247, and in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.1, Page
 316:

 C1034       cannot open source file 'filename'

             One of the conditions listed under error message C1032
             prevents the given file from being opened.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 The following is the information listed under error message C1032:

             One of the following statements about the file name or
             path name given (filename) is true:

                1.  The given name is not valid.

                2.  The file with the given name cannot be opened for
                    lack of space.

                3.  A read-only file with the given name already
                    exists.


 215. Error C1036 Cannot Open Source Listing File 'filename'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38269

 The following error is from "Fatal-Error Messages" in the "Microsoft C
 Optimizing Compiler User's Guide," Section E.3.1, Page 248, and in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.1, Page
 316:

 C1036       cannot open source listing file 'filename'

             One of the conditions listed under error message C1032
             prevents the given file from being opened.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 The following is the information listed under error message C1032:

    One of the following statements about the file name or path name
    given (filename) is true:

    1.  The given name is not valid.

    2.  The file with the given name cannot be opened for lack of
        space.

    3.  A read-only file with the given name already exists.


 216. Error C1037 Cannot Open Object File 'filename'

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38270

 The following error is from "Fatal-Error Messages" in the "Microsoft C
 Optimizing Compiler User's Guide," Section E.3.1, Page 248, and in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.1.1, Page
 317:

 C1037       cannot open object file 'filename'

             One of the conditions listed under error message C1032
             prevents the given file from being opened.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 The following is the information listed under error message C1032:

    One of the following statements about the file name or path name
    given (filename) is true:

    1.  The given name is not valid.

    2.  The file with the given name cannot be opened for lack of
        space.

    3.  A read-only file with the given name already exists.


 217. Error C1059 Out of Near Heap Space

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 30-NOV-1988    ArticleIdent: Q38271

 The following error is from "Fatal-Error Messages" in (1) the
 "Microsoft C Optimizing Compiler User's Guide," Section E.3.1, Page
 250, and in (2) the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.1.1, Page 319:

 C1059       out of near heap space

 (1)         The compiler has run out of storage for items that it
             stores in the "near" (default data segment) heap. This
             usually means that your program has too many symbols or
             complex expressions. To correct the problem, divide the
             file into several smaller source files, or break
             expressions into smaller subexpressions.

 (2)         The compiler ran out of storage for items that it stores
             in the "near" (default data segment) heap.

 The compiler cannot recover from a fatal error; it terminates after
 printing the error message.

 The following is from "Part 2: Notes for the Microsoft C Optimizing
 Compiler User's Guide" in the README.DOC file on Compiler Disk 1 for
 Microsoft C Version 5.10. A similar section is found in the README
 file on the Setup Disk for Version 5.00.

 This release includes an alternate form of compiler pass 1 named
 C1L.EXE. This compiler pass can be used to compile programs that get
 the error message "out of near heap space". Invoke C1L.EXE by entering
 the CL command with the /B1 <path> option, as follows:

    cl /B1 <path>\c1l.exe <sourcefile>.c

 In the preceding command, <path> is the path (including drive and
 directory) where C1L.EXE resides, and <sourcefile> is the name of the
 C source file you want to compile.


 218. Example Incorrect on Page 373 of C Run-Time Library Reference

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 22-NOV-1988    ArticleIdent: Q38283

 The example for intdosx on Page 373 of the "Microsoft C 5.1 Optimizing
 Compiler Run-Time Library Reference" is incorrect.

 To get the example to work correctly, the line that reads

    char far *dir = "\newdir";   /* Directory to create */

 must be changed to read as follows:

    char far *dir = "\\newdir";  /* Directory to create */

 The backslash character \ in a C string is interpreted as part of an
 escape code. To actually represent the backslash character for a
 file's path, use two consecutive backslashes.


 219. 80386 and 80387 Instruction Set

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | h_fortran s_pascal s_quickc
 Last Modified:  7-DEC-1988    ArticleIdent: Q38284

 Question:

 According to the "Microsoft C 5.1 Optimizing Compiler User's Guide,"
 you can generate 80286 and 80287 instructions with your high-level
 language compilers. Can I also use the 80386 and 80387 instruction
 set?

 Response:

 You can use the 80386 and 80387 chips. However, none of our products
 generate true 80386 code, or use 32-bit addressing. Although our
 compilers do not generate specific 80386 or 80387 code, the code which
 is generated will run faster than on a 80286 and 80287.


 220. Detecting Presence of 80x87 Math Coprocessor

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | SR# G881027-5369 8087 80287 80387 87 /FPc
 Last Modified: 30-NOV-1988    ArticleIdent: Q38285

 Question:

 My Microsoft C program is compiled with the /FPi (floating-point
 emulator) option. I would like to warn the user if they are running it
 on a machine that has no math coprocessor. Is there any way to detect
 if an 80x87 is currently being used by the floating-point libraries?

 Response:

 There is no direct way to query the Microsoft C floating-point
 libraries as to whether or not they're using a math coprocessor. If
 you compile /FPi, you're telling the compiler you don't want to have
 to worry about whether or not a coprocessor is present. Consequently,
 the compiler generates code that will do the following:

 1. Check to see if a 80x87 coprocessor is present.

 2. If so, use it.

 3. If not, emulate it with software routines.

 There is nothing in this algorithm to tell your program what it found.
 The only way you'll know it's emulating the coprocessor is by
 observing how slowly your program runs.

 If you really need to know whether a coprocessor is present, you'll
 have to test it yourself. For more information on how to test for the
 presence of an 80x87 coprocessor, please consult Intel's "80286 and
 80287 Programmer's Reference Manual," Pages 3-2 and 3-3 (in the 2nd
 half of the book). This section is titled "System-Level Numeric
 Programming," and states that your program can detect the presence of
 the 80287 NPX. It then gives an assembly-language example that works
 correctly for both 8086- and 80286-based machines.

 Here is how you could use this routine in your program:

 1. During initialization of your program, call the short Intel routine
    to see if a coprocessor is present.

 2. If there is a coprocessor, proceed normally.

 3. If there is no coprocessor, put up a message box explaining the
    following to the user:

    "Your computer lacks a coprocessor, but <my_app> will emulate it in
    software; this emulation will slow down the calculations that
    <my_app> needs to perform. To increase the performance of
    <my_app>, as well as other programs, add a numeric coprocessor to
    your system."

 4. Proceed with your program as you normally would. The C run-time
    libraries will automatically adjust for the presence or lack of a
    80x87.


 221. Cannot Define Preprocessor Directives with #define

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 28-NOV-1988    ArticleIdent: Q38291

 The Microsoft C Compiler does not allow a "#define" statement to
 define another preprocessor directive. Although the preprocessor
 output option ( /P or /E ) generates the desired expansion, the
 Microsoft C Compiler Version 5.10 generates the following error
 messages when compiling the code below:

    error C2014: preprocessor command must start as first non-whitespace
    error C2054: expected '(' to follow 'define'
    error C2061: syntax error : identifier 'MAX'

 The following code demonstrates the problem:

 #define A( x )      x##define       MAX     100

 A( # )
 /*
     Preprocessor output expands A( # ) to be:
 #define       MAX     100
 */

 char w[ MAX ];
 void main(void);
 void main()
 {
 w[ 0 ] = w[ MAX ];
 }


 222. wait and cwait Are for Protected Mode

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  7-DEC-1988    ArticleIdent: Q38293

 Page 556 of the "Microsoft C 5.1 Optimizing Compiler User's Guide"
 states that to obtain the exit code for an asynchronous spawned
 process, you must call the wait or cwait function and specify the
 process ID.

 Wait, Cwait, and asynchronous spawns can only occur in protected mode.

 The wait function suspends the calling process until any of the
 caller's immediate child processes terminate. If all of the caller's
 child processes have terminated before it calls the wait function, the
 function returns immediately.

 The cwait function suspends the calling process until the specified
 child process terminates.

 For more information, refer to the "Microsoft C 5.1 Optimizing
 Compiler User's Guide" Update Pages 30 and 48.


 223. Overwriting End of HALLOC Causes Crash at Termination

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 12-DEC-1988    ArticleIdent: Q38294

 The following message appearing at the termination of a program can be
 caused by overwriting past the end of a block of memory allocated by
 the halloc function:

    Memory allocation error: Cannot load command.com

 The bytes following a halloc'd block are used by DOS for keeping
 track of memory allocation, and DOS may be unable to load command.com
 upon completion of your process if this area is corrupted.

 This error can also conceivably be caused by overwriting blocks of
 memory allocated by other functions such as malloc, _nmalloc, and _fmalloc.


 224. How the Null Character Is Handled by Printf Functions.

 Product Version(s): 4.00 5.00 5.10 | 4.00 5.00 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 28-NOV-1988    ArticleIdent: Q38296

 When the C run-time functions printf, fprintf, or sprintf encounter
 the character-conversion specifier %c in their format-control string,
 they will convert the corresponding argument of int type to unsigned
 char type and write the resulting value to output. Therefore, if the
 argument is a NULL character, the value 0 (not the character "0") is
 written to the output.

 The output can be stdout, a file (with fprintf) or a string (with
 sprintf). In case of stdout, the NULL character is ignored by the
 display device. In the case of string, the NULL character will be
 interpreted as a terminator character when the resulting string is
 used later in the program.

 The output of the following program is the result of expected
 behavior:

 #include <stdio.h>
 char buffer[30] ;
 main()
 {
 printf("Before,%c,After\n", '\0') ;
 sprintf(buffer, "Before,%c,After\n", '\0') ;
 printf(buffer) ;
 }
 /* end of sample program */

 Output :

 Before,,After
 Before,


 225. Spawn Will Not Pass Redirection to Child

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S880925-1
 Last Modified: 12-DEC-1988    ArticleIdent: Q38308

 Question:

 When using the program below to spawn sort.exe, it seems that "sort"
 starts, but then sits there doing nothing. The behavior is similar to
 starting "sort" from the DOS prompt without any arguments.

 The following program demonstrates the problem:

 #include <stdio.h>
 #include <process.h>
 main()
 {
         char *args[6] ;
         args[0] = "sort" ;
         args[1] = "<" ;
         args[2] = "infile.dat" ; /* exists */
         args[3] = ">" ;         /* direct output to a disk file */
         args[4] = "outfile.dat" ;
         args[5] = NULL ;

         spawnvp (P_WAIT, "sort.exe", args) ;
 }

 Why doesn't this work correctly? What can I do about it?

 Response:

 Because COMMAND.COM, and NOT the EXEC loader, handles indirection,
 this is the expected behavior. Child processes inherit the handles of
 their parents; therefore, to redirect the input and output of the
 child you first change the definitions of STDIN and STDOUT in the
 parent process. The proper way to redirect input for a filter is
 described starting on Page 441 of the "MS-DOS Encyclopedia," along with
 a complete MASM example. Note: the dup and dup2 functions in the C
 Version 5.10 run-time library are the same as the INT 21h functions 45h
 and 46h, respectively.

 There also are partial examples of this technique on Page 230 of the
 "Microsoft C Version 5.10 Run-Time Library Reference" manual and on
 Page 353 of "Advanced MS-DOS Programming" (by Duncan, published by
 Microsoft Press).

 It is possible to use freopen() to redefine STDIN and STDOUT; however,
 doing so loses any redirection that may have been performed on the
 parent process.

 The easiest workaround is to use the system function to spawn a copy
 of COMMAND.COM that runs SORT.EXE, as follows:

    system("sort.exe <infile.dat >outfile.dat");


 226. Attributes in Hercules Graphics Mode

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 19-DEC-1988    ArticleIdent: Q38312

 Problem:

 I'm using a Hercules graphics adapter in graphics mode and I would
 like to do high-intensity "bold" graphics, but I can't seem to get it
 to work correctly.

 Response:

 Using the Hercules graphics adapter in graphics mode, each pixel maps
 to only 1 bit in memory. Because there is only 1 bit, that pixel can
 only be on or off. In Hercules graphics mode, there is no facility for
 attributes such as high-intensity, blinking, reverse, or underline.

 In Hercules graphics mode, the only way to get blinking, reverse, and
 underline is for your program to manipulate or turn on and off each
 pixel. High-intensity will not be possible.

 If you put the adapter into Text mode, you can use all of these
 attributes freely.


 227. C Setup Gives Error U2155 When Building Libraries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_LIB
 Last Modified: 15-JAN-1990    ArticleIdent: Q38319

 Problem:

 When installing Optimizing C, I get the following error:

    LIB : error U2155: <path> : module not in library; ignored

 Response:

 Most likely, this is caused by having a dash (-) embedded in the path
 specified as the combined libraries destination. Restart SETUP and do
 not include a dash in the library path.

 This is a problem with LIB.EXE.

 LIB cannot handle the "-" (hyphen, dash) character embedded in a
 directory/file name. Instead, it interprets the dash as the extraction
 operator giving rise to error U2155. The hyphen is a legal character
 for DOS file and directory names and many people use it (for example,
 MS-C for the C directory.) In this example, LIB will terminate with
 the following cryptic message:

    U2155:   C:\MS-C\MLIBCE.LIB  module not in library (ms.obj)

 The message is dependent upon the directory/file name used, but the
 symptom is always the same: module not in library, invalid object
 module, object file not found, etc.

 Note: this error can occur in situations other than setting up the
 compiler. Anytime you pass a directory/file name that contains a
 hyphen, you can cause this behavior.


 228. _Fheapwalk Does Not Check the Near Heap

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-NOV-1988    ArticleIdent: Q38327

 The HeapWalk routines are provided as an aid in debugging heap-related
 problems in programs. In large-, huge-, and compact-memory models
 _heapwalk will map onto the function _fheapwalk. In small- and
 medium-memory models, it maps onto function _nheapwalk. The _fheapwalk
 function will not check or examine the near heap in the default data
 segement while _nheapwalk will examine only the near heap.

 Because _fheapwalk will not check the near heap, you should not assume
 that the HeapWalk routine will always reflect information about all
 your pointers when you are using compact-, large- and huge-memory
 models. This is because in these models, malloc will draw upon the
 far heap until it is exhausted, then turn to the near heap. In this
 case, it is possible to have valid pointers but _fheapwalk will not
 acknowledge them.

 For this reason, you should not assume that _fheapwalk will provide
 information about all your pointers, or you should use both _fheapwalk
 and _nheapwalk to check both the near heap and the far heap.


 229. C 5.10 Doesn't Implement Multibyte Integer Character Constants

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 28-NOV-1988    ArticleIdent: Q38328

 Page 28 of the ANSI C draft proposal X3J11/88-001 describes an integer
 character constant as being a sequence of one or more multibyte
 characters enclosed in single quotation marks, e.g. 'a' or 'ab'.

 Page 21 of the "Microsoft C 5.1 Optimizing Compiler Language
 Reference Guide" states that an integer character constant
 is formed by enclosing a single character from the representable
 character set within single quotation marks. It makes no reference to
 multibyte character constants (e.g. 'ab'). If a source file has the
 character constant defined as follows, the error "C2015: Too many
 chars in constant" is generated:

    int ch = 'ab';

 This error is correct, because Microsoft C Version 5.10 does not
 implement multi-character integer character constants.  Note that
 page 29 of the draft standard says that such constructions are
 "implementation-defined."


 230. sscanf Example Using a Comma (,) as Delimiter

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 12-DEC-1988    ArticleIdent: Q38335

 The example below shows how to use the sscanf C Run-Time function
 to read from an internal buffer delimiting fields with a comma (,).
 The key is to use the brackets in the format of sscanf function. The
 format would be %[^','], which tells the function to read from the
 buffer until a comma (,) is reached.

 The following is a C source example illustrating the use of brackets
 and the caret (^):

 #include <math.h>
 #include <stdio.h>

 char *tokenstring = "first,25.5,second,15";
 int result, i;
 double fp;
 char o[10], f[10], s[10], t[10];

 main()
 {
  result = sscanf(tokenstring, "%[^','],%[^','],%[^','],%s", o, s, t, f);
  fp = atof(s);
  i  = atoi(f);
  printf("%s\n %lf\n %s\n %d\n", o, fp, t, i);
 }


 231. Shared and Instance Segments in a DLL

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G881019-4906 -ND SINGLE S_LINK
 Last Modified: 24-JAN-1990    ArticleIdent: Q38714

 Question:

 How can I get both shared and instance data in a DLL? I'd like to have
 the default data segment (DGROUP) and most of the far segments to be
 instance data and a single far data segment to be shared data. I've
 tried to do this by doing the following:

 1. Isolating the data for the far segment in fardata.c and compiling
    it with -NDSEG1

 2. Linking with a .DEF file that contains the following:

     DATA    MULTIPLE NONSHARED
         SEGMENTS
                 SEG1 CLASS 'FAR_DATA' SHARED

 When I do this, ALL data segments (including SEG1) are instance; I
 determined this from both my test program and the output of the exehdr
 utility.

 How can I make the SEG1 segment shared?

 Response:

 Every time you use /NDSEG1 option compiler will generate the
 following segment definitions:

         SEG1        class   'FAR_DATA'
         SEG1_CONST  class   'FAR_DATA'
         SEG1_BSS    class   'FAR_DATA'
         GROUP SEG1_GROUP SEG1, SEG1_CONST, SEG1_BSS

 SEG1, SEG1_CONST, and SEG1_BSS are all members of the same group
 (physical segment). (SEG1_CONST AND SEG1_BSS are created automatically
 by the compiler, as is the group SEG1_GROUP.) The linker overrides the
 SEGMENTS specification if ANY of the segments in the group are left at
 the default. The solution is to ask the linker to share ALL of the
 segments in the group. In your case, insert the following into the
 .DEF file:

 DATA MULTIPLE NONSHARED
 SEGMENTS
         SEG1         CLASS 'FAR_DATA' SHARED
         SEG1_CONST   CLASS 'FAR_DATA' SHARED
         SEG1_BSS     CLASS 'FAR_DATA' SHARED

 Note: if the segment(s) you want to share are part of a group, you
 must set ALL of the segments in the group to be shared or NONE will
 be.


 232. Finding Out what Video Adapters Are Installed and Active

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | video display monitor color monochrome black white b/w mono
 Last Modified: 14-DEC-1988    ArticleIdent: Q38726

 Question:

 I am writing a program that has to determine what adapter boards are
 installed in a machine. In addition, it must also determine which
 board is active. How can I use the functions supplied with C to get
 this information?

 Response:

 There is no way using the functions we supply to find out what type of
 video adapters are installed in your system. There is, however, a
 book entitled "Programmer's Guide to PC & PS/2 Video Systems,"
 published by Microsoft Press, which has an appendix that has a MASM
 example of finding out what adapters are installed. (This example
 could be translated into C.)

 However, even if you write code to find out what adapters are
 installed, there is no simple way to tell the graphics library to
 use an adapter other than the one it wants to use. The library will
 pick an adapter according to the following rules:

 1. If there is a VGA in the system, it uses it regardless of what
    other adapters are installed and regardless of what adapter is
    currently the default adapter. The only way to change this is to
    hook the BIOS INT 10h interrupt as described below.

 2. If there is no VGA, it uses the current adapter. This can be set
    with the MODE command in DOS before you start your program.

 If you hook INT 10h, you can change the behavior with the VGA to pick
 the current adapter. The _setvideomode function makes a call to INT
 10h function 1Bh to determine whether a VGA is installed or not. You
 can write code to change the return value if the VGA is not the
 current adapter, leaving it alone if the VGA is the current adapter.

 The _getvideoconfig function only gives information on the current
 video mode, as set by _setvideomode. It is not helpful for finding out
 what adapters are installed in your system.

 You can find out what adapter the library would use by making calls to
 _setvideomode. If the mode cannot be selected, _setvideomode will
 return zero. For example, if you tried to select a VGA mode and
 _setvideomode returned zero, you would know that no VGA was present in
 the system. You then could attempt to select an EGA, etc.


 233. Initializing Large Character Arrays

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881128-6987
 Last Modified: 16-JAN-1989    ArticleIdent: Q38728

 Question:

 How can I initialize an array of characters larger than 512 bytes?
 When I try initializing using a character string literal, as follows,

     char a[] = " *** 1000 characters *** ";

 I get the following compiler message:

     Warning C4009: string too big, trailing chars truncated

 Response:

 One method of initializing character arrays is to use a character
 string literal. The minimum limit allowed by ANSI for a characters
 string literal after concatenation is 509 characters. The limit in
 Microsoft C is 512 characters. Because the limit on the length of a
 string literal is 512 characters, you cannot initialize character
 arrays longer than 512 bytes with this method.

 The following won't work correctly either because the compiler treats
 these as a single string literal rather than specially as an
 initializer:

 char stuff[] =
         "xxx...xxx"
             ...
         "xxx...xxx";

 (The ANSI standard says that strings separated only by white space are
 automatically concatenated.)

 There are, however, a few other methods you can use that will work
 successfully, such as the following:

 char stuff [] =
         { 'a', ...
                ...
           ... 'z' };

 However, such an initializer is no fun to type. If you decide to use
 this method, you might want to write a program that will read a data
 file and output the proper initializer.

 You might also want to try the following:

 char stuff[][10] =  {
         "0123456789",
                 ...
         "0123456789"  };

 The value 10 is not important EXCEPT that it must match the actual
 length of the string constants. If any of the constants are shorter
 than the length you specify, the end of that row will be padded out
 with zero bytes. If any are longer, the extra characters will be
 thrown away. You can use another pointer to access the following in
 almost any method you want:

    char *stuffptr = (char *) stuff;

 This method seems to be the most convenient.

 You can also define the array in MASM and link it to your C
 program. In MASM, once you've done the correct segment and public
 definitions, you could write the following:

 stuff   db      "abcdefghijkl"
         db      "morestuff"
         ...
         db      "laststuff"

 In C, you could access the array with the following:

 extern char stuff[];   /*    char * stuff;   will NOT work    */

 Finally, you could read the values into the array at run-time from a
 data file. If you read the file in large blocks, (e.g. using read or
 fread) you'll find that the I/O is quite fast.


 234. Mixing Old Declarations with Prototypes Causes Passing Errors

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881107-5854
 Last Modified: 12-DEC-1988    ArticleIdent: Q38729

 Question:

 It is my understanding that both of the following functions should
 produce identical results:

 float AAA(float x1, float x2)
 {
     x1 = x2;
 }

 float BBB(x1,x2)
 float x1,x2;
 {
     x1 = x2;
 }

 However, they don't. Looking at the code, I see that in BBB, the two
 parameters are treated as double instead of float. When I compile with
 the /Zg switch, which generates function prototypes, the following
 prototypes are generated:

 extern  float AAA(float x1, float x2);
 extern  float BBB(double x1, double x2);

 Why is this behavior occuring?

 Response:

 The following is from the May 5, 1988 ANSI draft, Section 3.3.2.2:

 "If the expression that denotes the called function has a type that
 does not include a prototype...arguments that have type float are
 promoted to double.

 "If the expression that denotes the called function has a type that
 includes a prototype, the arguments are implicitly converted, as if
 by assignment, to the types of the corresponding parameters."

 For AAA, you're using the new function definition style. Note that if
 you call this function (perhaps in another module) without a prototype
 in scope, you'll have problems because you'll pass doubles rather than
 floats (see first paragraph above).

 BBB uses the old style of definition as described in K & R. Because
 K & R specified that the floats are to be widened to doubles when
 they're passed to functions (and in a variety of other situations
 as well), the old style declarations maintain the old semantics.

 Therefore, the /Zg switch is correctly generating the function
 prototypes.

 Your program wouldn't run when you declared the following prototype
 before calling BBB because the prototype that was in scope when you
 CALLED BBB did not match the implicit prototype generated when the
 function was defined:

    void BBB(float, float);

 As a result, you passed floats to a function that was expecting
 doubles.


 235. Changing Default int to 32 Bits

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: END-USER | SR# G881110-6126
 Last Modified: 12-DEC-1988    ArticleIdent: Q38730

 Question:

 I am porting a VERY large C program from another C compiler to OS/2.
 In the other compiler, the type int is defined as being the same as
 long (i.e., 32 bits). In Microsoft C, int is defined as being the same
 as short (i.e., 16 bits).

 Is there a compiler switch to change int to long rather than short?

 Response:

 There's no compiler switch that changes the default int to long rather
 than short. If you included a "typedef long int;" or a "#define int
 long" in each and every module you compiled, you would take care of
 some of the problems. However, redefining the identifier "int" is
 likely to cause you severe and difficult-to-find problems. We
 emphatically do NOT recommend it.

 Note: K & R and ANSI are both very clear that int could be any size,
 provided that it's at least 16 bits. It is bad coding practice to rely
 on 32-bit ints because it makes porting code difficult.

 Changing all int variables to long causes your program to run very
 slowly because whenever it does arithmetic, it will have to do slower
 32-bit arithmetic rather than the more efficient built-in 16-bit
 arithmetic. This situation is true even on 80386 processors because
 current versions of our compilers do not support the generation of
 code that takes advantage of the 80386's 32-bit registers.

 A far better strategy is to change only the variables that need to be
 long to long. This way, you will avoid a lot of unintended side
 effects and you will not do more 32-bit arithmetic than is necessary.


 236. Overflow in Integer Math Expressions Not Checked

 Product Version(s): 4.00 5.00 5.10  | 5.10
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 12-DEC-1988    ArticleIdent: Q38733

 The operations performed by the integer arithmetic and shift operators
 do not check for overflow or underflow conditions. Information may be
 lost if the result of an operation cannot be represented in the type of
 the operands after conversion. All expressions are evaluated prior to
 assignment to a variable.

 Rules for numeric conversion are described on Page 115 of the
 "Microsoft C Language Reference" manual.

 The following example demonstrates the overflow condition:

 #include <stdio.h>
 void main(void);
 void main()
 {
 long l;

     l = 70 * 1000;              /* First Example            */
     printf( "l = %ld\n", l );   /* l = 4464 = 70000 % 65536 */
                                 /* Overflow not caught!!!   */

     l = 70L * 1000;             /* Second Example           */
     printf( "l = %ld\n", l );   /* l = 70000                */
                                 /* arithmetic in long--no   */
                                 /*   overflow               */
 }

 In the first example, 70 and 1000 are considered as integers. Because
 both are integer types, integer math is being performed. Integers can
 have at most a value of 32,767. When 70 is multiplied to 1000, the
 product exceeds the maximum value that an integer can hold. Overflow
 is not checked and information is lost. Thus we get a value of 4464,
 which is 70,000 mod 65,536.

 The workaround is the second example. Conversions occur if the types
 of the operands are different. Because 70 is a long integer (32 bits.
 Without the L, it is considered a normal integer of 16 bits). Because
 a long integer is used, all operands will be converted to long and the
 math will be done using 32-bit arithmetic. The product is large enough
 to handle the multiplication, so the correct result of 70,000 is
 generated.


 237. Viewing Array Elements in CodeView

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 12-DEC-1988    ArticleIdent: Q38735

 Question:

 In CodeView, why am I unable to view elements of an array with an
 index of type char in my C program? Whenever I do so, I get the
 following error:

    "operand types incorrect for this operation"

 Response:

 Using a char variable to index an array is only valid in the C
 language. As CodeView supports multiple languages, it does not allow
 a char variable to index into an array, even if the program is written
 in C.

 For a workaround to view elements of an array indexed by a variable of
 type "char", you need to cast the variable to an int type in
 CodeView's Dialog Box as follows:

    > ? buffer[(int)i]

 The following code sample demonstrates the situation:

 #include <stdio.h>
 main()
 {
    int  j = 5;
    char i = 5;
    char buffer[10];

    scanf("%s",buffer);

 }

 When the above program is loaded, CodeView allows you to view
 the fifth element of the array with the following commands:

    > ?buffer[5]

    > ?buffer[j].

 However, the following command causes the error: "operand types
 incorrect for this operation":

    > ?buffer[i]


 238. Error L1006 Option : Stack Size Exceeds 65535 Bytes

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error docerr
 Last Modified:  7-DEC-1988    ArticleIdent: Q38769

 The following error is from "Linker Error Messages" in (1) the manual
 "CodeView and Utilities," Section C.2, Page 360, and in (2) the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.4, Page 365:

 (1)
 L1010       option : stack size exceeds 65536 bytes

             The size specified for the stack in the /STACK option of
             the LINK command was more than 65,536 bytes.

 (2)
 L1006       option : stack size exceeds 65535 bytes

             The size specified for the stack was more than 65,535
             bytes.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 The documentation of the error in the "CodeView and Utilities" manual
 is incorrect. The error number should be L1006, not L1010. The upper
 limit of the stack as given in both the error message and its
 description should be 65535, not 65536. The QuickC manual is correct.

 This error is documented in the files ERRMSG.DOC for Microsoft C
 Version 5.10, README.DOC for Microsoft Macro Assembler Version 5.10,
 CVREADME.DOC for Microsoft FORTRAN Version 4.10, and README.DOC for
 Microsoft Pascal Version 4.00, but the description given has a
 documentation error. The error is given as:

   L1006   <option-text>: stack size exceeds 65535 bytes

   The value given as a parameter to the /STACKSIZE option exceeds
   the maximum allowed.

 The option /STACKSIZE is wrong. The LINK option to change the stack is
 either /STACK or /ST. Specifying /STACKSIZE will generate the error:

    LINK : fatal error L1002: STACKSIZE : unrecognized option name


 239. Error L1081 Out of Space for Run File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38790

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities," Section C.2, Page 364, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 369:

 L1081       out of space for run file

             The disk on which the .EXE file was being written was
             full.

             Free more space on the disk and restart the linker.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.


 240. Error L1087 Unexpected End-of-File on Scratch File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38795

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities," Section C.2, Page 364, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 370:

 L1087       unexpected end-of-file on scratch file

             The disk with the temporary linker-output file was
             removed.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 This error can be caused by insufficient space on the disk (hard,
 floppy, or RAM) where the temporary file is being written.


 241. Error L2002 Fixup Overflow Near Number...

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38806

 The L2002 error below is from "Linker Error Messages" in the manual
 "CodeView and Utilities," Section C.2, Page 366, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 372.

 The following is the error:

 L2002       fixup overflow near number in frame seg segname target seg
             segname target offset number

             The following conditions can cause this error:

             A small-model program is compiled with the /NT option.

             A group is larger than 64K.

             The program contains an intersegment short jump or
             intersegment short call.

             The name of a data item in the program conflicts with
             that of a subroutine in a library included in the
             link.

             An EXTRN declaration in an assembly-language source
             file appeared inside the body of a segment, as in the
             following example:

                 code   SEGMENT public 'CODE'
                        EXTRN   main:far
                 start  PROC    far
                        call    main
                        ret
                 start  ENDP
                 code   ENDS

                 The following construction is preferred:

                        EXTRN   main:far
                 code   SEGMENT public 'CODE'
                 start  PROC    far
                        call    main
                        ret
                 start  ENDP
                 code   ENDS

             Revise the source file and recreate the object file. (For
             information about frame and target segments, refer to the
             "Microsoft MS-DOS Programmer's Reference.")

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

    location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 Force data outside of DGROUP by using the /Gt compiler switch along
 with a large data model (compact, large, or huge).

 Using the linker switch /CO twice can cause this. For example, when
 LINK is invoked with /CO when a LINK environment variable is also set
 to /CO, then this situation results.


 242. Error L1070 Segment Size Exceeds 64K

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified: 12-JAN-1989    ArticleIdent: Q38807

 The following error is from "Linker Error Messages" in (1) the manual
 "CodeView and Utilities," Section C.2, Page 363, and in (2) the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.4, Page 369:

 (1)
 L1070       segment size exceeds 64K

             A single segment contained more than 64K of code or data.

             Try compiling and linking using the large model.

 (2)
 L1070       name: segment size exceeds 64K

             The specified segment contained more than 64K of code or
             data.

             Try compiling and linking using the large model.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 Use a large data model (compact, large, or huge). Try applying the /Gt
 compilation option to lower the threshhold.


 243. Error L1072 Common Area Longer than 65536 Bytes

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified: 12-JAN-1989    ArticleIdent: Q38808

 The following error is from "Linker Error Messages" in (1) the manual
 "CodeView and Utilities," Section C.2, Page 364, and in (2) the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.4, Page 369:

 L1072       common area longer than 65536 bytes

 (1)         The program had more than 64K of communal variables. This
             error cannot appear with object files generated by the
             Microsoft Macro Assembler, MASM. It occurs only with
             programs produced by the Microsoft FORTRAN or C Compilers
             or other compilers that support communal variables.

 (2)         The program had more than 64K of communal variables. This
             error cannot appear with object files generated by the
             Microsoft Macro Assembler, MASM. It occurs only with
             programs produced by the Microsoft QuickC Compiler or
             other compilers that support communal variables.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 Use a large data model (compact, large, or huge). Try applying the /Gt
 compilation option to lower the threshhold.


 244. Error L1085 Cannot Open Temporary File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38809

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities," Section C.2, Page 364, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 370:

 L1085       cannnot open temporary file

             The disk or the root directory was full.

             Delete or move files to make space.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 This error can be caused by insufficient file handles. Resident
 software (TSR) can use up some handles, or can cause other kinds of
 interference that can cause this error.


 245. Error L1089 Filename : Cannot Open Response File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified: 11-JAN-1990    ArticleIdent: Q38810

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities," Section C.2, Page 365, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 370:

 L1089       filename : cannot open response file

             LINK could not find the specified response file.

             This usually indicates a typing error.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

    location : fatal error L1xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 Also, check the TMP environment variable setting and/or TSR's.


 246. Error L2029 Unresolved Externals

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified: 11-JAN-1990    ArticleIdent: Q38818

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities", Section C.2, Page 368, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 373:

 L2029       unresolved externals

             One or more symbols were declared to be external in one or
             more modules, but they were not publicly defined in any of
             the modules or libraries. A list of the unresolved
             external references appears after the message, as shown in
             the following example:

             EXIT in file(s):
              MAIN.OBJ (main.for)
             OPEN in file(s):
              MAIN.OBJ (main.for)

             The name that comes before in file(s) is the unresolved
             external symbol. On the next line is a list of object
             modules that have made references to this symbol. This
             message and the list are also written to the map file, if
             one exists.

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

    location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 This linker error message means that a reference to a function or
 procedure was made, but the actual routine to that reference was never
 found (in either a library or in another object module). This message
 is not in regards to inclusion or exclusion of include files in a C
 program. (Include files in a C program usually do not contain
 functions, but rather function prototypes.) If this error message
 should occur, check the following:

 1. Make sure the command line used to invoke the linker or the
    compiler/linker is correct.

 2. Check that you have specified all libraries that are needed by
    the program (e.g. graphics.lib, a third-party library).

 3. Check the spelling of the procedure or function name in the
    program and make sure it corresponds to how the function is
    actually declared.

 4. Make a listing of the libraries that are being linked with to
    see if the missing procedure or function is indeed in the library.
    This process will require the use of LIB.EXE.

 5. If you are in QuickC and this message occurs, check to see if
    the function that is being called is contained in the core library.
    If it isn't, you need to set a Program List in the QuickC editor.

 6. Check the name that the linker can't resolve. If the name is
    preceded by two underscores, then most likely it is either an
    internal routine for startup or other internal functions or the
    library was built with an incorrect version of LIB.

 Make sure a main() has been declared and/or a function in C wasn't
 preceded with an undesired underscore. This error can also occur if a
 C program is being mixed with an assembler routine and the assembler
 routine was not assembled with the /MX and /ML options to preserve the
 case of the functions, or the function in the assembler program didn't
 have an underscore in front of its name to make it compatible with the
 C naming convention.


 247. Error L2041 Stack Plus Data Exceeds 64K

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38819

 The error below is from "Linker Error Messages" in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 374. It is also
 in the file ERRMSG.DOC on Compiler Disk 1 for Microsoft C Version 5.10
 and on the Setup Disk for Microsoft C Version 5.00, and in the file
 README.DOC on Disk 1 for Microsoft Macro Assembler Version 5.10, and
 in the file CVREADME.DOC on the CodeView for MS-DOS disk for Microsoft
 FORTRAN Version 4.10. It is not found in the manual "CodeView and
 Utilities."

 The following is the error:

 L2041       stack plus data exceeds 64K

             The combined size of the program stack segment plus DGROUP
             was greater than 64K; as a result, the program will not
             load up correctly.

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

    location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 To correct the problem, do the following:

 1. Reduce the stack size.

 2. Use a large data model (compact, large, or huge). Try applying the
    /Gt compilation option to lower the threshhold.

 3. Use the FAR keyword to move data out of DGROUP.


 248. Error L2025 Name : Symbol Defined More than Once

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified:  7-DEC-1988    ArticleIdent: Q38820

 The following error is from "Linker Error Messages" in the manual
 "CodeView and Utilities", Section C.2, Page 368, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.4, Page 373:

 L2025       name : symbol defined more than once

             Remove the extra symbol definition from the object file.

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

    location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.

 One way this error can be caused is by incorrectly using or omitting a
 keyword such as pascal. If the included function prototype has the
 keyword and the library routine does not, or vice versa, the linker
 reports that the function is defined more than once.


 249. %TMP% in NEW_VARS.BAT Causes Fatal Error C1042

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran
 Last Modified: 12-DEC-1988    ArticleIdent: Q38839

 If you append new_vars.bat to your AUTOEXEC.BAT and your TMP
 environment variable is already set for specifying the drive,
 directory compiler, and linker to which temporary files should be
 written, %TMP% causes the following error message:

    Fatal-Error C1042: cannot open intermediate file -- no
                       such file or directory.

 This message occurs because the TMP variable should specify only one
 directory.

 %TMP% appends any TMP directories already defined at that location.
 Generally, it is best not to have any %<environmental variable>%
 symbols in AUTOEXEC.BAT because it should be the first place the
 environment is defined.


 250. Error L1126, Error L2043

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_link s_error
 Last Modified: 19-DEC-1988    ArticleIdent: Q38979

 The information below describes linker-error messages L1126 and L2043.

 The following error is from "Linker Error Messages" in (1) the manual
 "CodeView and Utilities", Section C.2, Page 366, and in (2) the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.4, Page 374.
 It is also in (3) the file ERRMSG.DOC on Compiler Disk 1 for Microsoft
 C Version 5.10 and on the Setup Disk for Microsoft C Version 5.00,
 also in the file README.DOC on Disk 1 for Microsoft Macro Assembler
 Version 5.10, also in the file CVREADME.DOC on the CodeView for MS-DOS
 disk for Microsoft FORTRAN Version 4.10:

 (1)
 L1126       starting address __aulstart not found

             You tried to create a Quick library without linking with
             the required LIB library.

 (2)
 L2043       starting address __aulstart not found

             When you build a Quick library using the /Q option, the
             linker expects to find the symbol __aulstart defined as a
             starting address.

 (3)
 L2043       Quick Library support module missing

             When creating a Quick library, you did not link with the
             required QUICKLIB.OBJ module.

 Fatal errors cause the linker to stop execution. Fatal error messages
 have the following format:

 location : fatal error L1xxx: messagetext

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

 location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an OBJ
 or LIB file and has a module name, the module name is enclosed in
 parentheses.


 251. Error U1188 Cannot Write to VM

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_util s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39018

 The information below describes library-error message U1188.

 The following error is from "LIB Error Messages" in (1) the manual
 "CodeView and Utilities", Section C.3, Page 373, and in (2) the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.5, Page 379:

 U1188       cannot write to VM

 (1)         Note the circumstances of the failure and notify Microsoft
             Corporation by using the Product Assistance Request form
             at the back of one of your manuals.

 (2)         Note the circumstances of the failure and notify Microsoft
             Corporation, using the Product Assistance Request form at
             the back of this manual.

 IMPORTANT NOTE:  This error can also occur when a temporary file
 cannot be created, possibly because the disk is full.

 Error messages generated by the Microsoft Library Manager, LIB, have
 one of the following formats:

 {filename | LIB} : fatal error U1xxx: messagetext
 {filename | LIB} : error U2xxx: messagetext
 {filename | LIB} : warning U4xxx: messagetext

 The message begins with the input-file name (filename), if one exists,
 or with the name of the utility. If possible, LIB prints a warning and
 continues operation. In some cases errors are fatal and LIB terminates
 processing.


 252. Error U2157 Filename : Cannot Access File

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_util s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39019

 The following error is from "LIB Error Messages" in the manual
 "CodeView and Utilities", Section C.3, Page 374, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.5, Page 380:

 U2157       filename : cannot access file

             LIB was unable to open the specified file.

 Error messages generated by the Microsoft Library Manager, LIB, have
 one of the following formats:

 {filename | LIB} : fatal error U1xxx: messagetext
 {filename | LIB} : error U2xxx: messagetext
 {filename | LIB} : warning U4xxx: messagetext

 The message begins with the input-file name (filename), if one exists,
 or with the name of the utility. If possible, LIB prints a warning and
 continues operation. In some cases errors are fatal and LIB terminates
 processing.

 A hyphen (dash, - ) in a subdirectory name in the path can cause this
 error; this error occurs because of a problem in LIB.


 253. Error U2155 Modulename : Module Not In Library; Ignored

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_util s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39020

 The following error is from "LIB Error Messages" in the manual
 "CodeView and Utilities", Section C.3, Page 374, and in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.5, Page 380:

 U2155       modulename : module not in library; ignored

             The specified module was not found in the input library.

 Error messages generated by the Microsoft Library Manager, LIB, have
 one of the following formats:

 {filename | LIB} : fatal error U1xxx: messagetext
 {filename | LIB} : error U2xxx: messagetext
 {filename | LIB} : warning U4xxx: messagetext

 The message begins with the input-file name (filename), if one exists,
 or with the name of the utility. If possible, LIB prints a warning and
 continues operation. In some cases errors are fatal and LIB terminates
 processing.

 A hyphen (dash, - ) in a subdirectory name in the path can cause this
 error; this error occurs because of a problem in LIB.


 254. Error U1005 Syntax Error: Colon Missing

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal h_fortran h_masm s_quickc s_make s_error
 Last Modified: 15-JAN-1990    ArticleIdent: Q39037

 The following error is from "MAKE Error Messages" in the manual
 "CodeView and Utilities", Section C.4, Page 376, and in the "Microsoft
 QuickC Compiler Programmer's Guide," Section D.6, Page 382:

 U1005       syntax error : colon missing

             A line that should be an outfile/infile line lacked a
             colon indicating the separation between outfile and
             infile. MAKE expects any line following a blank line to be
             an outfile/infile line.

 Note: MAKE expects a blank character or tab(s) after the colon between
 outfile and infile. If such a space is missing, this error occurs.

 Error messages displayed by the Microsoft Program Maintenance Utility,
 MAKE, have one of the following formats:

    {filename | MAKE} : fatal error U1xxx: messagetext
    {filename | MAKE} : warning U4xxx: messagetext

 The message begins with the input-file name (filename), if one exists,
 or with the name of the utility. If possible, MAKE prints a warning
 and continues operation. In some cases, errors are fatal and MAKE
 terminates processing.

 This problem can also be caused by using a NMAKE compatible make file
 with MAKE.


 255. Error R6006 Bad Format on exec

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39045

 The following error is from "Run-Time Library Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.4.1, Page
 283, and in the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.3.2, Page 362:

 R6006       bad format on exec

             The file to be executed by one of the exec functions was
             not in the correct format for an executable file.

 These messages may be generated at run time when your program has
 serious errors. Run-time error-message numbers range from R6000 to
 R6999. A run-time error message takes the following general form:

    run-time error R6nnn
    - messagetext

 Errors R6005 through R6007 occur when a child process spawned by one
 of the exec library routines fails, and DOS could not return control
 to the parent process. This error indicates that not enough memory
 remained to load the program being spawned.


 256. Error R6007 Bad Environment on exec

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39046

 The information below discusses the run-time error message R6007.

 The following error is from "Run-Time Library Error Messages" in the
 "Microsoft C Optimizing Compiler User's Guide," Section E.4.1, Page
 283, and in the "Microsoft QuickC Compiler Programmer's Guide,"
 Section D.3.2, Page 362:

 R6007       bad environment on exec

             During a call to one of the exec functions, DOS determined
             that the child process was being given a bad environment
             block.

 These messages may be generated at run time when your program has
 serious errors. Run-time error-message numbers range from R6000 to
 R6999. A run-time error message takes the following general form:

    run-time error R6nnn
    - messagetext

 Errors R6005 through R6007 occur when a child process spawned by one
 of the exec library routines fails, and DOS could not return control
 to the parent process. This error indicates that not enough memory
 remained to load the program being spawned.


 257. Error R6008 Not Enough Space for Arguments

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 11-JAN-1990    ArticleIdent: Q39047

 The information below discusses the run-time library error message
 R6008.

 The following error is from "Run-Time Library Error Messages" in (1)
 the "Microsoft C Optimizing Compiler User's Guide," Section E.4.1,
 Page 283, and in (2) the "Microsoft QuickC Compiler Programmer's
 Guide," Section D.3.2, Page 363:

 R6008       not enough space for arguments

 (1)         See explanation under error R6009.

 (2)         (no description given)

 These messages may be generated at run time when your program has
 serious errors. Run-time error-message numbers range from R6000 to
 R6999. A run-time error message takes the following general form:

    run-time error R6nnn
    - messagetext

 The following is the description for R6009 in the "Microsoft C
 Optimizing Compiler User's Guide":

    Errors R6008 and R6009 both occur at start-up if there is
    enough memory to load the program, but not enough room for
    the argv vector, the envp vector, or both. To avoid this
    problem, rewrite the _setargv or _setenvp routines (see
    Section 5.2.2, "Suppressing Command-Line Processing," for
    more information).


 258. Error R6013 Illegal Far Pointer Use

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_error
 Last Modified: 21-DEC-1988    ArticleIdent: Q39050

 The information below explains the run-time library error message
 R6013.

 The error below is from "Run-Time Library Error Messages" in the
 "Microsoft QuickC Compiler Programmer's Guide," Section D.3.2, Page
 363. It is not documented in the "Microsoft C Optimizing Compiler
 User's Guide" or in ERRMSG.DOC for Versions 5.00 and 5.10.

 The following is the error:

 R6013       Invalid far pointer reference

             An out-of-range far pointer was used in the program.

             This error occurs only if pointer checking is in effect
             (that is, if the program was compiled with the Pointer
             Check option in the Compile dialog box, the /Zr option on
             the QCL command line, or the pointer_check pragma in
             effect).

 These messages may be generated at run time when your program has
 serious errors. Run-time error-message numbers range from R6000 to
 R6999. A run-time error message takes the following general form:

    run-time error R6nnn
    - messagetext

 According to the README.DOC found on the Product Disk for Microsoft
 QuickC Version 1.00 and on the Setup Disk for QuickC Version 1.01, the
 run-time error message R6013 has changed as follows:

    R6013 illegal far pointer use


 259. C1004: Unexpected EOF

 Product Version(s): 4.00  5.00  5.10 | 5.10
 Operating System:   MS-DOS           | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 12-DEC-1988    ArticleIdent: Q39088

 The fatal-compiler error "C1004: Unexpected EOF" can be caused by
 failing to end a line with a <CR>.  On pure C language statements the
 compiler ignores white space, but on statements with directives a <CR>
 is needed.

 This will occur if the following include file is used in a program:

     #include <stdio.h><CR>
     #define YES 1<CR>
     #define NO  0

 Without the <CR> after the third line, error C1004 will be produced by
 the compiler.


 260. Using _gettextposition and printf.

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 12-DEC-1988    ArticleIdent: Q39089

 When the C graphic routines are being used in a program, they should
 be used for all output to the screen, including text output. Other C
 run-time functions for output should not be used.

 If a C program uses the run-time function _gettextposition, the
 function _outtext should be used to output text to the screen. Using
 the function printf will cause overwritting of text or blank lines to
 be inserted on the video screen.

 The following program will result in unpredictable output:

 #include <stdio.h>
 #include <stdlib.h>
 #include <graph.h>

 main()
 {
    struct rccoord rcoord;
    system("cls");
    printf("11\n");
    printf("22222222\n");
    printf("333333\n");
    printf("fourth line\n");
    printf("fifth line\n");

    rcoord=_gettextposition();

    printf("6666\n");
    printf("77777777\n");
 }

 The work around is use _outtext instead of printf.


 261. Pattern Format for _setfillmask

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | _getfillmask
 Last Modified: 29-DEC-1988    ArticleIdent: Q39215

 The _setfillmask function sets a background pattern using repeated
 8-by-8 pixel patterns. The mask consists of an 8-byte character array.

 The following example illustrates a pixel pattern:

                          Powers of 2

     decimal:   128  64  32  16  08  04  02  01
         hex:    80  40  20  10  08  04  02  01
                --------------------------------
        byte 1 |      1   1           1   1        =   0x66
        byte 2 |      1   1           1   1        =   0x66
        byte 3 |                                   =   0x00
        byte 4 |                  1                =   0x08
        byte 5 |              1   1                =   0x18
        byte 6 |  1                           1    =   0x81
        byte 7 |      1                   1        =   0x42
        byte 8 |          1   1   1   1            =   0x3C

 The character array for this particular fill mask would be declared in
 a C program as follows:

    unsigned char *maskarray = "\x66\x66\x00\x08\x18\x81\x42\x3C";

 When the fill mask above is used with _setfillmask and a graphics
 function such as _rectangle or _ellipse, the pattern will create
 a continuous field of faces.


 262. Opening Files Using Command Line Arguments.

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 29-DEC-1988    ArticleIdent: Q39216

 File names may be specified as command line arguments to a C
 program.  The example below uses the first command line argument as
 the name of the input file and the second as the name of the output
 file.  The parameter argv, which is declared by main(), is used to
 access the command line arguments.

 In the example below, the following occurs:

 1. argv[0] will contain a full path to the source (exe) file

 2. argv[1] will contain the first argument, which is the input file
 name

 3. argv[2] will contain the second argument, which is the output file
 name

 The following program opens a file for reading and writing and
 also prints argv[0], argv[1], and argv[2].  Note that argc is checked
 to make sure that two argument strings were actually passed and that
 the file pointers are checked to make sure that the files were
 actually opened.

 #include <stdio.h>

 main (argc,argv)
 int argc;
 char *argv[];
 {
   FILE *in, *out;

   if (argc < 3)  {         /* enough arguments? */
     puts("Usage:  demo infile outfile");
     exit(1);
   }

   printf("%s\n", argv[0]);
   printf("%s\n", argv[1]);
   printf("%s\n", argv[2]);

   in  = fopen (argv[1],"r");
   out = fopen (argv[2],"w");

   if (in == NULL || out == NULL)  {
     puts("Could not open both files");
     exit(2);
   }
   puts("Opened both files OK");
   exit(0);
 }

 The command line: "C:\>demo infile outfile" produces the
 following output if infile and outfile can be opened:

    C:\demo.exe
    infile
    outfile
    Opened both files OK


 263. Example of C Calling a MASM Procedure

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_masm
 Last Modified: 29-DEC-1988    ArticleIdent: Q39309

 The sample code below demonstrates a C program calling a MASM
 procedure. The C code declares an integer and passes the integer to
 the MASM procedure called mixed(). The mixed() function has an integer
 return value. The C code is compiled in the large-memory model and the
 MASM code is assembled with the /ML option.

 The following is the code:

 #include <stdio.h>

 int retval, value, foo;
 extern int mixed(int);

 main() {
     value = 35;
     foo = 25;
     retval = 0;
     retval = mixed(foo);
     printf("%d\n%d\n",retval,value);
     }

       DOSSEG
       .MODEL LARGE C
       .STACK  100h
       .DATA
         Dw 0
       .FARDATA
         EXTRN _value:WORD
       .CODE
         PUBLIC _mixed
 _mixed PROC
          push  bp
          mov   bp,sp
 ; access and change _value
          mov   ax, seg _DATA
          mov   ds,ax
          mov   ax,SEG _value
          mov   es,ax
          mov   es:_value,10h
 ; return the passed variable
          mov   ax,[bp+6]
          pop   bp
          ret
 _mixed   ENDP
          END


 264. Selective Initialization of Array Elements Not Allowed

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-DEC-1988    ArticleIdent: Q39310

 The ANSI C standard does not allow selective initialization of
 array elements with the following syntax:

    char MyArray[10] = {'a','b',,'d',,'f','g',,'i','j'};

 This attempt at selective initialization is illegal and will generate
 a "Syntax Error" at compile time. The following two declarations will
 compile and are valid declarations for Microsoft C Version 5.10:

 1. The initialization of all the elements of the array is as follows:

    char MyArray[10] = {'a','b','c','d','e','f','g','h','i','j'}

 2. The initialization of the front characters in the array is as
    follows:

    char MyArray[10] = {'a','b','c','d','e'}


 265. Use 0x80 to Access Drive C when Calling _bios_disk

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 29-DEC-1988    ArticleIdent: Q39311

 Question:

 I am using the _bios_disk function to access my fixed disk. I have
 initialized the drive parameter to 2 to specify my fixed-disk drive.
 This function does not seem to be accessing my fixed disk. What am I
 doing wrong?

 Response:

 The first floppy drive in a computer is identified as drive 0 with
 additional floppy drives numbered sequentially. However, the first
 fixed disk is identified as drive 0x80 (128 decimal) with additional
 partitions numbered sequentially. Therefore, call _bios_disk with the
 drive parameter set to 0x80 to access the first fixed disk.

 The following is an example:

    Logical Drive    diskinfo.drive
          A                 0
          B                 1
          C                0x80
          D                0x81
          E                0x82
          .                 .
          .                 .
          .                 .


 266. Commenting Out Blocks of Code and Comments for Debugging

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-DEC-1988    ArticleIdent: Q39312

 The C language does not support the use of nested comments. This might
 appear to be a limitation in cases where it is necessary,  perhaps for
 debugging purposes, to comment out a block of code which  contains
 comments. However, this situation can be overcome by using the
 much more powerful preprocessor commands #if and #endif.

 The #if preprocessor command evaluates a constant expression to either
 true (which has the value 1) or false (which has the value 0) to
 perform conditional compilation. If the expression equates to true,
 the code segment will be compiled. If it equates to false, it will be
 ignored by the compiler. Therefore, if the syntax below is used,
 the enclosed block of code will be forever ignored by the compiler
 giving a convenient method of effectively commenting out a block of
 code.

 Since the expression in the #if can be any constant expression, you
 can make complicated tests.  You can even use the /Dconst=value
 switch on the CL command line to set a preprocessor symbol which will
 include or exclude the debugging code when you compile.  This
 technique is described more fully on pages 75-77 of the Microsoft C
 Optimizing Compiler User's Guide.

 The following is a simple example:

 #define OUT 0

 #if OUT       /* will always equate to "false" */

    /* code and comments that you wish to remove are here */

 #endif


 267. #pragma pack() Affects Declarations, not Definitions

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified:  5-JAN-1989    ArticleIdent: Q40027

 Question:

 I need to use the preprocessor directive "#pragma pack()" to control
 how structure data are "packed" into memory. However, I don't know
 where to stick it. Should I place it before a declaration (creating a
 type) or before a definition (allocating space)?

 Response:

 The pack pragma affects declarations; not definitions. Place #pragma
 pack() prior data declarations.

 The following program demonstrates usage of #pragma pack():

 /* Elements of variables of type struct x will be byte-aligned. */
 #pragma pack(1)
 struct x { int a; char b; int c; };

 /* Elements of variables of type struct y will be word-aligned. */
 #pragma pack(2)
 struct y { int a; char b; int d; };

 /* The pragma below does NOT affect the definitions that follow. */
 #pragma pack(4)

 struct x X;
 struct y Y;

 void main (void)
 { /* dummy main */ }


 268. Error C2001: Newline in Constant for a String on Multiple Line

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified:  9-JAN-1989    ArticleIdent: Q40160

 If the program below, which contains a string literal that is
 incorrectly split over multiple lines, is compiled, the following
 error will occur:

    error C 2001: newline in constant

 The incorrect program is as follows:

 #include <stdio.h>
 main() {
     printf("\n %s
             %s
             %s",
             "this", "is", "it");
     }

 As indicated on Page 23 of the "Microsoft C for the MS-DOS Operating
 System: Language Reference" for Version 5.10, there are two methods to
 form a string that takes up more than one line.

 The best method is to change the format string as in the following
 example (this work because strings separated only by spaces, tabs,
 and/or newlines are concatenated):

 #include <stdio.h>
 main() {
     printf("\n %s"
            "%s"
            "%s",
            "this", "is", "it");
     }

 The older and less-prefered method is to use continuation lines by
 typing a backslash followed by a carriage return at the end of a line,
 as in the following example:

 printf("\n %s\
            %s\
            %s",
            "this", "is", "it");

 This is not as good as the previous example because the spaces at the
 beginning of the continuation line become part of the string, unlike
 example one.


 269. Simple Example Using _bios_serialcom

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 29-DEC-1988    ArticleIdent: Q39501

 Below is an example of using the C run-time library function
 _bios_serialcom to transmit and receive a single character over the
 serial-communications port COM1:.

 The _bios_serialcom routine simply calls the PC's ROM BIOS routines.
 On most PC's, these routines are not interrupt-driven nor buffered.
 As a result, characters may be lost when receiving very high-speed
 transmissions and/or if a significant amount of processing occurs
 between status checks and reads.  Although Microsoft does not provide
 interrupt-driven serial I/O routines with our C compilers, there are
 several third-parties which do.  A partial listing is available in
 the Language Support Directory which comes with the compiler.

 For additional information about ROM BIOS calls, please refer to "IBM
 ROM BIOS" by Ray Duncan, published by Microsoft Press. For examples of
 serial communication programs written in assembler, please refer to
 the MS-DOS Encyclopedia.

 The following program is a simple example which sends and receives one
 character to/from COM1:

 #include <stdio.h>
 #include <bios.h>

 void main(void)
 {
     unsigned com1_status;
     unsigned com1_send;
     unsigned com1_rec;
     unsigned com1_init;
     int result, mask;

     /* open serial port at 1200 baud, 8 data bits,
     ** No parity, 1 stop bit */
     com1_init = _bios_serialcom(_COM_INIT, 0,
         _COM_CHR8 | _COM_NOPARITY | _COM_STOP1 | _COM_1200);
     printf("Init status: 0x%4.4X\n", com1_init);

     /* send an '*' to com1 */
     com1_send = _bios_serialcom(_COM_SEND, 0, '*');
     printf("Send status: 0x%4.4X\n", com1_send);

     mask = 0x6100;
     /* value used to mask:
     *    bits 0-7 are related to modems,
     *    bits 8-15 are for port status,
     *      check to see that the following bits are set:
     *         8 (data ready)
     *        13 (Transmission-hold  register empty)
     *        14 (Transmission-shift register empty)
     */

     /* check the status */
     com1_status = _bios_serialcom(_COM_STATUS, 0, 0);
     printf("COM1 status: 0x%4.4X\n", com1_status);

     /* wait until a character is ready */
     do {
         /* check the status */
         com1_status = _bios_serialcom(_COM_STATUS, 0, 0);

         /* mask off the low order byte of com1_status */
         com1_status = com1_status & 0xFF00;
     } while( (mask & com1_status) == 0);

     /* get a character */
     com1_rec =  _bios_serialcom(_COM_RECEIVE, 0, 0);
     printf("Read status: 0x%4.4X\n", com1_rec);

     /* print the character we just received */
     result = com1_rec & 0x00FF;
     printf("Character: 0x%2.2X  =  %c\n", result, (char)result);
 }


 270. Wrong Syntax for fopen Mode Argument Gives NULL Return Value

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 29-DEC-1988    ArticleIdent: Q39602

 In the second argument to the fopen function, if the specification of
 the mode character t (text) or b (binary) is before the file-access
 type r (read), w (write), or a (append), no compilation errors occur.
 However, at run-time, fopen fails to open the file and returns NULL.

 Page 275 of the "Microsoft C Run-Time Library Reference" states that
 the mode character is to be appended to the character string for the
 type argument. If, instead, the mode character is placed before the
 beginning of the type argument, then fopen fails. An example follows.

 Please note that the string which is passed as the second parameter
 to fopen could be a variable string as well as a constant string.
 Since the variable string could be constructed at run-time, it is
 impossible to check for this error at compile time.

 Also note that strings of the form below are explicitly prohibited on
 page 275 of the C Runtime Library Reference.

 The program below demonstrates this behavior. It prints "failed"
 and does not open a file. If the second argument to fopen is changed
 to "wt", then it prints "succeeded" and the file is opened.

 The following is the program:

 #include <stdio.h>
 FILE *s;
 void main(void);
 void main(void)
 {
   if ((s = fopen("test.dat","tw")) == NULL)
     printf("fopen failed\n");
   else
     printf("fopen succeeded\n");
 }


 271. Example of Using Formatting with _outtext

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 29-DEC-1988    ArticleIdent: Q39783

 When programming with the Microsoft graphics library, the printf
 function can be used, but it is not recommended. Instead, to do any
 desired formatting, the _outtext function should be used with a prior
 call to sprintf. You should not mix printf() calls with _outtext()
 calls.

 The user-defined _outtextf function demonstrated in the program below
 performs formatting and printing in one function. This function
 simplifies conversion of non-Microsoft C graphics-compatible source
 code to Microsoft-compatible code. An intelligent text editor could
 simply do a global search and replace "printf" to "_outtextf".

 This following program defines and demonstrates the function "_outtextf":

 #include <stdio.h>
 #include <graph.h>
 #include <stdarg.h>

 int _outtextf (char *format,...);
 void main (void);

 void main (void)
  { /* Clear the screen and display "Hello, world #87!" */
    _clearscreen (_GCLEARSCREEN);
    _outtextf ("Hello, %s #%d!","world",87);
  }

 int _outtextf (char *format,...)
  { va_list arglist;
    char buffer[150]; /*Must be large enough to hold formatted string*/
    int retval;

    va_start (arglist,format);
    retval = vsprintf(buffer,format,arglist);
    va_end (arglist);

    _outtext (buffer);
    return (retval);
  }


 272. "D" Incorrectly Defined as a printf/scanf Format Specifier

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 29-DEC-1988    ArticleIdent: Q39784

 On Page 80 of the "Microsoft C 5.1 (and 5.0) Quick Reference Guide"
 (spiral bound), the capital letter "D" is incorrectly defined as a
 printf/scanf format specifier representing a signed long-decimal
 integer. The printf/scanf format specifier for a long-decimal integer
 is "ld". Using %D will print/return garbage characters.


 273. Using _getvideoconfig for Analog Monitors

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43536

 In the Microsoft C 5.10 Optimizing Compiler Run-Time Library, the
 function _getvideoconfig does not make a distinction between an analog
 color monitor and an analog monochrome monitor. For both of these
 configurations, it puts the value _ANALOG in the "monitor" field of
 the struct "videoconfig." _ANALOG is a manifest constant defined in
 the include file GRAPH.H to be 0x0018.

 The function _getvideoconfig is enhanced in QuickC Version 2.00 so
 that it recognizes analog monitors as being color or monochrome.
 There are two additional manifest constants defined in the new
 GRAPH.H: _ANALOGCOLOR (defined to be 0x0010) and _ANALOGMONO
 (0x0008).


 274. Time Functions Calculate for Daylight Savings Time

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-DEC-1988    ArticleIdent: Q39908

 The Microsoft time functions calculate for daylight savings time. In
 particular, mktime will set the hour ahead or back one hour according
 to the rules of daylight savings time. The only way to change the
 dates that the time functions use in calculating daylight savings time
 is to get the run-time library source code available for the time
 functions and modify the routine _isindst() in the file tzset.c.


 275. _scanf and _cscanf always Echo to the Screen

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 30-DEC-1988    ArticleIdent: Q39909

 The following is on Page 177 of the "Microsoft C 5.1 Optimizing
 Compiler Run-Time Library Reference" manual:

    Note:
    While scanf normally echoes the input character, it will not
    do so if the last call was to ungetch.

 This process does not appear to work correctly. The following code
 sample uses _getch() to get a character from the keyboard, then calls
 _ungetch(ch) to disable echoing to the screen before calling _cscanf.
 The keyboard input echoes to the screen regardless of the call to
 _ungetch. If _cscanf is replaced with _scanf, it still echoes to the
 screen.

 The following program calls _ungetch, then echoes the filename to
 the screen when it is read by _scanf; although, according to the
 documentation, it should not echo:

 ------------------------------------------------------------
 #include <conio.h>
 #include <stdio.h>
 #include <ctype.h>

 int result;                   /* return value from _scanf */
 char buff2[20];               /* buffer for filename */
 int ch;                       /* character returned by _getch*/

 main()                        /* begin executable code */

 {
 ch = getch();                 /* read a keyboard character */

 cprintf ("please enter file name");
 ungetch(ch);                  /* call to _ungetch */
 result = scanf("%19s", buff2);                 /* call _scanf */
 printf ("\n Number of correctly matched input"
        "items =  %d\n", result);          /* print # of input items */
        }


 276. C4047 Error Message when Initializing Unions

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 30-DEC-1988    ArticleIdent: Q39910

 If an attempt is made to initialize the second element of a union at
 declaration time (rather than in the code), the following warning
 is generated:

    C4047:'initialization' - different levels of indirection

 This error conforms to the ANSI standard, which assumes that the
 initialization is directed at the first element of the union, and
 reports, therefore, that the initializing values are of an incorrect
 type. If an attempt is made to initialize both the first and second
 element at declaration time, the same warning results.

 The following program demonstrates this error:

 -----------------------------------------------------------------
 union TEST {
     struct{
       int a;
       int b;
       int c;
     } one;             /* union element #1 */
     struct {
       char *ptr1;
       char *ptr2;
       char *ptr3;
       char *ptr4;
    } two;             /* union element #2 */
 }u;

 char ch1[10], ch2[10], ch3[10],ch4[10] ;

 union TEST test ={{1,2,3},    /* initialize element #1*/
                    {ch1,ch2,ch3,ch4} /* attempt to initialize #2 */
                    };

 main()
 {
 }
 ----------------------------------------------------------------

 The above program fails with the error C4047. The following
 initialization also fails with the same error:

    union TEST test = {ch1,ch2,ch3,ch4}

 However, an attempt to initialize the first element of the union will
 be successful, as follows:

    union TEST test = {1,2,3}

 If it is necessary to initialize the second element of a union, we
 suggest that you change the order of your union members, so that the
 element that requires initialization appears as the first element of
 the union.


 277. C 5.10 Setup Gives U1203 Error under DOS Versions 2.x

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 30-DEC-1988    ArticleIdent: Q39911

 When running the setup program for C Version 5.10 under DOS Versions 2.x,
 the following error is generated:

    U1203    : invalid object module

 This error occurs because the library manager, LIB.EXE, is bound.
 Under DOS Versions 2.x, bound programs can only be run from within the
 current working directory. Giving an fully qualified path will cause
 the error.

 Moving LIB.EXE into the current directory may avoid this problem.

 More information will be posted as it becomes available.


 278. Misleading Information about Linker Options with /link

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 30-DEC-1988    ArticleIdent: Q39915

 Pages 120-123 of the "Microsoft C 5.1 Optimizing Compiler User's
 Guide" describe options that can be used with the linker. The manual
 states that these options have equivalent options that can be used on
 the compiler command line. This subject can be confusing.

 If you are compiling and linking through the CL driver, then compile
 options are available to pass options to the link command line. For
 example, the /Fm option passes the /MAP option to the linker and a
 map file is produced.

 If a compiler option is not available for the linker option you want
 to pass to the link command line, the /link compile option can be
 used. The linker option can be given after /link option on the CL
 command line.


 279. Using _dos_findfirst to Get the Time and Date

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |  s_quickc
 Last Modified: 30-DEC-1988    ArticleIdent: Q39916

 The code below illustrates how to extract the time and the date out of
 the C run-time function _dos_findfirst. The program prints out the
 time and the date of the creation of the file "test".

 This information also applies to QuickC.

 The time at which the file was last written is returned as a binary
 value in a word formatted as follows:

    Bits     Meaning

    0-4      Number of seconds DIVIDED BY TWO
         (to find actual number of seconds, multiply by two)
    5-10     Minutes
    11-15    Hours, based on a 24-hour clock

 The date at which the file was last written is returned as a binary
 value in a word formatted as follows:

    Bits     Meaning

    0-4      Day of the month
    5-8      Month (1 = January and so on)
    9-15     Number of the year minus 1980

 The following is a sample code:

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

 struct {
   unsigned biseconds: 5;  /* in units of TWO seconds */
   unsigned minutes: 6;
   unsigned hours:   5;
 } *ptime;

 struct{
   unsigned day:   5;
   unsigned month: 4;
   unsigned year:  7;
 } *pdate;

 struct find_t c_file;

 main()
 {
    _dos_findfirst ("test", _A_NORMAL, &c_file);

    system("cls");

    ptime = &c_file.wr_time;
    pdate = &c_file.wr_date;

    printf ("Created at %u:%u:%u",\
             ptime->hours, ptime->minutes, ptime->seconds * 2);
         /* NOTE: seconds are divided by two when stored,
              so we have to multiply by two to get
              the proper value.... */

    printf ("on %u-%u-%u.",\
             pdate->month, pdate->day, pdate->year);
 }

 The program might produce the following output (depending on when the
 file "test" was created):

    Created at 10:32:28 on 12-19-8

 Note that the seconds field of the time will always be even.

 For more information on function _dos_findfirst, see "Microsoft C 5.1
 Optimizing Compiler Run-Time Library Reference," starting on Page 194.


 280. Open() Will Not Ignore Append Path

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  9-JAN-1989    ArticleIdent: Q40183

 DOS allows you to set an APPEND path to locate data files. Microsoft C
 library functions such as open and fopen will not ignore the APPEND
 statement, even if a full pathname is given to the specific function.
 This is expected behavior. If you wish to have the APPEND path
 ignored, you will have to write your own low-level open function, or
 ensure that the APPEND path is removed before your program is run.


 281. LINK4 Is Not Included in C 5.10 or MASM 5.10 Packages

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_masm PMWIN
 Last Modified: 13-JAN-1989    ArticleIdent: Q40236

 LINK.EXE, the incremental linker provided with the Windows Software
 Development Kit for DOS, is not included with C Version 5.10 or MASM
 Version 5.10, contrary to the statement on Page 82 of the January 1989
 issue of the "Microsoft Systems Journal."

 A bound linker, LINK.EXE Version 5.01.20, which may be used under DOS
 or OS/2, comes with MASM Version 5.10 as well as the real-mode linker
 Version 3.64 for DOS only. The C Version 5.10 retail package comes with
 the bound linker Version 5.01.21 and the real-mode linker Version
 3.65.

 To link under OS/2, use the bound linker with the latest version
 number you have available. To prepare for incremental linking with the
 ILINK.EXE utility under OS/2, use LINK.EXE with the option /INC. See
 the C Version 5.10 "Update (CodeView and Utility)" section of the
 "Microsoft C 5.1 Optimizing Compiler CodeView and Utilities" manual,
 or the "Microsoft Macro Assembler 5.1 Updates and Microsoft Editor"
 manual for more information on incremental linkage and the ILINK.EXE
 utility.

 LINK with /INC and ILINK have failed to work correctly for Windows
 program development under DOS, contrary to our documentation. DOS
 Windows developers should use LINK4, which comes with the Windows SDK.

 The ILINK utility should only be used under OS/2 for creating OS/2
 programs.



 282. Accessing I/O Ports under OS/2 Protected Mode

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | COM1 COM2 serial communication
 Last Modified:  5-JAN-1989    ArticleIdent: Q39973

 Problem:

 I am trying to use the inp(), inpw(), outp(), and outpw() routines in
 the Microsoft C Version 5.10 run-time library. Every time I run my
 program I get the following message:

    SYS1943: A program caused a protection violation.

 Response:

 To read from or write to ports under OS/2 protected mode you must have
 a .DEF module-definition file that gives IOPL (input/output privilege)
 to the _IOSEG segment. Also, if the intrinsic (/Oi) switch is used
 during compilation, the segments that contain the port functions must
 be given IOPL. You can check the .MAP file for the associated segment
 name or compile with the /NT switch to manually name the segment.

 The following must be in your .DEF file if /Oi was not used:

 SEGMENTS
     _IOSEG CLASS 'IOSEG_CODE' IOPL

 If /Oi was used, the following must be in your .DEF file:

 SEGMENTS
     (segment name) IOPL

 Note: Segments that have IOPL cannot make system calls. If you do,
 you will generate a GP fault, a general protection violation. This
 behavior is discussed on Page 239 of Letwin's "Inside OS/2."


 283. Error C2177: Constant Too Big

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  9-JAN-1989    ArticleIdent: Q39974

 The code below produces compiler error "C2177 : constant too big,"
 even though variable p is an unsigned long. The compiler does not
 generate this error if the number is 2,147,483,647 (maximum signed
 long possible) or less. Casting p to an unsigned long or putting L
 (for long) on the end of the number had no effect.

 This information also applies to QuickC.

 The following example demonstrates the error:

 #include <stdio.h>
 main()
 {
   unsigned long p;
   p = 4294967295;      /* maximum unsigned long */
   printf("%lu is the maximum unsigned long.",p);
 }

 According to the include file limits.h, to declare something as
 unsigned long, one must use the hexadecimal form if the number will be
 greater than 2,147,483,647. The code should be changed to the following:

 #include <stdio.h>
 main()
 {
   unsigned long p;
   p = 0xffffffff;
   printf("%lu is the maximum unsigned long.",p);
 }

 The code will produce the following output:

    4294967295 is the maximum unsigned long.


 284. Dynamic Allocation for Two Dimensional Arrays

 Product Version(s): 4.00 5.x | 5.10
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  4-JAN-1989    ArticleIdent: Q39976

 Question:

 How can I dynamically allocate memory for a two dimensional array?

 Response:

 The best method depends on the flexibility needed and the amount of
 information concerning the array known at coding time. The examples
 below set up two dimensional arrays of characters. Any element can be
 accessed with double sub-scripts, such as array[i][j]. Symbols in
 uppercase are constants, while those in lowercase are variables.

 If one of the dimensions of the array is known, either of the
 following two methods can be used. The first example creates more
 overhead due to the number of malloc calls, but it is more flexible
 because each malloc can be of a different size.

 The following is the first example:

     char *array[DIM_ONE];
     int   i;

     for (i = 0; i < DIM_ONE; i++) {
         array[i] = (char *)malloc(sizeof(char) * dim_two);
         if (array[i] == NULL) {
             printf("Not enough memory for columns in row %d!\n", i);
             exit(1);
         }
     }

 The following is the second example:

     char *array[DIM_ONE];
     int   i;

     array[0] = (char *)malloc(sizeof(char) * DIM_ONE * dim_two);
     if (array[0] == NULL) {
         printf("Not enough memory for columns!\n");
         exit(1);
     }
     for (i = 1; i < DIM_ONE; i++) {
         array[i] = (array[0] + (i * dim_two));
     }

 If neither of the dimensions is known at coding time, one of the
 following two methods can be used. The pros and cons of each example
 are the same as those for the previous examples.

 The following is the third example:

     char **array;
     int    i;

     array = (char **)malloc(sizeof(char *) * dim_one);
     if (array == NULL) {
         printf("Not enough memory for rows!\n");
         exit(1);
     }
     for (i = 0; i < dim_one; i++) {
         array[i] = (char *)malloc(sizeof(char) * dim_two);
         if (array[i] == NULL) {
             printf("Not enough memory for columns in row %d!\n", i);
             exit(1);
         }
     }

 The following is the fourth example:

     char **array;
     int    i;

     array = (char **)malloc(sizeof(char *) * dim_one);
     if (array == NULL) {
         printf("Not enough memory for rows!\n");
         exit(1);
     }
     array[0] = (char *)malloc(sizeof(char) * dim_one * dim_two);
     if (array[0] == NULL) {
         printf("Not enough memory for columns!\n");
         exit(1);
     }
     for (i = 1; i < dim_one; i++) {
         array[i] = (array[0] + (i * dim_two));
     }


 285. Chmod() on an Open File

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q40349

 When a file has been opened, it is not valid to perform a chmod() on
 the file. Although some operating systems (for example, UNIX) allow a
 program to change the permission of a file while it it open, MS-DOS
 requires the file to be closed before performing this function.
 Unusual results can occur, particularly when SHARE.EXE is installed,
 if an attempt is made to chmod() on an open file. One of the results
 is an error indicating the file is full, when only 1 byte is written
 to an empty file.


 286. _getimage Buffer May Be Huge (Larger than 64K)

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 16-JAN-1989    ArticleIdent: Q40350

 The graphics functions _getimage and _putimage may be used to store
 and display graphic images that require a buffer size larger than 64K.
 Even though these functions specify that the storage buffer is a far
 pointer, _getimage and _putimage internally treat the buffer as huge
 and do 32-bit address arithmetic.

 The following program demonstrates using the image functions on a huge
 image.

 /********************************************************************
  * Example program to demonstrate using the functions _getimage and *
  * _putimage on a huge image.                                       *
  ********************************************************************/

 #include <stddef.h>
 #include <malloc.h>
 #include <process.h>
 #include <graph.h>

 void main (void)
  { long size;
    char far *image;

    /* Put the display in a VGA mode and allocate a huge buffer. */
    if (_setvideomode(_VRES16COLOR)==0)
        { _outtext ("Video mode not supported!\n");
          exit (0);
        }

    /* In _VRES16COLOR, size is 153604. */
    size = _imagesize(0,0,639,479);

    if ( (image=halloc(size,1)) == NULL)
        { _outtext ("Not enough memory for buffer!\n");
          exit (0);
        }

    /* Draw a couple shapes and capture the screen. */
    _ellipse (_GBORDER,0,0,639,479);
    _rectangle (_GBORDER,0,0,639,479);
    _getimage (0,0,639,479,image);

    /* Clear the screen and redraw the image. */
    _clearscreen (_GCLEARSCREEN);
    _putimage (0,0,image,_GOR);

    hfree (image);
  }


 287. Call _setvideomode before Calling _imagesize

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 16-JAN-1989    ArticleIdent: Q40351

 Problem:

 I am using the _imagesize function to determine the size required to
 store a graphics image. However, this function is not returning the
 expected result.

 Response:

 The _imagesize function calls _getvideoconfig to determine the number
 of bits required to store a pixel given the CURRENT video mode. If you
 are calling _imagesize prior to calling _setvideomode, an unexpected
 result is returned by _imagesize.

 In summary, do the following in order:

 1. _setvideomode

 2. _imagesize

 3. _getimage and putimage


 288. Operation of scanf When Using the Width Option in the Format

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q40357

 The scanf run-time library function under Microsoft C allows the
 specification of the width that you would like to read in from the
 input device. Some examples of this width formatting are as follows:

    scanf ("%10s", buffer);   /* read ten chars into buffer[] */
    scanf ("%5d", &i);     /* read five digits of a number into i */

 When using width parameters in the format, the first n digits are read
 into the address specified.

 When used with a character string, the width parameter performs as
 follows:

    char buffer[15];
    scanf ("%10s", buffer);

 The first 10 characters are read, and a NULL terminator is added to
 the end of the string.

 When used with an integer or float, scanf always reads the first n
 characters (including decimal if in a float) specified with the width
 format. Entering Invalid characters (e.g. a decimal in an integer, any
 alphabetic character) causes the termination and failure of the read.


 289. Bit-Shift Function in C

 Product Version(s): 5.10    | 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q40358

 Question:

 How do I rotate, rather than shift, bits in a word? I don't want to
 lose any bits as happens when I shift.

 Response:

 Use the _rotl and _rotr functions in the C Runtime Library. These
 are described in the "Microsoft C Run-Time Library Reference."


 290. Turning the Scroll Lock On

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-JAN-1989    ArticleIdent: Q40359

 The following code illustrates how to turn the Scroll Lock on in
 your program. Note: This code is only for use under DOS. Running
 it under OS/2 will cause a protection violation. Use the OS/2
 FAPI function KbdSetStatus to set the status of shift flags when
 writing programs which will run under OS/2 or be bound to run under
 both DOS and OS/2.

 #include <stdio.h>
 main()
 {
    /* Get the address of the keyboard status byte */
    char far *kbdstat=0x00000417L;

    char scrollmask=0x10;

    /* OR *kbdstat with scrollmask to set bit 4 in the
       keyboard status byte to 1 */

    *kbdstat= *kbdstat | scrollmask;
 }

 Additional information on keyboard status can be found in the Peter
 Norton "Programmer's Guide to the IBM PC and PS/2." The above information
 also applies to QuickC.


 291. Incomplete Memory Model Switch in User's Guide Example

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-MAY-1989    ArticleIdent: Q40375

 The following compile command line given on Page 158, Section 6.7, of
 the "Microsoft C 5.1 Optimizing Compiler User's Guide" is incorrect:

    CL /As /Au /ND DATA1 PROG1.C

 This line should read as follows:

    CL /AS /Au /ND DATA1 PROG1.C

 If a program is compiled with /As rather than /AS, the following error
 will be issued:

    Command line error : D2013 incomplete model specification

 This error occurs because the data pointer size has not been
 specified.


 292. Warning C4051 Generated by Clock Function in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_QuickC docerr
 Last Modified: 16-MAY-1989    ArticleIdent: Q40376

 The example on Page 167 of the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" that shows how to use the run-time library
 function clock produces a warning C4051 : data conversion. The warning
 is generated because the variable tm is defined as an integer while
 clock_t is defined as a long in the include file time.h.

 As a result, warning C4051 is generated on the following line:

    if ((tm=clock()) != (clock_t)-1)

 To eliminate this warning, declare variable tm as a long.

 Also, if you want to see the elapsed time as real numbers, the
 following line should be changed:

    printf("Processor time equals %d second\n", tm/CLK_TCK)

 The line above should be changed to the following:

    printf("Processor time equals %fsecond\n",tm/(float)CLK_TCK)


 293. Problems with Using the Digital Output of a VGA Adapter

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 16-MAY-1989    ArticleIdent: Q40573

 Problem:

 When I run programs, such as GRDEMO, that call the graphics function
 _setvideomode, a border is displayed around my monitor. Also, the
 functions _remappalette and _remapallpalette do not seem to work
 correctly.

 Response:

 Some VGA display adapters have analog- and digital-output
 capabilities. The above behavior occurs when the digital output of a
 VGA display adapter is connected to the monitor.

 When the digital output is connected to an ECD (EGA monitor), a green
 border is observed. When the digital output is connected to a
 multisync class monitor, a gray border is observed. In either case,
 remapping the palette does not function. When the analog output is
 connected to a multisync or VGA monitor, the correct behavior is
 observed.

 The problem is that the graphics adapter is rightfully determined to
 be VGA class -- although for practical purposes it is really EGA
 class. At this point, the C graphics library treats the display
 incorrectly as VGA. Connecting a digital monitor to the digital output
 of a VGA adapter is a non-standard hardware configuration (the digital
 output of a VGA graphics adapter is non-standard). The behavior of a
 non-standard hardware configuration is unpredictable.



 294. You Cannot Trap CTRL+ALT+DEL in OS/2

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40580

 In OS/2, you cannot trap the CTRL+ALT+DEL. This key sequence is caught
 by the keyboard driver and never makes it into the input steam, so you
 have no access to it.


 295. Overlays and BINDing Are Not Compatible

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q40581

 Question:

 I have written a large program that needs to be overlaid to run in
 DOS. Is there a way I can compile it for OS/2, then BIND it to run in
 DOS with overlays so that I only have a single executable for both
 OS/2 and DOS?

 Response:

 You cannot do this; to BIND a program to run in DOS, you need a
 protected-mode executable. However, protected-mode executables do not
 understand overlays. As a result, there is no way to BIND a program
 that needs overlays in DOS. You have to have two different
 executables.

 Note: The two executables could be combined into one large executable
 by creating the real-mode executable and naming it in the STUB
 statement in the .DEF file when linking the OS/2 application. There is
 no real advantage to this; however, the new .EXE file will be a little
 larger than the two separate files. The STUB statement is documented
 by the C 5.10 utilities update in the LINK section.


 296. Floating-Point Routines Are Not Reentrant

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q40587

 Even if you only want simple arithmetic operations, the 80x87 chip
 doesn't provide a means for saving and restoring all of its registers.
 Microsoft wrote its library routines for DOS, which for the most part
 handle single-process routines, and therefore do not provide the
 routines necessary for achieving this effect with the coprocessor
 chip.

 If you want to develop a program that requires the coprocessor to be
 reentrant, you must provide your own routines that save and restore
 the registers of the coprocessor.


 297. Search Order for Include Files When Using APPEND Command

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | append include
 Last Modified: 25-MAY-1989    ArticleIdent: Q40588

 A data file path can be specified in DOS by using the APPEND command.
 DOS searches for a data file using the APPEND path. A file included by
 a C program can be in a directory that is in the data file path. The C
 compiler searches for the include file in the following order:

 1. Current directory

 2. Directories specified by the INCLUDE environment variable

 3. Directories specified by the APPEND command

 Please refer to your DOS documentation for specific information about
 using the APPEND command.

 Note: The APPEND command can cause other problems during
 compilation, linking, and execution. Microsoft recommends not using
 the APPEND command when developing C programs.


 298. The Definition of Reentrancy

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | re-entrant reentrant
 Last Modified: 16-MAY-1989    ArticleIdent: Q40589

 Question:

 What is reentrancy?

 Response:

 Reentrancy is the ability of code to be executed simultaneously by
 more than one process. It requires that the code not change the state
 of any global object, such as global variables or hardware. Any code
 compiled by the C compiler that uses only automatic variables will be
 reentrant only if the library functions used by the code are also
 reentrant.

 Note: Most library routines are not reentrant, nor is DOS or BIOS.


 299. Operator sizeof Returns Type size_t Defined as Unsigned int

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 11-JAN-1990    ArticleIdent: Q40590

 The sizeof operator returns a value that is of type size_t. The
 definition of size_t is implementation dependent, according to the
 ANSI standard. In Microsoft C, the size_t type is defined in STDDEF.H
 and in MALLOC.H as an unsigned int. This is documented on Pages 38 and
 98 of the "Microsoft C Optimizing Compiler Run-Time Library Reference"
 manual.

 The reference manual describes the sizeof operator on Pages 120-121,
 Section 5.3.4, but does not give the return type.

 The index entry for "size_t type" incorrectly lists Pages 38 and 97;
 it should say 38 and 98.


 300. Misspelling "Default" Gives No Error

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40593

 It has been reported that when the keyword "default" is misspelled as
 "defualt", the C compiler does not generate an error and the
 executable code does not execute the "defualt" branch in any case.

 This is not a problem with the C compiler. When the keyword "default"
 is spelled incorrectly, it is treated as a label. You may use a goto
 statement to reference the label.

 Note: It is not a good programming practice to jump to a label that is
 within a switch statement from outside the switch statement.


 301. Accessing the COM3: or COM4: Port

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40594

 If the DOS, the ROM BIOS, and the hardware all support COM3: and COM4:
 as valid devices, then the DOS mode command may possibly be used to
 redirect communication to access the ports from within Microsoft C.
 For example, to redirect COM3: to COM1:, give the following command:

    mode COM3:=COM1:

 Note: This process has not been tested by Microsoft and is offered
 only as a suggestion.

 Versions of DOS earlier than MS-DOS Version 3.30 do not recognize the
 COM3: and COM4: ports. Versions beginning with MS-DOS Version 3.30
 allow some systems to access the ports, but the ROM BIOS also must
 support the extra communications port hardware.


 302. C memcpy and Large Model

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881031-5486
 Last Modified: 16-MAY-1989    ArticleIdent: Q40738

 Question:

 I normally compile a certain program with the /Ox switch. Inside a few
 modules, I use the #pragma function(memcpy) statement, to force the
 use of the function version of memcpy, which is required because I use
 memcpy with some huge pointers.

 This works correctly, until I want to use CodeView. At that time, I
 recompile with the switches /Od /Zi. This produces the following error
 message:

    Error C2164: 'memcpy': intrinsic was not declared

 Editing each module to remove the #pragma function(memcpy), which is
 not required in the /Od case, eliminates the error message. Editing
 the pragma in and out is a lot of work, however.

 Why is this required?

 Response:

 The C2164 error message is listed in ERRMSG.DOC, which is supplied
 with the compiler. (It's a good idea to print out all the .DOC files
 for reference; there's a lot of important information there that
 doesn't appear in the manuals.) When you don't use the -Oi or -Ox
 option, you need to declare a function prototype before you can use
 the function or intrinsic pragmas. An easy way to do this is to
 include the appropriate .H file: in this case, either STRING.H or
 MEMORY.H will do. This will work with or without intrinsics.


 303. How to Pass a Far Pointer from Parent to Spawned Child in C

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881208-7649
 Last Modified: 25-MAY-1989    ArticleIdent: Q40774

 Question:

 Is it possible to hand over a far pointer from a parent process to a
 child process? My parent process is doing a memory allocation that it
 fills with data. I'd like to be able to access this data in the child
 process.

 Response:

 The best way to pass a pointer to a child is to convert the pointer to
 an ASCII string using sprintf, spawn the child with the string on the
 command line, and convert the string back to a pointer with sscanf.
 Below is a sample program that does this. Note that the program and
 the child process must be compiled separately. Be sure to pass a far
 (segment and offset) pointer rather than a near (offset only)
 pointer. Attempting to pass a near pointer will not work.

 It is also possible to leave the pointer in an agreed-upon memory
 area. Frequently, unused interrupt vectors are used for this purpose.
 We do not recommend this method because it could cause conflicts with
 other software using the same memory. The method described above
 is much safer.

 A sample parent program and child program follow:

 /**************** parent process ****************/
 #include <process.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>

 char buffer[80];            /* buffer to be passed to child */
 char ascptr[20];            /* holds ASCII version of ptr.  */

 void main(void)
 {
 int ret;

                             /* initial string */
     strcpy(buffer, "Main1");
     printf("Beginning main1...\nString is:  %s\n", buffer);

                             /* convert address to ASCII */
     sprintf(ascptr, "%p", buffer);
     printf("ASCII version of pointer is: %p\nSpawning main2...\n\n",
             ascptr);

                             /* spawn, passing ASCII address on
                                command line */
     ret = spawnlp(P_WAIT, "main2.exe", "main2", ascptr, NULL);
     printf("\nBack to main1--spawnlp returned %d\n", ret);

                             /* Show that string is changed */
     printf("String is now:  %s\nAll done", buffer);
     exit(0);
 }
 /* end of program number one*/

 /**************** child process--compile seperately! *************/
 #include <process.h>
 #include <stdlib.h>
 #include <signal.h>
 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>

 char far *ptrstuff;

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

     printf("In main2:  argv[1] is %s\n", argv[1]);
     if (argc != 2) {        /* error in argument list */
         printf("Error in argument list to main2\n");
         exit(1);
     }

                             /* retrieve pointer value from string */
     sscanf(argv[1], "%p", &ptrstuff);
     printf("\nPointer is actually set to:  %p\n", ptrstuff);

                             /* check to see that it's right */
     printf("Pointer points to: %s\n", ptrstuff);

                             /* change string (CAREFULLY!!!!!) */
     printf("Warning:  modifying the string incorrectly could hang "
            "your system...\n");
     printf("\007Should I modify this string? ");
     ch = getchar();
     if (toupper(ch) == 'Y')  {
         strcpy(ptrstuff, "2nd main");
         printf("Changed string to: %s\n", ptrstuff);
     }
     else printf("String not changed....\n");

     printf("Exiting main2...\n");
     exit(0);
 }
 /* end of child process */


 304. Using /ND to Put Uninitialized Data in a Named Segment

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40777

 Question:

 When I compile the example below with the /NDsegname switch, why don't
 the variables a and b end up in the segname_BSS segment?

 #include <stdio.h>

 int a,b,c=2;

 main()
 {

 }

 How do I get my uninitialized global data and static data to go into
 the named data segment (namely segname_BSS)?

 Response:

 Variables that are declared outside of a function and not initialized
 are communal. The BTDATA_BSS segment is for uninitialized static data.
 So, when compiling with /ND:

 int a;      /* goes to FAR_BSS   */
 int b = 5;  /* goes to STUFF     */
 static c;   /* goes to STUFF_BSS */

 The reason that "int a;" is treated in this way is that it's legal to
 have such declarations in several modules as long as at most one of
 the declarations contains an initializer. The linker combines all
 these definitions into one. If it were subject to the /ND switch, the
 variable could be in different segments in different modules, which
 would be impossible to link.

 So, to put the variable in the STUFF group, either declare the
 variable static or initialize it (like either b or c above).


 305. Assembly Listing Doesn't Match Generated Code in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q40783

 Microsoft has received several reports that the listings generated by
 the /Fc, /Fl, and /Fa options do not match the actual code in the
 .OBJ or .EXE file, as viewed by CodeView.

 In these cases, we have found that the file has been compiled using
 different options when creating the listing than when producing the
 CodeView file. In particular, adding the /Zi option causes some
 changes in the generated code. As we document, /Zi turns off
 optimizations that move code.

 If the listing was generated without /Zi, but the .EXE being viewed in
 CodeView was compiled with /Zi, there often are differences between
 the CodeView listing and the printed listing.

 Be sure to use EXACTLY the same options when comparing listing files
 with the actual code.


 306. Available Memory in C with More Than 20 Files and PC-DOS 3.30

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40785

 Question:

 Following the directions in the C 5.10 README.DOC file, I have
 modified the CRT0DAT.ASM file to increase the number of file handles
 from 20 to 30. I have a simple program (below) that checks the amount
 of available memory. When I link it with the modified CRT0DAT and
 execute the program, the amount of available memory is significantly
 less (approximately 64K) if I am running PC-DOS 3.30 than it is if I
 am running MS-DOS 3.30.

 Note: If I do not link in the CRT0DAT, then the difference in the
 available memory between MS-DOS 3.30 and PC-DOS 3.30 is negligible.

 All memory models will produce results similar to those described
 above.

 How can I eliminate this inconsistency between the two versions of
 DOS?

 Response:

 The only workarounds are to not link with a modified CRT0DAT.ASM, or
 to use MS-DOS instead of PC-DOS.

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

 The following program, compiled with "cl /W3 /c", demonstrates the
 problem:

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

 void main(void)
 {
    unsigned size;
    unsigned segment;

    printf("Checking memory:\n");
    size = 0xffff;
    if (_dos_allocmem (size, &segment))
       printf("Available paragraphs: %u\n",segment);
    else
       printf("Memory allocated.\n");
 }


 307. C Compiler Error: (compiler file '@(#)code.c1.46, line 393)

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40786

 The code below generates the following error when compiled with any
 /A?f? option:

    fatal error C1001 Internal Compiler Error
    (compiler file '@(#)code.c1.46, line 393)

 To work around the problem, use a different memory model, use only one
 register variable, or simplify the assignment with temporary
 variables.

 Sample code that demonstrates the problem follows:

 int main()
 {
     char *buff;
     char *ptr[8];

     register int k;
     register int i;

     *ptr[i]++ = buff[k++];
 }


 308. _edata and _end Are Defined by LINK

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_LINK
 Last Modified: 16-MAY-1989    ArticleIdent: Q40810

 Question :

 In the map file generated by Microsoft LINK, there are two symbols:
 _edata and _end. What are they?

 Response:

 When the /DOSSEG (default) option is used with the LINK command, these
 two symbols are created by LINK and are used in the C startup code as
 markers. They are only meaningful for the Microsoft C and FORTRAN
 Compilers.

 This information is explained on Page 273 of the "Microsoft CodeView
 and Utilities Software Development Tools for the MS-DOS Operating
 System" manual for C Version 5.00 or 5.10 in the LINK section. The
 note on this page states that the _edata points to the beginning of
 the BSS segment; _end points to the end of the BSS segment and the
 beginning of the STACK segment.

 These two symbols can be found in the startup source code file
 CRT0.ASM. The startup source code is included in the Microsoft C
 Optimizing Compiler for Versions 5.00 and 5.10.


 309. Maximum Number of Include Directories Is 15

 Product Version(s): 5.00 5.10  | 5.10
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | limits
 Last Modified: 31-JAN-1989    ArticleIdent: Q40837

 There is a maximum number of directories you can set in both the
 compile line and the INCLUDE environment variable. The combined
 maximum is 15. Exceeding the maximum can cause the error U1013 or
 U1077 in a MAKE file.

 No error message is given if the compile line is typed in directly
 from the DOS prompt. The program just fails to compile. This maximum
 applies to both DOS and OS/2.

 Note: If you have 14 directories in your include environment variable
 and added several others at the command line (with one /I, as opposed
 to using a /I for every directory), you could break this boundary.
 However, you should normally avoid using more than 15 directories.


 310. FATAL: Internal Stack Failure, System Halted

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC S_PASCAL H_FORTRAN H_MASM
 Last Modified: 16-MAY-1989    ArticleIdent: Q41024

 For DOS Version 3.20 or later, the following message is issued by DOS
 when too many interrupts occur too quickly and the pool of internal
 stack frames is exhausted:

    FATAL: Internal Stack Failure, System Halted

 Increasing the number of stacks allocated for use by interrupt
 handlers in the STACKS command in CONFIG.SYS usually corrects the
 problem.

 The syntax is as follows:

 STACKS=n,s

 n = number of stacks, ranging from 8 to 64, with 9 as the as the default
 s = size of each stack, ranging from 32 to 512 bytes, default of 128

 For more information about the STACKS command, see Page 805 of the
 "MS-DOS Encyclopedia."

 This error can occur if network cards, laboratory measurement
 instruments, and other devices are in use. They may generate many
 hardware interrupts thus exhausting the DOS stack resources.

 Note: For MS-DOS Version 3.30 on an IBM-PC, IBM-XT, or
 IBM-PC-Portable, the default for n is 0 and s is 0 .



 311. Libraries Added by the Comment pragma Appear After Default

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 11-SEP-1989    ArticleIdent: Q41104

 Page 12 of the "Microsoft C for MS OS/2 and MS-DOS Operating Systems:
 Version 5.1 Update" manual states that when using the library option
 of the comment pragma, the specified library name will be inserted
 before the default library name in the object module. This is not the
 case; the given library name appears after the default library name.
 This agrees with the next statement in the documentation that states
 that using this pragma is the same as giving the library to LINK on
 the command line.

 If the order of the default library and an added library is important,
 compiling with the /Zl switch will prevent the default library name
 from being placed in the object module. A second comment pragma then
 can be used to insert the name of the default library after the added
 library. The libraries listed with these pragmas will appear in the
 object module in the same order they are found in the source code.


 312. C Versions 3.00, 4.00 Do Not Require Semicolon in Structure

 Product Version(s): 3.00 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q41158

 Microsoft C Versions 3.00 and 4.00 do not require a semicolon to be
 put after each field in the structure declaration. The following piece
 of code does not produce any errors in C Versions 3.00 and 4.00:

 struct one
 {
    int i
 };

 Microsoft C Versions 5.00 and 5.10 do require a semicolon after each
 field and will generate the following error if the semicolon
 is not there:

 error C2143
 syntax error: missing ';' before '}'

 Note: According to the Kernighan and Ritchie, semicolons are required
 after each field in the structure declaration.


 313. rewind(stdin) Clears Keyboard Buffer

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41159

 Problem:

 I am trying to clear the keyboard buffer. It seems that using the
 function "fflush" on stream "stdin" does not have any effect.

 Response :

 The function "fflush" clears the buffers that C programs use for
 stream level I/O. It doesn't clear the device buffer.

 To clear the keyboard buffer, use the function "rewind" with the
 stream "stdin", which is associated with the keyboard by default.
 The function is prototyped in "stdio.h".

 The following is an example to demonstrate the usage:

 #include <stdio.h>
 void main(void)
 {
 int ch ;

 ch = getchar() ;    /* input more than one character
                     ** to see the effect of rewind(stdin) */
 putchar(ch) ;
 putchar('\n') ;

 rewind(stdin) ;
 ch = getchar() ;    /* will wait for new input even the first input
                     ** has more than one character */
 putchar(ch) ;
 }


 314. Getpid under DOS Is Not Functional

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q41160

 Under DOS versions earlier than Version 4.00, the getpid() function
 returns the current time rather then the process ID as expected.

 DOS is a single-tasking operating system, so it does not generate a
 process ID and the Getpid function should not be used. Getpid is
 intended to be used with OS/2 and serves no purpose under DOS.


 315. How ungetch() Works with getch() and getche()

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41198

 The Microsoft C run-time function ungetch() pushes back a character
 to be read in by the next call to getch() or getche().

 The character is pushed back to a special memory buffer defined in
 getch(). The function getch() or getche() checks the special buffer
 before it calls the DOS interrupt function to read input from the real
 keyboard buffer. If the special buffer is not empty, it returns the
 value in the buffer without calling the interrupt 21h function.

 ungetch() does not put the character back to the keyboard buffer.

 Pushing a character back to the keyboard buffer can be done on some
 machines by calling BIOS keyboard service, interrupt 16H function 05H
 with scan code in the register CH and the character's ASCII code in
 the register CL.

 Note: This BIOS function does not exist on many machines -- be sure to
 check the machine you're running on before you try to use this
 function.


 316. getch() Misbehaves on Keyboard Inputs ALT+Q, ALT+R

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q41203

 Problem:

 The sample program below accepts all the keyboard inputs normally,
 including most of the ALT combination keys. But it appears to behave
 incorrectly on two keyboard inputs: ALT+Q and ALT+R.

 Response:

 This is not a problem with the Microsoft C Optimizing Compiler
 run-time function getch(). The problem is caused because DOS uses the
 values of these two ALT combination keys for other control purposes.

 In this case, the second scancode of ALT+Q is 16 and the second
 scancode of ALT+R is 19 (both decimal). DOS uses scancode 16 to mean
 "echo subsequent output to the printer" and scancode 19 to mean "pause
 output." These are equivalent to CTRL+P and CTRL+S. When a printer is
 not connected to the computer, the PRINT SCREEN key has to wait for
 time out. For the SCREEN PAUSE key, another key has to be pressed to
 activate the screen again.

 We recommend using the _bios_keybrd() function rather than getch()
 when you might press ALT+R or ALT+Q.

 Usually the ALT combination keys generate 2 bytes in the keyboard
 buffer. The program below checks if the first byte is zero. If it is
 zero the program reads in the next byte, which has the value for that
 particular ALT combination key.

 The following is a code example:

 /* sample program */
 #include <stdio.h>
 #include <conio.h>
 void main(void)
 {
     int ch, scan;

     do {
         ch = getch();    /* 1st getch() gets ASCII code */
         printf("Character is %d\n", ch);
         if (ch == 0) {    /* if ASCII code was zero */
             scan = getch();  /* 2nd getch() gets "scan code" */
             printf("\tExtended character:  scan is %d\n", scan);
         }
     }  while (ch != 27);    /* exit loop on ESC */
 }

 To read the combination keys successfully, use the function
 _bios_keybrd(). The following is an example that works in a similar
 manner to the example above. Note: Because _bios_keybrd() returns
 both the scan code and the ASCII value in the high and low bytes of
 the return value, only one call to _bios_keybrd() is necessary for
 each keystroke.

 The following is a code example:

 #include <stdio.h>
 #include <bios.h>

 void main(void)
 {
 unsigned scan_asc;
 int ch, scan;

     do {
         scan_asc = _bios_keybrd(_KEYBRD_READ);
         ch = scan_asc & 0xff;  /* character in low byte */
         scan = scan_asc >> 8;   /* scan code in high byte */
         printf("Character is %d\n", ch) ;
         if (ch == 0) {
             printf("\tExtended character:  scan is %d\n", scan) ;
         }
     }  while (ch != 27) ;   /* exit loop on ESC key */
 }


 317. Prototypes Must Be Used Before Intrinsic or Function Pragmas

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G881031-5486
 Last Modified: 16-MAY-1989    ArticleIdent: Q41212

 Question:

 I normally compile a certain program with the /Ox switch. Inside a few
 modules, I use the #pragma function(memcpy) statement to force the
 use of the function version of memcpy, which is required because I use
 memcpy with some "huge" pointers.

 This works correctly until I want to use CodeView. At that time, I
 recompile with the switches /Od /Zi. This produces the following error
 message:

    Error C2164: 'memcpy': intrinsic was not declared.

 Editing each module to remove the #pragma function(memcpy), which is
 not required in the /Od case, eliminates the error message. However
 this is time consuming. Why is this required?

 Note: Error C2164 is not listed in the "Microsoft C for MS-DOS
 Operating System: User's Guide."

 Response:

 When you don't use the -Oi or -Ox option, you need to declare a
 function prototype before you can use the function or intrinsic
 pragmas. One method is to include the appropriate .h file -- for this
 function, either string.h or memory.h will work correctly.

 The C2164 error message is listed in errmsg.doc, which is supplied
 with the compiler. (It's a good idea to print out all the .doc files
 for reference; there's a lot of important information there that
 doesn't appear in the manuals.)


 318. How to Trap CTRL+C

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | appnote softlib CTRLC.ARC S12319.EXE
 Last Modified: 25-JUL-1989    ArticleIdent: Q45497

 An application note is available that demonstrates how to trap the
 CTRL+C and CTRL+BREAK key combinations. This application note is
 available from Microsoft Product Support Services by calling (206)
 454-2030. This application note is also available from the Microsoft
 PSS System Languages group.

 This information is also available in the Software/Data library by
 searching on the keyword CTRLC, the Q number of this article, or
 S12319. CTRLC was archived using the PKware file-compression utility.

 The file provided is fully tested; however, it is not regularly
 released with the Microsoft C Version 5.10 Compiler. Consequently, it
 will not be maintained and any problem reported against it will not
 result in a patch or any other immediate repair. Problems experienced
 with this file should be reported to Microsoft Product Support
 Services.

 CTRLC contains the following files:

    README.NOW - Brief description of program and Microsoft
    disclaimer

    CTRL.C - Code example for trapping the CTRL+C and CTRL+BREAK
    key combinations


 319. Alleged Problems with Listing Options (/Fc, /Fl, /Fa)

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# S881208-32 errors
 Last Modified: 25-MAY-1989    ArticleIdent: Q41217

 Microsoft has received reports that the assembly listing options (/Fc,
 /Fl, /Fa) produce listings that don't accurately reflect the code
 generated.

 We have determined that this problem is caused
 because different compiler options are being used when compiling to
 produce the listing, than when compiling to produce an executable. An
 especially common situation is to use /Zi for compiling the executable
 and to leave it off when compiling to produce a listing.

 The /Zi option DOES in fact cause slightly different code to be
 generated because optimizations that would move code are  suppressed.
 Therefore, it is perfectly normal for the CodeView listing of a
 program compiled with /Zi to differ somewhat from the listing produced
 when compiled without /Zi.

 If you find a case in which the listing is different from the
 generated code when both are compiled with EXACTLY the same options,
 please report the problem to Microsoft.


 320. Program Hangs the Second Time It Is Run Using an 80287

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q41220

 When compiling a program that uses signal() with an 80287 coprocessor,
 the first time the program runs, everything works correctly. But if
 run a second time, it hangs the computer.

 This problem has been confirmed to be with the old 80287 coprocessors
 and has been corrected in newer 80287 chips.

 The example program in the "Microsoft C for the MS-DOS Operating
 System: Run-Time Library Reference" manual on Page 280 locks up on the
 second time the program is executed with an old 80287. The following
 is an example:

 #include <stdio.h>
 #include <signal.h>
 #include <setjmp.h>
 #include <float.h>

 int fphandler ();
 jmp_buf mark;
 double a = 1.0, b = 0.0, c;

 main()
 {
     if(signal(SIGFPE, fphandler) == (int(*) () ) -1)
      abort();

     if(setjmp(mark) == 0)
     {
      c = a/b;
      printf("Should never get here\n");
     }

     printf("Recovered from floating-point error\n");
 }

 int fphandler (sig, num)
 int sig, num;
 {
     printf("signal = %d subcode = %d\n", sig, num);
     _fpreset();
     longjmp(mark, -1);
 }


 321. Use Huge Pointers If Object Is Larger Than 64K Boundary

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890201-11081
 Last Modified: 16-MAY-1989    ArticleIdent: Q41247

 Question:

 I'm declaring a pointer that points into an array by saying the
 following:

   char huge carray[70000];
   char *pchar = carray;

 I compile the program using large-memory model.

 When I access the array using carray, everything work correctly.
 However, when I use the pointer pchar, I can't seem to access the
 array past the 64K boundary. What's wrong?

 Response:

 The problem is caused by using a far pointer in a situation where you
 need a huge pointer.

 There are three types of data pointers in Microsoft C: near, far, and
 huge. Near pointers represent offsets within DGROUP (the default data
 segment) and are stored in 2 bytes. Far and huge pointers contain both
 a segment address/selector and an offset and therefore take 4 bytes.

 Although far and huge pointers are identical in format, the algorithms
 used to do addressing calculations involving these two types of
 pointers are very different. Far pointers are assumed to point to a
 data item that does not cross a segment boundary (in other words, the
 size of the item must be less than 64K). As a result, the compiler
 ignores the segment part of the pointer in all calculations except for
 "equals" and "not equals" tests. This gives a considerable (more than
 2 times) savings in execution time for these operations. In fact,
 calculations involving far pointers are almost as fast as calculations
 involving near pointers.

 Huge pointers may point to items that are larger than 64K. The
 addressing arithmetic work on both the segment and the offset, if
 necessary. Huge pointer arithmetic is therefore considerably slower
 than far arithmetic, but it has the advantage of working when the data
 item is larger than 64K.

 Your code should work correctly if you declare pchar to be a huge
 pointer rather than a far (default for large-memory model) pointer. If
 you didn't want to add the huge keyword to the declaration, you could
 compile with the /AH option. It is recommended to use the huge keyword
 rather than /AH because it allows you to control when huge arithmetic
 is performed -- if you use /AH, then ALL pointers are huge.


 322. Number of Serial Ports under OS/2

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890121-10245
 Last Modified: 16-MAY-1989    ArticleIdent: Q41255

 The number of serial ports that can be supported under OS/2 is
 dependent on how your OS/2 vendor set up the device drivers
 shipped with the operating system. Most are set up with two ports for
 AT-type machines and three for PS/2 type machines. Each vendor writes
 its own communications device drivers, so it really depends on what
 the vendor is doing.

 Note: Both original and third-party vendors can support additional
 ports (essentially, as many as they like) if they write or modify
 device drivers to do so.


 323. ROMable Code Using Microsoft C

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890121-10245 appnote
 Last Modified: 31-MAY-1989    ArticleIdent: Q41256

 Question:

 How can I use the Microsoft C Compiler to produce code that will be
 put into ROM?

 Response:

 The best way is to use a third-party package designed to produce
 ROMable code using Microsoft C. The linker supplied with our compiler
 only produces code designed to run under the DOS and OS/2
 environments. CodeView only runs under DOS or OS/2. Third-party
 packages typically include an alternate linker and debugger.

 You can find out more about these third-party packages by obtaining a
 copy of a technically oriented PC magazine or by talking with a dealer
 who sells such packages. Microsoft also provides an application note
 called "Writing ROMable Code in Microsoft C," which can be obtained
 from Microsoft Product Support Services by calling (206) 454-2030.


 324. What Is the Format of an .EXE File?

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890118-9899
 Last Modified: 16-MAY-1989    ArticleIdent: Q41257

 Question:

 What is the format of an .EXE file?

 Response:

 The .EXE file format is documented in a number of places, including
 the "MS-DOS Programmer's Reference." Probably the best documentation
 you'll find is in the MS-DOS Encyclopedia, starting on Page 119. There
 is also an appendix on the new segmented format used by Windows in the
 back of this reference.

 The MS-DOS Encyclopedia is an incredibly valuable reference for
 systems programmers. The format is too long and complicated to
 reproduce here.


 325. Calculating Available Memory in Large Model

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890215-12018
 Last Modified: 16-MAY-1989    ArticleIdent: Q41345

 Question:

 I am using large-memory model (C Version 5.10). My program makes a
 call to the _memavl() function to see how much memory is remaining. I
 get back some number (e.g. 29320 bytes). Then I malloc some buffers
 for linked lists, data structures and place another call to _memavl. I
 get the same number back.

 Shouldn't the number get smaller after I have malloc'd memory?

 Is there a way for me to find out how much free memory (total) is
 available?

 Response:

 There are actually two memory-allocation heaps when you're using large
 model. The near heap is the unused portion of the 64K DGROUP segment.
 The far heap is the unused memory above your program. malloc() uses
 the near heap for small and medium models and the far heap for
 compact, large, and huge models. (You can choose which heap to use by
 using _fmalloc() for the far heap and _nmalloc() for the near heap.)

 The _memavl() function only measures the amount of memory available
 on the near heap. Because the near heap is not used in far model until
 the far heap is exhausted, _memavl() shouldn't change.

 To measure the amount of memory available on the far heap, you can
 use the _dos_allocmem() function. (This function calls the DOS
 memory-allocation function.) Pass the function 0xFFFF for the number
 of 16-byte paragraphs to allocate (which is 1 megabyte more memory
 than the machine has) and the address of an unsigned int. When the
 function returns, the unsigned int whose address you passed will
 contain the paragraph size of the largest contiguous block in the far
 heap. To find the number of bytes, multiply this by the 16L, which is
 the size of a paragraph. (Use 16L rather than 16 so that the
 multiplication will be done using long math, avoiding possible
 overflow.)

 The total memory available is the sum of the amount available on the
 far and near heaps. For best accuracy, you should do this calculation
 immediately after your program begins.

 There are a few traits of the malloc() allocation you should be aware
 of, as follows:

 1. malloc() does NOT call DOS for each small allocation. Instead, it
    asks DOS for an 8K block (this size can be set by setting the
    global variable _amblksiz, as described on Page 33 of the
    "Microsoft C Run-Time Library Reference"), then allocates from this
    block. If the requested allocation is more than than 8K, malloc
    allocates enough 8K blocks to fulfill the allocation. Before
    malloc() asks DOS for memory, it first tries to allocate the
    request from memory it already has.

 2. free() NEVER returns memory to DOS. So, if you allocated a block,
    checked the far heap space using _dos_allocmem(), free()'d the
    block and checked again, the amount of memory available to DOS
    would NOT increase on the second call. You can get a better idea of
    how much memory is available by using _fheapwalk() to find out how
    much memory is available to malloc() but not to DOS.

 Note: halloc() calls DOS directly and frees directly to DOS.

 A program that calculates an estimate of the total amount of free
 memory follows:

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

 void main(void)
 {
 long totalavail;
 unsigned farparaavail;

     _dos_allocmem(0xFFFF, &farparaavail);

     totalavail = (long)farparaavail * 16L + _memavl();

     printf("Total memory available is about %ld bytes\n", totalavail);

 }


 326. Run-Time Library Reference vfprintf Documentation Error

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41369

 Page 636 of the "Microsoft C 5.10 Optimizing Compiler Run-Time Library
 Reference" and the "Microsoft QuickC Run-Time Library Reference"
 contains an error. In the example listed, the line

    error("Error: line %d, file  filename);

 should read

    error("Error: line %d, file %s\n", line, filename);


 327. _Setvideomode _ERESCOLOR Only Supports 16 Colors

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc docerr langdoc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41373

 The manifest constant _ERESCOLOR is incorrectly shown as providing 64
 colors on Page 539 of the "Microsoft C Optimizing Compiler Version
 5.10 Run-Time Library Reference" manual, Page 539 of the "Microsoft
 QuickC Run-time Library Reference" manual, and Page 197 of the
 "Microsoft QuickC Version 2.00 Graphics Library Reference" manual.
 According to the "Programmer's Guide to PC & PS/2 Video Systems," Page
 448, and the "MS-DOS Encyclopedia," Page 1513, the correct number of
 colors in 640 x 350 EGA is 16 colors. The include file graph.h
 correctly shows 16 colors.


 328. Assignment of Void Pointer Does Not Give Warning Message

 Product Version(s): 5.10 | 5.00 5.10
 Operating System:   OS/2 | MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41374

 The code below shows an inconsistency with the way that the Microsoft
 C and QuickC compilers deal with pointer checking. The ANSI Standard
 is unclear as to whether an assignment to a void pointer should be
 checked to see if it is being assigned a nonpointer variable. The code
 below shows that character pointers are checked while void pointers
 are not; the code will generate a warning message at the default
 warning level:

 Warning C4017 : '=' different levels of indirection

 int i;         /* includes float,double,char,long,unsigned */
 char * p;
 void * v;

 main() {
     p = i;    /* this will give a warning message */
     v = i;    /* this will not give a warning message */
     }


 329. Documentation Error Page 136 _bios_equiplist

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc docerr
 Last Modified: 16-MAY-1989    ArticleIdent: Q41441

 Page 136 of the "Microsoft C 5.10 Run-Time Library Reference" manual
 incorrectly documents the return values for _bios_equiplist. In the
 list of return values, it states that bit 13 is as follows:

     True (1) if and only if a serial printer is installed.

 This is only true if you have an IBM PCjr. On PC XT type machines,
 this value reports regardless of whether or not you have an internal
 modem installed.

 As a result, for PC XT machines, this line should read as follows:

    True (1) if and only if an internal modem is installed.

 This error also exists in the QuickC Versions 1.00 and 1.01 run-time
 library reference manuals and in the QuickC Version 2.00 on-line help.


 330. Macros max and min Incorrectly Listed as Functions

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-MAY-1989    ArticleIdent: Q41610

 Page 181, section 8.3.2 of the "Microsoft C 5.1 Optimizing Compiler
 User's Guide" incorrectly lists max and min as functions that have
 intrinsic forms.

 As correctly noted in the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" on Pages 413 and 429, max and min are
 macros defined in the include file stdlib.h.


 331. Documentation on Global Variable _osversion Is Incomplete

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q41689

 Page 36 of the "Microsoft C 5.10 Optimizing Compiler Run-Time Library
 Reference" states the global variable _osversion "provides the
 complete version number" of DOS the program is running under. This
 information is correct, but the format of _osversion is not mentioned.

 The high-order byte of _osversion is the "minor" version number, or
 _osminor. The low-order byte is the "major" version number, or
 _osmajor.

 If you were to write out these values in hex on a system running DOS
 Version 3.30 your output would be as follows:

    _osversion = 1e03
    _osminor   = 1e    (30 in decimal)
    _osmajor   = 03

 See the C run-time library reference guide, Page 36 for more
 information.


 332. Using ANSI Escape Sequences in Microsoft C

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 17-MAY-1989    ArticleIdent: Q41701

 Question:

 How can I control the screen display using ANSI.SYS escape sequences
 in my C program? For example, how can I clear the screen using the
 escape sequences?

 Response:

 The easiest way to use ANSI escape sequences is to use them in the
 printf statement, as follows:

 #include <stdio.h>

 /* ESC[2J escape sequence clears the screen;
    \033 represents the octal code for ESC */

 #define  CLEAR "\033[2J"
 main()
 {
  printf ("%s screen is now cleared",CLEAR);
 }

 The best source of information on different escape sequences is "The
 MS-DOS Encyclopedia," Pages 731-738.

 Note: For escape sequences to work correctly, ANSI.SYS must be
 installed.


 333. Missing Closing ")" on Macro Causes C1004 Unexpected-EOF Error

 Product Version(s): 5.10    | 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q42019

 The Microsoft C Version 5.10 Optimizing Compiler generates the
 following error message when the compiler encounters an incomplete
 macro invocation:

    fatal error C1004: unexpected EOF

 A macro in the program missing a closing-right parenthesis causes this
 error to occur. The Microsoft Quick C Compiler Version 2.00 also
 generates this error. Microsoft C Versions 5.00 and 4.00 and QuickC
 Version 1.01 generate the following error:

    C1057 unexpected EOF in macro expansion ( missing ')'? )

 Now the macro expander uses the same code to read characters when
 looking for an actual as it does to read any character. When we get
 the EOF, we cannot distinguish between a macro or the end of the code.
 This is correct behavior for C Version 5.10.

 The following is a sample piece of code that demonstrates this error:

 #include <stdio.h>
 #define add(wx, wy)  (wx) + (wy)
 void main(void)
 {
 int i;
 i = add( 1, 2 );
 printf( "i = %d\n", i );

 i = add( 1, 2 ;                 /* Causes C1004: unexpected EOF */

 printf( "Hello World\n" );
 for( i = 0; i < 10; i++ )
         {
         printf( "i + 10 = %d\n", add( i, 10 ) );
         }
 }



 334. Incorrect Usage of /o Switch in "Peter Norton's Inside OS/2"

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-MAY-1989    ArticleIdent: Q42072

 "Peter Norton's Inside OS/2" book written by Peter Norton and Robert
 Lafore, published by Brady, contains examples of OS/2 programming that
 were written and compiled using the Microsoft C Optimizing compiler
 Version 5.10. Page 536 of the book states the following:

    The -o option prevents the compiler from thinking that the global
    variables have been defined more than once.

 This is incorrect. The /o option is an undocumented compiler switch
 that allows you to name the executable file. It is the same as the /Fe
 compiler switch.


 335. Second fscanf Is Skipped During Run Time

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 25-MAY-1989    ArticleIdent: Q42075

 Question:

 I am using fscanf to read from the keyboard. Why is the second fscanf
 is skipped in the program below during run time?

 Response:

 The following is stated in the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" on Page 503 (in the description of the
 char format specifier):

    White-space characters that are ordinarily skipped are read when %c
    is specified; to read the next non-white-space character, use %1s.

 Note: You need an array of two characters for %1s because scanf will
 also put a terminating null in the string.

 Thus, after the first character is read in the example below, the
 following newline (e.g. linefeed, 0A hex) that is still in the C file
 buffer for stdin is read by the second fscanf (or scanf), causing the
 "second" prompt to be skipped during run time. The following is an
 example:

 #include <stdio.h>
 main()
 {
   char a,b[2];
   do
    {
      fprintf (stdout, "\n Enter first single character\n");
      fscanf (stdin, "%c", &a);

      fprintf (stdout, "second\n");
      fscanf (stdin, "%c", b);       /*this will get the new-line*/
    }
    while (b != 'y');
 }

 To work around this problem, use the format specifier %1s instead of
 %c. Don't forget to pass scanf an array of two characters.

 Alternately, the fflush() function may be used to flush all characters,
 including white space, out of the specified buffer after each fscanf or
 scanf, or flushall() may be used to flush all file buffers. However, using
 these functions wouldn't leave any characters in the file buffer for
 later scanfs.


 336. Getting 43-line Mode for C and QuickC Graphics

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1990    ArticleIdent: Q42079

 The Microsoft C Version 5.10 Optimizing Compiler README.DOC file
 states the following:

    The graphics library new functions correctly in 43-line mode on an
    EGA, and in 43-line, 50-line, and 60-line modes on a VGA.

 This information is correct; however, it does not state that you must
 write your own interrupt routine to set the video mode to support
 this.

 The following program demonstrates using Int 10H, Function 11H,
 Subfunction 23H to set an EGA system into 43-line mode. The interrupt
 call must be made BEFORE the call to _setvideomode(). If the routine
 is called after _setvideomode(), the text height is changed, but the
 program uses only the first 25 lines of the screen.

 The same procedure also works with the QuickC Version 2.00
 Presentation Graphics package, for placing additional text (with
 _outtext) around the chart. It does not change any of the default text
 (which already has the text height of 43-line mode), or change the
 appearance of the chart, but it allows additional text to be added
 around the chart in the smaller font to create a uniform appearance.

 The following is a sample program that demonstrates 43-line mode:

 /* program line43.c */

 #include <conio.h>
 #include <stdio.h>
 #include <graph.h>
 #include <dos.h>
 #include <process.h>

 union REGS inregs, outregs;
 struct SREGS segregs;
 int result;

 void main(void)
 {
   inregs.h.ah = 0x11;      /*load Function # into AH register       */
   inregs.h.al = 0x23;      /*load SubFunc # into AL register        */
   inregs.h.bl = 0x03;      /*load constant for 43-line mode into BL */
                            /*For 50-line mode, use                  */
                            /*       inregs.h.bl=0x00;               */
                            /*       inregs.h.dl=0x32;               */

   int86x(0x10, &inregs, &outregs, &segregs);  /* call interrupt */

   _setvideomode(_ERESCOLOR);   /* 640x350 EGA graphics mode         */
                                /* For VGA w/50 lines, change to:    */
                                /* _setvideomode(_VRES16COLOR);      */
   _settextposition(30,30);
   _outtext("this should be tiny text!");
   while(!kbhit());
   _setvideomode(_DEFAULTMODE);  /* restore to default mode  */

 Note: The "IBM ROM BIOS" quick-reference guide states that this
 function should be used only AFTER a _setvideomode command. However,
 this does not work effectively with the C graphics library.


 337. Clarification of fcvt() Function

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q42453

 This article is meant to clarify the description of the fcvt()
 function in the "Microsoft C for the MS-DOS Operating System: Run-Time
 Library Reference," Pages 251-252.

 The fcvt() function converts a floating-point number to a
 null-terminated character string. The number of digits converted
 depends on the second parameter passed. This second parameter is
 called "count" for the remainder of this article.

 The function is designed to return all the digits to the left of the
 decimal point, and then count digits to the right. Once the string is
 converted, all leading zeros are removed unless the number passed was
 zero (see Example 4 below). The string will be terminated with the
 "/0" character. The decimal point is not included in the string, and
 its position can be obtained from the third parameter (see the
 documentation).

 Based on this description, the following examples apply. In all cases,
 count = 8. The examples are as follows:

 1. Number passed: 3.667      String returned: "366700000\0"

    Nine digits are returned: one for the number to the left of the
    decimal point, eight more because of the count parameter.

 2. Number passed: 3.67E-08   String returned: "3\0"

    In this case, only "3" is returned because after the number is
    converted, all the leading zeros are removed.

 3. Number passed: 1.023E-12  String returned: "\0"

    In this case, a NULL string is returned because only zeros are left
    after the conversion, and these are all removed from the resulting
    string. If error checking were being performed, this would indicate
    a conversion underflow.

 4. Number passed: 0          String returned: "00000000\0"

    This is the only "special" case. Eight zeros are returned so that
    error checking can be performed easily.


 338. C Function _dos_setdrive Returns "5" Drives in the System

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | QuickC
 Last Modified: 17-MAY-1989    ArticleIdent: Q42461

 Question:

 Why does the C function _dos_setdrive always return "5", indicating
 that I have five drives in my system, when in fact I only have two?

 Response:

 The run-time function _dos_setdrive takes two arguments, as follows:

    void _dos_setdrive (drivenum, drives)

 The drives argument indicates the total number of drives in the
 system. This means that it will return the number of possible drives
 in the system. The system call Int 21 function 0x0E that _dos_setdrive
 uses to get this information will return a value of either five drives
 in the system or the drive code corresponding to the LASTDRIVE entry
 in CONFIG.SYS, whichever is greater. Without setting
 lastdrive="character" in your CONFIG.SYS, the default "lastdrive" is
 E, which corresponds to five drives possible. This is why
 _dos_setdrive will return "5" when you do not have five physical
 drives in the system.

 For example, the following line in CONFIG.SYS will cause a return of
 26, indicating that 26 drives are present in the system:

    lastdrive=z

 Therefore, the function _dos_setdrive is working correctly; it is the
 system call 0x0E that is returning such information.

 Note: The above information applies only to DOS Versions 3.x and 4.x.
 Under DOS 2.x, the actual number of drives present in the system will
 be reported.


 339. Inconsistent Warnings: C4049 and C4024 in C and QuickC

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_QuickC
 Last Modified:  1-JUN-1989    ArticleIdent: Q42562

 When compiled with warning level one or higher, the following code
 produces a single warning under the C 5.10 compiler and an additional
 warning under QuickC 2.00:

     /*  Inconsistent warning example
      */
     void fozzy( short foo, short *spud );
     void winky( int   foo, int   *spud );

     void main( void )
     {
         short sTest;
         short sPoint;

         fozzy( sTest, &sPoint );
         winky( sTest, &sPoint );
     }

 The warning emitted by both compilers is as follows:

    warning C4049: 'argument' : indirection to different types

 QuickC also produces the following warning:

    warning C4024: 'winky' : different types : parameter 2

 In both cases, the compilers dislike the second parameter in the call
 to winky. Winky is prototyped as accepting a pointer to an integer and
 is being passed a pointer to a short.

 These warnings are inconsistent because the compiler is not upset
 about winky being passed a short as its first parameter, when it has
 been prototyped as accepting an integer. If the compiler considers a
 short and an integer to be the same for the first parameter, pointers
 to these types should be considered the same for the second parameter.

 These generated warnings are expected behavior for both C and QuickC.
 Although integers and shorts are the same under Microsoft's
 implementation of C, they should not be considered to be the same. The
 only restriction on the size of the short given by the ANSI standard
 is that it not be longer than an integer. Code should be written with
 this in mind to maintain ANSI compatibility and prevent problems with
 future compilers, where integers might not be the same size as shorts.


 340. Using Near Addresses in Interrupt Handlers in C

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42597

 When the Microsoft C Compiler compiles the sample program below for
 the small or medium memory model, it gives the following warning:

    warning C4058: address of frame variable taken, DS != SS

 The sample program is as follows:

 /* sample program */
 void interrupt far handler (void) ;
 void foo (char *) ;

 void interrupt far handler (void)
 {
 char ch ;
 foo (&ch) ;
 }

 void foo (char * ptr)   /* a trivial function */
 {
 *ptr = 'a' ;
 }

 The warning is generated because the Microsoft C Compiler assumes that
 DS is equal to SS. Because the stack segment SS could possibly be
 changed in an interrupt service routine, the compiler gives a warning
 when a near address that refers to a stack location is passed to a
 function.

 In general, in the small and medium memory models, data pointers are
 defaulted to be near unless the "far" keyword is used. In the example
 above, the function "foo" is expecting a near address that is a 16-bit
 offset. A function such as "foo" has no way to tell if the near
 pointer passed to it is an offset relative to the data segment or the
 stack segment. Therefore, the C compiler makes the assumption that an
 offset by itself is always relative to the default data segment. This
 is not a problem in the normal case, where we can depend on the
 assumption that the C compiler makes SS equal to DS. However, in the
 example above, the stack segment could be changed in the interrupt
 handling routine; therefore, the compiler warns you that the code may
 not work correctly.

 If the memory model is large or compact, or if the "far" keyword is
 used when foo's formal parameter is declared, the compiler will not
 give any warnings. When "foo" is called, an address with the stack
 segment and the offset will be passed to the function automatically.
 Declaring the stack variable "ch" as static will also avoid the
 problem. The corrected source code is as follows:

 /* sample program */
 void interrupt far handler (void) ;
 void foo (char *) ;

 void interrupt far handler (void)
 {
 static char ch ;
 foo (&ch) ;
 }

 void foo (char * ptr)   /* a trivial function */
 {
 *ptr = 'a' ;
 }


 341. _imagesize Formula Documented Incorrectly for Some Video Modes

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc docerr
 Last Modified: 17-MAY-1989    ArticleIdent: Q42600

 The formula given on Page 362 of the "Microsoft C for the MS-DOS
 Operating System: Run-Time Library Reference" for Optimizing C Version
 5.x and QuickC Version 1.x, and on Page 133 of the "Microsoft QuickC
 2.00 Graphics Library Reference" is incorrect for most color EGA and
 VGA video modes. The formula given is as follows:

    xwid = abs(x1-x2)+1;
    ywid = abs(y1-y2)+1;
    size = 4+((long) ((xwid*bits_per_pixel+7)/8)*(long)ywid);

 This formula is accurate only for the following modes:

    _MRES4COLOR
    _MRESNOCOLOR
    _HRESBW
    _VRES2COLOR
    _MRES256COLOR
    _HERCMONO
    _ORESCOLOR

 However, for most EGA and VGA color graphics modes, the correct
 formula is as follows:

    xwid = abs(x1-x2)+1;
    ywid = abs(y1-y2)+1;
    size = 4 + ((bits_per_pixel * (long) ((xwid+7)/8)) * ywid);

 This formula should be used exclusively for modes that utilize bit
 planes. These modes are as follows:

    _MRES16COLOR
    _HRES16COLOR
    _ERESCOLOR
    _VRES16COLOR

 Either formula is accurate for the following modes:

    _HRESBW
    _VRES2COLOR
    _HERCMONO
    _ORESCOLOR

 A call to _getvideoconfig will determine the current video mode. This
 call is also necessary to determine the bits_per_pixel value.

 The following is an example of values that will yield an incorrect
 result in _VRES16COLOR mode:

    x1 = 0;  y1 = 0;
    x2 = 4;  y2 = 5;

 Note that for all cases, _imagesize does return the correct value.
 Only the formula given in the reference manuals is incorrect.

 The formula used internally by the _imagesize function is as follows:

    xwid = abs(x1-x2)+1;
    ywid = abs(y1-y2)+1;
    size = 4+(bits_per_plane*(long) ((xwid*linear_bits_per_pixel+7)/8)*ywid);

 This formula is useful only for lending understanding of how the two
 prior formulas are derived. It cannot be used in a C program for the
 following reasons:

 1. In this formula, linear_bits_per_pixel is the actual number of
    linear bits required to store a pixel. In the color EGA and VGA
    modes listed, this is not equivalent to the bitsperpixel field of
    the videoconfig structure. There is no way to determine this value
    within C.

 2. There is no way to determine the bits_per_plane value within C.

 The formula given on Page 392 of the run-time library reference is
 correct for CGA, single-color, and _MRES256COLOR modes because bit
 planes are not utilized in storing graphic images. That is,
 bits_per_plane is equal to 1. Therefore, this factor may be simplified
 out of the equation.

 The formula given on Page 392 of the run-time library reference fails
 on the listed EGA and VGA modes because bit planes are implemented in
 storing graphics images under those modes. That is, bits_per_plane is
 greater than 1. Also, linear_bits_per_pixel is not equivalent to the
 bitsperpixel field of the videoconfig structure.

 In elaborating on the bitsperpixel field of the videoconfig structure,
 this value is as follows:

    vc.bitsperpixel = linear_bits_per_pixel * bits_per_plane;

 For more information on bit planes and pixel maps, refer to the
 "Programmer's Guide to PC & PS/2 Video Systems" by Richard Wilton,
 Pages 87-91.


 342. Not Including MALLOC.H in Compact, Large Model Causes Problems

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-MAY-1989    ArticleIdent: Q42756

 It is vital in the compact- and large-memory models that the malloc()
 function be prototyped as returning a four-byte type (preferably a far
 pointer, of course). The proper method in Microsoft C is to include
 the header file MALLOC.H. This prototypes malloc() as returning a void
 pointer.

 The default data-pointer size in the compact and large models is 32
 bits. The default return type of any function, including malloc, when
 it is not prototyped is a 16-bit short integer. Thus, the segment
 portion of a far address will be destroyed unless the compiler knows
 it is dealing with a 32-bit type.

 If you attempt to use the Unix style of including MEMORY.H rather than
 MALLOC.H, you will encounter problems at run time. MEMORY.H does not
 prototype any of the memory allocation functions; it only prototypes
 memory copy and move functions. In a segmented architecture that can
 have data and code pointers of different sizes, this may have serious
 ramifications. In the case of a large- or compact-model program such
 as the following, the call to malloc() will produce the following code
 fragment:

     #include <memory.h>
     main()
     {
         char    *addr;
         size_t  nbytes = 100;

         addr = (char *) malloc( nbytes );
     }

 The call to malloc() produces the following code fragment:

             push    Word Ptr [nbytes]
             call    _malloc
             add     sp, +02
             cwd
             mov     Word Ptr [addr], AX
             mov     Word Ptr [bp-06], DX

 If MALLOC.H had been included, then the CWD (Convert Word to Double)
 instruction would not be present. CWD sign extends the AX register
 into the DX register in an attempt to convert the 16-bit integer in AX
 to a 32-bit data pointer. This trashes the segment returned by
 malloc() in DX. The resultant pointer will typically point to segment
 0x0000, meaning that in DOS the interrupt table will be trashed and in
 OS/2 the program will GP fault when an assignment is made to the
 allocated memory.

 Note: The compiler will also produce data conversion warnings at
 warning level 1 or higher when such a program is compiled. Paying
 attention to these warnings generally eliminates problems in
 converting C programs from other systems.


 343. Use /Op to Avoid Floating-Point Optimization Problem

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890216-12181
 Last Modified: 17-MAY-1989    ArticleIdent: Q42761

 The program below fails when compiled without an /O? option, but works
 if compiled with /Od. The problem seems to be in the conversion of the
 double to int -- the rounding seems to be done incorrectly.

 When the code is optimized, the result of the division is kept on the
 floating-point stack rather than being stored into memory and reloaded
 onto the stack. This causes precision problems because the numbers on
 the stack are stored in extended (10- byte) precision while doubles in
 memory are stored using 8 bytes.

 Note that the constant 23.31 cannot be represented exactly in the
 binary floating-point scheme used by Microsoft C. The fact that it is
 represented slightly small and then multiplied by 100 (magnifying the
 error) contributes to this problem.

 To avoid this problem, use the /Op option when compiling. The /Op
 switch forces in-memory storage of intermediate results. /Op can be
 combined with other optimizations (for instance, /Oxp).

 Program Example

 /*

   When the following program is compiled using default optimization,
   the program prints 2330 instead of 2331 (as it is supposed to.)
   Also, if the commented line is uncommented, the program works
   correctly with default optimization.

 */

 #include <stdio.h>
 void main(void)
 {
     int a;
     double f;
     f = 23.31;
     f = f * 100;
     /* printf(">%g<\n", f); */
     a = (int)f;
     printf(">%d<\n",a);
     return;
 }


 344. Patches of Floating-Point Instructions at Run Time Are Normal

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890217-12193
 Last Modified: 30-MAY-1989    ArticleIdent: Q42762

 Question:

 I have noticed that memory overwrites occur in the library routine
 i8_input. While debugging the program under CodeView with the
 assembler listing, I noticed that after executing into the code, the
 first 2 bytes of each instruction beginning with a hex CD are
 overwritten. The C statement that generated the assembler code with
 the problem in it was an "fscanf" function call.

 Below is an listing example of what is occurring:

 Before
 ------

 7E1F:4266 CD35C0       INT 35 ; FLD     ST(0)
 7E1F:4269 CD35E1       INT 35 ; FABS
 7E1F:426C CD372E7425   INT 37 ; FLD     TByte Ptr [__chbuf+5C (2574)]

 After
 -----

 7E1F:4266 90           NOP
 7E1F:4267 D9C0         FLD      ST(0)
 7E1F:4269 90           NOP
 7E1F:426A D9E1         FABS
 7E1F:426C 90           NOP
 7E1F:426D DB2E7425     FLD      TByte Ptr [__chbuf+5C (2574)]

 Response:

 The behavior you describe is quite normal and nothing to worry about.
 Our floating-point package works by generating the INT instructions
 you noticed. When these instructions are executed, the routine they
 call replaces the INT instructions with the either library calls to
 the emulator library or the actual 80 x 87 floating-point
 instructions, depending on whether or not a coprocessor is installed.

 When the instructions are executed again, there is no overhead for
 determining whether on not a coprocessor is installed: the proper
 instructions have been patched into place already. This patching
 occurs even if the -FPi87 option has been selected.

 You can force in-line 8087 instructions to be put into your code.
 For information on this technique, query on the following keywords:

    in-line 8087 instructions

 There is no need to do this if your code is going to run under DOS or
 OS/2. Although this article mainly discusses FORTRAN, it applies to C
 as well because the two languages use the same floating-point library.

 This code modification occurs only under DOS. Under OS/2, coprocessor
 instructions (such as in the second listing) are always generated. If a
 coprocessor is not present at execution, the instructions cause
 exceptions that are handled by the floating-point emulator software.

 Note: Such code modification is impossible under OS/2 because there is
 no way to dynamically change a code segment under OS/2, although it is
 possible to cause a data segment to be executed.


 345. Opening a C File When Disk Is Write Protected

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q42773

 With the run-time library in the Microsoft C Optimizing Compiler, a
 program can open an existing file for both read and write when the
 floppy disk is write protected. The following statement may be used to
 open the file:

    handle = open ("a:test.dat", O_RDWR | O_TRUNC) ;

 No error condition is returned and no hard error occurs. However,
 later, when the program tries to write to the file handle or even to
 close the file without writing, a hard error will occur with the
 following message:

    Writing protect error writing drive A:
    Abort, Retry, Fail?

 This is not a problem with the open() function in the Microsoft C
 run-time library. The low-level DOS function call that is used to
 implement open() does not check for a write-protect error. When the
 file is to be closed by close(), the internal buffer has to be flushed
 to the disk. No low-level DOS function can close a file without
 flushing its associated buffer.

 Workaround

 There is no direct way to detect the write-protect condition. An
 indirect workaround is to open a file with the mode to be O_CREAT, as
 follows:

     open ( "a:chk00000.xxx", O_CREAT, S_IWRITE | S_IREAD) ;

 A hard error will occur, which can be captured by a user-implemented
 and installed hard-error handler. This handler will override the
 printing of the hard-error message on the user screen. The open()
 function does return -1 when it regains the control from the
 hard-error handle. If the file was opened successfully, it may be
 removed at the end of the program.

 The following sample program demonstrates checking of a
 write-protected disk:

 /* sample program */
 #include <fcntl.h>
 #include <sys\types.h>
 #include <sys\stat.h>
 #include <io.h>
 #include <stdio.h>
 #include <dos.h>
 void far handler ( unsigned, unsigned, unsigned far * ) ;

 #define PROTECTED 1
 #define OTHER     2

 int Flag = 0 ;

 char * ChkName = "a:qwlbqwsi.ufp" ;     /* dummy file name */

 /* Note:
 ** If the file happens to exist, the hard error will not occur.
 ** The program will output "Disk is not write-protected."
 */

 void main(void)
 {
 int FileHandle;

 _harderr ( handler ) ;              /* set up hard error handler */

 FileHandle = open ( ChkName, O_CREAT, S_IWRITE | S_IREAD ) ;

 if ( FileHandle == -1 )             /* check write-protect */
      {
      switch ( Flag ) {              /* may be set by the handler */
         case PROTECTED :
             puts ( "Disk in drive A: is write-protected." ) ;
             break ;
         case OTHER :
             puts ( "A another hard error has occurred." ) ;
             break ;
         default :
             puts ( "Error opening file (non hard error.)" ) ;
         }
      }
 else {
      puts ( "Disk is not write-protected." ) ;
      close ( FileHandle ) ;
      remove ( ChkName ) ;           /* delete the file */
      }
 }

 /*
         Hard error routine should be as short as possible
 */
 void far handler ( unsigned deverror, unsigned errcode,
                    unsigned far *devhdr )
 {
 if ( errcode == 0 )
     Flag = PROTECTED ;
 else
     Flag = OTHER ;              /* like drive door is open */

 _hardretn ( 0 ) ;
 }
 /* end of sample */

 Note: The argument 0 to _hardretn() is not significant in this
 program. Please refer to Page 351 of the "Microsoft C for the MS-DOS
 Operating System: Run-Time Library Reference" for Version 5.10 for
 more specific information regarding the _hardretn() function.


 346. C Compiler: _control87() and Modifying the Control Word

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q42781

 Question:

 I want to mask off invalid arithmetic operation interrupts
 (EM_INVALID) from the math coprocessor using the _control87()
 function. However, after masking invalids with _control87() and
 confirming its value, invalids continue to be unmasked.

 Can I adjust the control word myself, or does the math package depend
 on a certain state of the control word?

 Response:

 You cannot mask or unmask certain bits with _control87(), even though
 it will report that it was successful. Also, modifying certain bits of
 the control word yourself (with the 80X87 instruction FLDCW) will
 corrupt all subsequent floating-point C run-time operations.

 The documentation in FPEXCEPT.DOC (which is contained in the C 5.10
 package) does state that denormals are always masked off and that
 invalids are never masked. It also states that bits 7, 6, 1, and 0 in
 the control word cannot be modified. It is true that these bits cannot
 be modified with the function _control87(); however, if you look at
 the control word with an assembly routine, you will see that the
 control word does not hold the same value as the C run time would have
 you believe.

 Invalid exceptions cannot be masked because the C run time uses them
 internally to handle extending the 80 x 87 floating-point stack beyond
 eight stack elements. If you try to mask invalid with the C run time,
 you will be told that you were successful, but the control word will
 not be changed at all. No invalid exceptions will ever reach you. If
 you try to mask invalid and an invalid exception occurs (which doesn't
 have anything to do with stack overflow or underflow), the C run time
 will check to see if you tried to mask invalid. If you did, the
 floating point routines will simply ignore the mask. If you mask
 invalid by setting the control word from an assembly routine with
 FLDCW, the run time will have stack problems.

 As for denormals, the denormal exception is never masked internally
 because every time the 80 x 87 encounters a denormal number, the
 emulator will try to convert it to a normalized number. This is the
 masked behavior on an 80387. Because this should not be changed (since
 it will break our math routines), you should treat denormals as if
 they are always masked. Thus, denormals always appear to be masked;
 you will never see a denormal exception, since they are all handled
 internally by the emulator.

 Therefore, denormals always appear to be masked unless you look at the
 control word on the chip directly, by using an FSTCW or CodeView. Also,
 it will appear that invalids can be masked, unless you look at the
 chip directly. If you do look at the chip directly, you will see that
 nothing has changed when trying to mask an invalid with _control87.
 Therefore, the code is functioning as expected. Both invalid and
 denormal are unmasked. If you look at the control word with FSTCW, you
 will see that the default control word is 1370h, instead of the 1332h
 returned by _control87. Also, if you send _control87(0x00ff,0x00ff),
 this function will tell you that the control word is set to 13FFh;
 however, FSTCW will reveal that the control word is really set to
 137Ch.

 Because the run time depends on certain settings of the control word,
 we do not want the run time to modify those settings. You can easily
 write an assembly routine to set the control word to anything you
 like, using FLDCW. It would not be to anyone's advantage to provide a
 floating-point function that would nullify all subsequent
 floating-point run time.

 We do not support the modification of the control-word bits mentioned
 above.

 For additional information on floating point exceptions, please refer
 to the file FPEXCEPT.DOC contained in the C 5.10 package.


 347. Fatal Error C1059: Out of Near Heap Space

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42793

 Using the /Zg compiler option to generate function declarations from
 the function definitions can cause the following error:

    Fatal error C1059: Out of near heap space.

 You may be able to free more space on the near heap by invoking the
 compiler in two passes, as follows:

         cl /P filename.c
         cl /Zg /c /Tc filename.I

 The first pass processes the preprocessor statements and produces an
 intermediate file. The second pass generates the function declarations
 from the intermediate file.

 Both the preprocessor and the compiler /Zg option use the near heap.
 The preprocessor uses the near heap to evaluate macro expansions. The
 compiler /Zg option uses the near heap while producing the function
 declaration listing.


 348. Background Colors Limited to 0 Through 7 in Text Mode

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1990    ArticleIdent: Q42796

 The function _setbkcolor() displays only colors "0" through "7" when
 in text mode. This is a limit of the hardware, not the library
 function.

 Two bytes are allocated for each character displayed on a text 80 x 25
 screen. The first byte is the ASCII code of the character; the second
 is the attribute byte.

 The attribute byte contains the information about the foreground and
 background attributes of the character. Four bits of this byte are
 allocated for the foreground color. The most significant bit of the
 foreground color is set aside for intensity or highlight. However, of
 the 4 bits allocated for the background color, the most significant
 bit is reserved to indicate a blinking or a nonblinking state.

 The layout of the attribute bytes is as follows:

             7    6   5   4   3   2   1   0
          +----+------------+---+------------+
          | BL | background | I | foreground |
          +----+------------+---+------------+

 Since only 3 bits are used to indicate the background color, only
 numbers from 0 through 7 can be represented. For this reason, only
 colors 0 through 7 are available as background colors for
 _setbkcolor().

 On most display adapters, you can set the adapter such that the blink
 bit becomes a background intensity bit. See your hardware technical
 reference or the "Programmer's Guide to PC and PS/2 Video Systems"
 (Richard Wilton, Microsoft Press) for more information.


 349. Exception #13 at xxxx:xxxx Error Code 0 Caused by QEMM

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC H_MASM B_QUICKBAS B_BASCOM
 Last Modified: 25-JUL-1990    ArticleIdent: Q42830

 A call to Quarterdeck Office Systems has confirmed that their
 Quarterdeck Expanded Memory Manager (QEMM) driver is responsible for
 the following error message reported by several customers:

     Exception #13 at xxxx:xxxx
     Error code 0
     Terminate, Reboot or Continue?

 This message indicates that an error was detected by the Quarterdeck
 memory manager. This error is essentially the same as a general
 protection fault in OS/2 and typically indicates that a stray pointer
 is involved.

 The error may occur either while the program is executing or after
 execution has ended and the program is returning to DOS. A technician
 at Quarterdeck stated that they generally use CodeView to track down
 such errors, and that while the address printed in the error
 diagnostic does not necessarily indicate the precise location of the
 error, it does indicate the location at which the error was first
 detected.


 350. Near Const Data Placed in _DATA in C 5.10

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42850

 Question:

 I have a program which was originally written in Microsoft C Version
 5.00. From the combined source-object code listing, I notice that the
 near constant data items are placed in the _CONST segment of DGROUP.
 In C Version 5.10, these same data items are placed in the _DATA
 segment. Is there a reason for this, and can I specify the items to
 remain in _CONST?

 Response:

 In C 5.00, near constant data was placed in _CONST because it was
 constant and produced more easily ROMable code. Unfortunately, the /Gt
 and /ND switches would not affect it. C Version 5.10 reverted to the C
 Version 4.00 convention of putting such data in _DATA. The /Gm switch
 is provided to specify the C Version 5.00 convention instead.

 For more information see the Update section, Page 51, of the
 "Microsoft C 5.10 Optimizing Compiler User's Guide."


 351. Limit of 40 Files with LLIBCMT.LIB and LLIBCDLL.LIB

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q42929

 Start-up source code is provided for the real- and protected-mode
 standard C run-time libraries. This code can be modified to allow more
 file handles and stream pointers to be opened by a process.

 This start-up code is not designed for LLIBCMT.LIB or CRTLIB.DLL.
 These are the protected-mode libraries for multithreaded applications
 and DLLs. The file and stream limits on both of these libraries are
 hard coded at 40.

 Handles 0, 1, and 2 are opened by C for stdin, stdout, and stderr,
 while handles 3, 7, and 8 are opened by different OS/2 subsystems.
 With these file handles taken, 34 files can be opened at once.

 Note: This restrictin has been removed from the C 6.0 version of these
 libraries. In fact, even with C 5.10, the open file count could be
 bumped up using DosSetMaxFH().  The problem was with the streams. In C
 6.0, the readme.doc file details how to increase the file stream count
 also.


 352. Passing Two-Dimensional Arrays between C and FORTRAN

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | H_FORTRAN
 Last Modified: 18-MAY-1989    ArticleIdent: Q43000

 When passing two-dimensional arrays from FORTRAN to C and vice versa,
 it is important to note that the indexing conventions for the two
 languages are different.

 C arrays are indexed row followed by column; or, the second index
 varies the quickest. However, FORTRAN is indexed just the opposite: in
 FORTRAN, two-dimensional arrays are indexed with the first indice
 varying the quickest. Thus, passing two-dimensioned arrays requires
 modification to either the C code or the FORTRAN code.

 For more information regarding passing arrays between C and FORTRAN,
 please see Page 127, Section 9.1.2, "Array Declaration and Indexing,"
 in the "Microsoft Mixed-Language Programming Guide for the MS-DOS
 Operating System."

 The following code samples define an array in a common block in
 FORTRAN, then use C to print the arrays to the screen:

 c     program mix_for.for
 c
 c
 c     this is to be used with mix_c.c......
 c
       subroutine test ()
       common/cblock/array(0:8,0:1)
       integer*4 i,j

       do 20 i = 0,8,1
         do 30 j = 0,1,1
         array(i,j) = i
       write(6,*)'the value of (',i,':',j,') is ',array(i,j)
   30  continue
   20  continue
       end

 /*  program mix_c.c

     this program is to be used with  mix_for.for......
     */

 #include <stdio.h>

 struct common_blk{
                  float array[2][9]; /* note that the subscripts
                                         of the array are inverted */
                  };

 extern void fortran test (void);

 extern struct common_blk fortran cblock;

 main()
 {
     int i,j;
     test();
     for(i=0;i<=8;i++)
         for(j=0;j<=1;j++)
             printf("\nthe value of %d:%d is %f"
                           ,i,j,cblock.array[j][i]);
 }


 353. Return Values for _remapallpalette and _remappalette

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC docerr
 Last Modified: 17-MAY-1989    ArticleIdent: Q43002

 The function _remapallpalette returns (short) -1 when successful and
 (short) 0 on error.

 The function _remappalette returns (long) previous color number of the
 pixel on success and (long) -1 on error.

 Their return values are incorrectly stated on Page 488 in the
 "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference" for both C Version 5.10 and QuickC Version 1.01, the C 5.10
 README.DOC, and QuickC 2.00 Advisor (on-line help screens titled
 "Help: _remapallpalette" and "Help: _remappalette).


 354. Reading Extended Keyboard Characters with C

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 17-MAY-1989    ArticleIdent: Q43007

 Question:

 How do I read from the extended keyboard with the C _bios_keybrd
 routine? It does not seem to recognize the scan codes for the
 additional keys of the extended keyboard.

 Response:

 The _bios_keybrd function uses INT function 16H to access the keyboard
 services. The _bios_keybrd function is based on the original PC BIOS
 INT 16H, which does not support the extended keyboard. The BIOS for
 AT's and PS/2's has been updated to support the extended keyboard. The
 updated BIOS has three addition services: 10H reads a character from
 the extended keyboard, 11H gets the extended-keyboard status, 12H gets
 the extended-keyboard flags.

 To allow the C function _bios_keybrd to use these updated keyboard
 services, add the following manifest constants to the bios.h include
 file:

 /* manifest constants for BIOS enhanced keyboard services */

 #define _EXT_KEYBRD_READ         0x10  /* read character */
 #define _EXT_KEYBRD_READY        0x11  /* check if key waiting */
 /* check status of shift keys*/
 #define _EXT_KEYBRD_SHIFT_STATUS 0x12

 To read keys from the extended keyboard, use these new constants in
 place of the manifest constants described on Page 138 of the
 "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference" for Version 5.10.

 The following program uses the enhanced services of INT function 16H
 to determine if the UP ARROW or DOWN ARROW keys on the extended
 keyboard were pressed:

 #include <bios.h>
 #include <stdio.h>

 main()
 {
         unsigned key;

         key = _bios_keybrd(EXT_KEYBRD_READ);
         if ( key == 0x48e0)
                 printf("up arrow key was pressed\n");
         if ( key == 0x50e0)
                 printf("down arrow key was pressed\n");
 }


 355. Switching from Reading to Writing Files Can Garble Data

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc sequence locate position
 Last Modified: 17-JAN-1990    ArticleIdent: Q43072

 When switching from reading to writing of C Version 5.10 files, it is
 necessary to do an fsetpos, fseek, or rewind. If you do not use one of
 these library functions, the file pointer may not be updated and you
 could get some erroneous results. This also applies when switching
 from writing to reading. This is documented on Page 275 of the
 "Microsoft C Run-Time Library Reference" manual.

 The following program will attempt to read in the first character of a
 file and to write it out as the second character:

 #include <stdio.h>
 void main(void)
 {
   FILE *fp;
   char a;

   if (( fp = fopen("text.fil","r+")) != NULL)
   {
     fscanf(fp,"%c",a);      /* read one character */
     fprintf(fp,"%c",a);     /* write to the next location */
     fclose(fp);
   }
 }

 The above program will fail because there is no fseek, fsetpos, or
 rewind between the fscanf and fprintf. The following program will
 perform the desired operation:

 #include <stdio.h>
 void main(void)
 {
   FILE *fp;
   char a;
   fpos_t loc;     /* storage for the current location */

   if (( fp = fopen("text.fil","r+")) != NULL)
   {
     fscanf(fp,"%c",a);    /* read one character */
     fgetpos(fp,&loc);     /* get current file pointer pos */
     fsetpos(fp,&loc);     /* set current file pointer pos */
     fprintf(fp,"%c",a);   /* write to next location */
     fclose(fp);
   }
 }


 356. The Function fopen Accepts Filenames with Embedded Spaces

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43073

 The Microsoft run-time library functions fopen and open do not screen
 for invalid filenames. These functions will accept a filename string
 with an embedded space. For example, the following program will create
 the file "he llo.dat" (without the quotation marks):

 #include <stdio.h>
 FILE *fh;
 void main(void)  {
    fh = fopen ("he llo.dat", "w+);
 }

 This error is not the result of a problem with fopen or open. The
 functions fopen and open should not be expected to screen filenames.
 This activity should be handled by the program using these routines.
 Filename screening is not specified in the "Microsoft C for the MS-DOS
 Operating System: Run-Time Library Reference" manual; this applies to
 both MS-DOS and OS/2.

 However, the creation of this file could cause some difficulties under
 DOS. The simplest way to delete such a file would be "del *.dat"
 (without the quotation marks).


 357. C: Using the _dos_findfirst and _dosfindnext Functions

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS_DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43144

 Question:

 Why do all my files show up in addition to the subdirectories when
 using the _dos_findfirst and _dos_findnext functions to find all the
 subdirectories in my working directory?

 Response:

 When the attribute argument to the _dos_findfirst and _dos_findnext
 functions is either _A_RDONLY, _A_HIDDEN, _A_SYSTEM, or _A_SUBDIR, the
 functions will return all normal-attribute files.  A normal-attribute
 file is any file that does not have a read-only, hidden, system, or
 directory attribute.

 Thus, the following function call will return either a normal file or
 a subdirectory:

    _dos_findfirst( "*.*", _A_SUBDIR, &c_file )

 To verify that the returned c_file is a subdirectory, check the
 attribute field of the c_file to determine whether the _A_SUBDIR bit
 is set. If so, then it is a subdirectory. This process may be
 accomplished by bitwise-ANDing c_file.attrib with _A_SUBDIR and
 checking for a nonzero result.

 The following program illustrates the use of these functions:

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

 main()
 {
         struct find_t c_file;

         _dos_findfirst( "*.*", _A_SUBDIR, &c_file );

         if( c_file.attrib & _A_SUBDIR )
         printf( "Directory listing %s\n", c_file.name );

         while (_dos_findnext(&c_file) == 0)
             if( c_file.attrib & _A_SUBDIR )
             printf( "Directory listing %s\n", c_file.name );
 }


 358. C: How Stack Checking Is Done

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 22-MAY-1989    ArticleIdent: Q43166

 Microsoft C does stack checking to check for stack overflow. The stack
 for an application program grows from high memory to low memory. The
 lowest memory location to which the stack can grow is determined in
 Microsoft C as follows:

 &end + STACKSLOP      /* in assembly: OFFSET _end + STACKSLOP */

 The _end symbol is created by Microsoft LINK which assigns it the
 address of the lowest memory location of the STACK segment.

 STACKSLOP is a manifest constant. For DOS, STACKSLOP = 256 (decimal);
 for OS/2, STACKSLOP = 512 (decimal).

 At runtime, the function _chkstk is called, on entry to each function,
 to check the stack. If the current value of the SP register minus the
 total size of the local variables is less than the sum of &end plus
 STACKLOP, _chkstk prints the following error message and terminates
 the program:

 R6000   stack overflow

 Otherwise, _chkstk will update the value of SP according to the total
 size of the local variables.

 The source code for the function _chkstk is included in the startup
 source code in the Microsoft C Optimizing Compiler Version 5.10.

 The value of the SP register is not updated if the stack overflow
 condition is detected.

 Stack checking can be manually disabled with either the compile line
 option /Gs, or with the pragma; #pragma check_stack(off). In that
 case, SP will be updated even if a stack overflow occurs.

 For more information on _end, query on _edata.


 359. Critical Error during Spawn Will Lose Parent

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43537

 A critical error occurs when spawning another program using one of the
 C Version 5.10 run-time library's spawn functions that can prevent the
 child program from returning to the parent process. A sample program
 is shown below.

 This is not a problem with the run-time library, but is a limitation
 of the spawn family of functions.

 A workaround is to attempt to open the .EXE file before the spawn. The
 critical error will occur on the open and allow DOS and the run-time
 library to handle any problems encountered in a more elegant fashion.

 The following program can be used to demonstrate the situation:

     #include <stdio.h>
     #include <process.h>

     void main( void )
     {
         spawnlp( P_WAIT, "a:\\test.exe", "a:\\test.exe", NULL );
     }

 If Drive A is ready, TEST.EXE will be spawned correctly and return to
 the parent. However, if the drive door is open, the following prompt
 will be produced by the DOS critical error handler "Abort, Retry,
 Fail?".

 If the drive door is closed and "Retry" is selected, TEST.EXE will run
 but not return to the parent, hanging the system. An assembly language
 program that simply calls DOS interrupt 4B to do the same thing will
 work correctly under the same conditions.


 360. C: Cannot Bind Programs with Increased File Handles

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q43271

 Microsoft C defaults to making 20 file handles available to an
 application. This is the case for both OS/2 and DOS. This number can
 be increased by modifying the start-up source code provided with
 Optimizing C Version 5.10 and linking in the resulting OBJs. This is
 documented in the README.DOC (search for _NFILE_).

 However, it is not possible to bind a program that is linked to these
 modified OBJs. This is because the protect-mode start up makes a call
 to DOSSETMAXFH after being modified. This function is not FAPI (dual
 mode) and is not bindable.

 To give a program more than 20 file handles under both OS/2 and DOS,
 you must create separate EXEs for each environment.

 An attempt to bind a program that is linked with modified start up will
 produce the following error:

    LINK : error L2029: Unresolved externals:

    DOSSETMAXFH in file(s):
    BV3.OBJ(bindv3)

 The start-up files that must be modified to increase the number of
 available file handles are CRT0DAT.ASM and _FILE.C.


 361. Printing ASCII Characters Greater Than 127 Fails in CGA Mode

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43272

 When a CGA graphics card is in any CGA graphics mode it will not
 display ASCII characters greater than 127 when Microsoft C text-output
 routines are used. Garbage characters will be displayed instead.

 This is expected behavior. The default character-definition table for
 CGA graphics cards contains only the first 128 ASCII characters. To
 print ASCII characters 128 to 255, a separate character-definition
 table must be set up and accessed through interrupt vector 1FH. The
 MS-DOS utility GRAFTABL leaves such a table and hooks the interrupt
 1FH vector to point to it.

 For more information, see Richard Wilton's book "Programmer's Guide to
 PC & PS/2 Video Systems," Page 269, which is available from Microsoft
 Press.


 362. C: Spawned Program Accessing Parent's Functions

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q43318

 It is possible for a program spawned with the P_WAIT modeflag to
 successfully call functions within its parent. The functions must be
 set up in such a way that CPU registers are preserved and the data
 segment register is loaded as necessary. It is also vitally important
 that all necessary start-up code and C run time are present whenever
 the parent functions are called.

 Warning: This procedure is neither recommended nor supported. This
 article is for informational purposes only.

 The programs below, PARENT.C and CHILD.C, demonstrate this technique.
 This method of sharing functions may be useful as a primitive form of
 overlaying when there is a need for a common set of functions to be
 accessed by a sequence of spawned child processes. The method of
 communication from the parent to the child is through command-line
 arguments. In the parent, a far pointer to the function that will be
 called is converted to a string and passed as a parameter through a
 spawn. In the child, it is then converted back into a far pointer.

 There are several considerations to be made when writing code of this
 nature.

 For any variables in the parent to be accessed, the routines to be
 called must use the _loadds keyword. Not loading DS for the called
 function results in the child's DS being used rather than the DS
 associated with the function in the parent.

 Even if _loadds is used, however, DS will not be equal to SS, since
 the child's stack is the one that is used and there is no mechanism in
 C for changing stacks. It is necessary to ensure that the functions
 called by the child do not blow out the child's stack.

 Many of the run-time library routines rely on SS equaling DS;
 therefore, one must obviously avoid those routines.

 Preservation of the child's state can be accomplished by using the
 _saveregs keyword. This is not necessary when calling C from C;
 however, it may be vital if C is being called from MASM.

 All calls must be far since the parent and child were loaded
 separately. Different memory models may be used for parent and child.

 This process obviously produces a general-protection fault in OS/2.
 Use dynamic link libraries to duplicate this functionality with
 greater ease, portability, and safety.

 The following is the parent program:

 /*
  *   PARENT.C
  */

 #include <stdio.h>
 #include <stdlib.h>
 #include <process.h>

 int far _saveregs _loadds foo( void );
 void main( void );

 int         k = 0,
             l = 0;              /* Globals to be accessed inside foo */

 int far _saveregs _loadds foo()
 {
     int         i,              /* Return value */
                 j;              /* Indexing */

     for( j = 1; j < 10; j++ )
     {
         k = k + j;
         l = k * j;
     }
     i = k + l;
     return( i );
 }

 void main()
 {
     int         (far _saveregs _loadds *fooaddr)();  /* foo() pointer */
     char        address[16];                         /* address to pass */

     printf( "Now inside parent main().\n" );
     fooaddr = foo;
     ultoa( (unsigned long)fooaddr, address, 10 );
     printf( "Address of foo(): %s\n", address );

     spawnlp( P_WAIT, "child.exe", "child.exe", address, NULL );
     printf( "Back inside parent main().\n" );
 }

 The following is the child program:

 /*
  *   CHILD.C
  */

 #include <stdio.h>
 #include <stdlib.h>

 void main(
     int         argc,
     char        **argv )
 {
     int         (far *fooaddr)();      /* Pointer to parent's function */
     int         i;                     /* Function return value */

     printf( "    Now in child.\n" );
     fooaddr = (void far *)atol( argv[1] );
     printf( "    Received: %ld\n", fooaddr );
     printf( "    Calling foo().\n" );
     i = fooaddr();
     printf( "        Result of foo(): %d\n", i );
     printf( "    Leaving child.\n" );
 }


 363. C: exec and spawn (P_OVERLAY) Will Fail When Bound

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | O_OS2SDK
 Last Modified: 15-JAN-1990    ArticleIdent: Q43319

 The Microsoft C run-time library functions exec and spawn (with a
 P_OVERLAY attribute) do not work correctly when executed in a bound
 application under DOS. This is briefly documented on Page 24 of the
 "Microsoft C for MS OS/2 and MS-DOS Operating Systems: Version 5.1
 Update" manual. The execution will fail with the program returning the
 following error message:

    run-time error R6006
    - bad format on exec

 This occurs only when the dual-mode program is running under DOS. A
 spawn with the P_WAIT attribute will work properly.

 Examining the DosExecPgm() API reveals that there is no option to
 overlay the currently executing program. OS/2's protection scheme does
 not support overwriting the code segment; therefore, to exec another
 program, it is necessary to actually spawn the program in a different
 area of memory and terminate the current process.

 To create a bound program that uses overlays, not only would a
 remapping of the FAPI function be necessary, but also a complete
 reprogramming to allow for loading over the current code segment. At
 this time, BIND does not support this.

 The following functions do not work properly when executed under DOS
 in a bound application:

    execl    execle  execlp   execlpe   execv    execve   execvp
    execvpe  spawnl  spawnl   spawnle   spawnlp  spawnlpe spawnv
    spawnve  spawnvp spawnvpe

 Note: The spawn functions fail only with the P_OVERLAY attribute.

 The following program will fail to spawn PROG.EXE from DOS:

 /* Program:  spawn.c                                      */
 /*                                                        */
 /* Compile and bind from OS/2 with:                       */
 /*                                                        */
 /*         cl /Lp spawn.c                                 */
 /*         bind spawn /c/lib/api.lib /c/lib/doscalls.lib  */

 #include <stdio.h>
 #include <process.h>

 void main(void)
 {
   spawnl(P_OVERLAY,"c:\\tmp\\prog.exe","prog",NULL);
 }


 364. How to Use _remappalette in EGA Modes

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43330

 When attempting to remap the palette in the EGA modes, follow the
 required format to form the argument passed to the remapping
 functions. This article uses _remappalette as an example. What is said
 about lColor (see function prototype below) also applies to the
 element of the array slColors for _remapallpalette.

 The function prototypes are as follows:

 short far _remappalette (nPixel, lColor) ;
 short nPixel ;
 long lColor ;                   Color number to assign nPixel to

 short far _remapallpalette (slColors) ;
 long far * slColors ;           Color array

 lColor is a long int formed by the following four bytes:

     00, blue byte, green byte, red byte

 The four bytes are arranged from the most significant byte to the
 least significant byte (left to right). The most significant byte is
 always "0" (zero). Each of the remaining three bytes can have the
 value of either 00, 2a, 15, or 3f. (In VGA mode, each byte can take
 any value between 00 and 3f.) Combinations of different values in the
 three bytes form the complete palette of 64 colors for the EGA
 graphics modes.

 The manifest constants for the EGA modes are _MRES16COLOR,
 _HRES16COLOR, and _ERESCOLOR, which are used with the function
 _setvideomode.

 Please refer to the include file "GRAPH.H" for the default values of
 the 16 colors in an EGA mode.

 An algorithm is provided in this section to convert a color
 represented by an arbitrary number from 0 - 63 to the required format.
 A sample program is included that implements the algorithm.

 Suppose the color is represented by a byte, as follows:

    bit7 , bit6 , bit5 , bit4 , bit3 , bit2 , bit1 , bit0

 1. bit7 and bit6 can be ignored, because the byte is always less than
    64.

 2. The remaining bits are grouped in the following three pairs, where
    the order of the two bits in the pair is significant:

    bit3 , bit0 ;
    bit4 , bit1 ;
    bit5 , bit2 ;

 3. Each pair is mapped to 00, 2a, 15, or 3f, according to the
    following table:

    bitX   bitY   MappedXY
      0      0      00
      0      1      2a
      1      0      15
      1      1      3f

 4. Mapped30 (from pair bit3, bit0) goes to the blue byte.
    Mapped41 (from pair bit4, bit1) goes to the green byte.
    Mapped52 (from pair bit5, bit2) goes to the red byte.

    The order (from high to low) of the three bytes is as follows:

       blue byte  ,  green byte  ,  red byte

 5. Example:

    Color 43 has bit pattern 0 0 1 0 1 0 1 1. This pattern is
    transformed to three pairs : 11, 01, 10. The three pairs are mapped
    to 3f, 2a, 15. The mapped color represented in long integer format
    is 0x3f2a15.

 The following program uses _remappalette to remap the color "0" (which
 defaults to black) to the 64 different colors:

 // file : palette.c

 #include <stdio.h>
 #include <graph.h>
 #include <conio.h>

 #define NUMCOLOR        64
 #define MASK            0x0001

 unsigned long ConvertColNum (unsigned int) ;

 unsigned char ConvertArr [4] = { 0x00, 0x2a, 0x15, 0x3f } ;

 void main (void)
 {
 unsigned short nColor = 0 ;
 unsigned int i ;
 unsigned long lMappedColor ;

 if (!_setvideomode (_ERESCOLOR))
     return ;

 puts ("Press any key to continue ...") ;
 getch () ;

 for (i = 0 ; i < NUMCOLOR ; i++)
     {
     lMappedColor = ConvertColNum (i) ;
     if (_remappalette (nColor, lMappedColor) == -1L)
         puts ("\x007Mapping color failed : ") ;  // beep if fails

     printf ("Color number = %u, lMappedColor = %08lx\n", i,
             lMappedColor);
     if (getch () == 'q')
         break ;
     }

 _setvideomode (_DEFAULTMODE) ;
 }

 unsigned long ConvertColNum (unsigned int nOrgColor)
 {
     unsigned long lColor, lTemp ;
     int j, temp ;

     lColor = 0L ;
     for (j = 0 ; j < 3 ; j++)
         {
         // get the pair
         temp = ((nOrgColor >> (j + 3) & MASK) << 1 ) |
                 (nOrgColor >> j & MASK) ;
         lTemp = (unsigned long) ConvertArr [ temp ] ;
         lColor |= lTemp << ((2-j) << 3) ;      // (2-j) * 8
         }

     return (lColor) ;
 }


 365. Changing System Time or Date Will Temporarily Pause Clock

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43331

 The system clock temporarily pauses when the time or the date is set.
 This feature prevents cases in which the date or time may need to be
 updated during the actual time change. For example, an attempt to set
 the system date exactly at midnight using _dos_setdate would not
 produce the desired effect if the system changed the date at the same
 time it was being set. Therefore, the system clock pauses.

 The effects of such a pause can be seen in the sample program that
 follows. If you run this program, you will find upon exit that the
 system time is the same as when the program was started.

 The following is the sample program:

 /* Note - this code takes a couple of minutes to run */
 #include <stdio.h>
 #include <dos.h>

 struct dosdate_t Date;
 struct dostime_t Time;
 unsigned long loop;

 void main(void)  {
    _dos_getdate(&Date);       /* Show time when starting */
    _dos_gettime(&Time);
    printf ("Today's date is %d-%d-%d\n", Date.month, Date.day,
            Date.year);
    printf ("Start time = %d:%d\n", Time.hour, Time.minute);

    Date.year = 1988;
    for (loop = 1; loop <= 200000; loop++) {
       _dos_setdate(&Date);
    }

    _dos_getdate(&Date);       /* Show time after loop */
    _dos_gettime(&Time);
    printf ("Date is now %d-%d-%d\n", Date.month, Date.day, Date.year);
    printf ("End time = %d:%d\n", Time.hour, Time.minute);
 }



 366. Handling Floating-Point Errors in C

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q43391

 You can set up a floating-point error-handling routine by using the
 signal() function. Do not use the return() function to return to the
 calling process. If return() is used, the floating-point state is left
 undefined.

 Instead, use the function setjmp() to save the stack environment
 before each section of the calling process code that may potentially
 generate a floating-point error. In the error handler, use _fpreset()
 to reinitialize the floating-point package and longjmp() to return to
 the calling process.

 The sample program on Page 280 of the "Microsoft C Run-time Library
 Reference" demonstrates the use of setjmp(), _fpreset(), and longjmp()
 to handle a floating-point error.

 The function setjmp() saves the environment (bp, si, di, sp, and ds
 registers) and return address in a buffer. The buffer is used by
 longjmp() to restore the environment.


 367. C: Clarification of the "g" Format Specifier

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43392

 The output format resulting from the printf() format specifier "g"
 does not exactly match the output format resulting from either format
 specifier "e" or "f." Page 459 of the "Microsoft C Run-Time Library
 Reference" states that "g" will use either the "f" or "e" format,
 whichever is more compact.

 The precision value is interpreted differently in "g" format than in
 "f" format. Table R.3 on Pages 461-2 states the difference. The
 precision for "f" specifies the number of digits after the decimal
 point. The precision for "g" specifies the maximum number of
 significant digits printed.

 The following example demonstrates the difference:

 #include <stdio.h>

 void main (void)
 {
   printf ("%.4g\n", 4.0/3.0);    /* Outputs:  1.333  */
   printf ("%.4f\n", 4.0/3.0);    /* Outputs:  1.3333 */
 }

 The results of the above program are correct.


 368. C: _bios_timeofday Documentation Error

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-APR-1989    ArticleIdent: Q43396

 On Page 146 of the "Microsoft C 5.1 Optimizing Compiler Run-Time
 Library Reference" manual and the "Microsoft QuickC Run-Time Library
 Reference" manual, the second parameter of _bios_timeofday is
 incorrectly stated as a long integer, as follows:

    long timeval;

 The corrected declaration is a pointer to a long integer, as follows:

    long *timeval;


 369. Incorrect Reference to Preprocessor Directives in User's Guide

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-APR-1989    ArticleIdent: Q43398

 Section 3.3.9 on Page 75 of the "Microsoft C 5.1 Optimizing Compiler
 Users' Guide" has a documentation error at the bottom of the second
 paragraph.

 The paragraph refers to Section 8 of the "Microsoft C Quick Reference
 Guide"; however, Section 8 does not exist. The actual location of the
 information is in Part 2 on Pages 30-32 of the Quick Reference Guide.
 This section contains a listing of the preprocessor directives.


 370. How to Test for an Error When Using _bios_serialcom Service

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc docerr
 Last Modified: 14-APR-1989    ArticleIdent: Q43401

 Problem:

 I am using the _COM_RECEIVE function of _bios_serialcom to read data
 from a communications port. How do I determine if an error has
 occurred?

 Response:

 Referring to the table on Page 144, Page 145 of the "Microsoft
 Optimizing C Run-Time Library Reference" and the "Microsoft QuickC
 Run-Time Library Reference" states the following:

    If an error occurs, at least one of the high-order bits will be
    set.

 While this is correct, it is misleading. It is true that at least one
 of the high-order bits will be set if an error occurs. However, it is
 not true that if ANY high-order bit is set, an error has occurred. An
 error has occurred if, and only if, any of the following four bits are
 set:

    Bit     Meaning if Set

    15      Timed out
    11      Framing error
    10      Parity error
     9      Overrun error

 The sentence quoted above would be more accurate if it read as
 follows:

    If an error occurs, any of bits 9, 10, 11, or 15 will be set.

 This information is explained on Page 431 of "Advanced MS-DOS" by
 Ray Duncan.


 371. The Storage of Environment Variables

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 17-MAY-1989    ArticleIdent: Q43428

 Question:

 How can I find out where the environment variables (PATH, LIB, etc.)
 are being stored?

 Response:

 The environment variables are stored in the near heap, which is part
 of DGROUP. The ENVIRON variable is an array of pointers to the strings
 that constitute the process environment. The C start-up code takes the
 environment information and initializes the ENVIRON variable to point
 to the environment table. The function getenv() uses the ENVIRON
 variable to access the environment table. ENVIRON can be used to
 obtain the environment table address directly.

 The following program will print out the address of the beginning of
 the environment table and the PATH environment variable:

 #include <stdlib.h>
 #include <stdio.h>

 char *path;

 void main (void)
 {
   path = getenv( "PATH" );
   printf( "path: %s\nenviron: %x\n", path, environ );
 }


 372. Why _setvideomode() May Fail to Set Some Modes

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC setvideomode _setvideomode
 Last Modified: 25-MAY-1989    ArticleIdent: Q43587

 The following are possible reasons that _setvideomode() might fail
 when attempting to set a video mode:

 1. Some of the older IBM EGA (enhanced graphics adapter) cards only
    have 64K of video memory. As such, they cannot display the
    640 x 350 16 (_ERES16COLOR) color EGA mode. However,
    lower-resolution modes may work correctly because they don't
    require that much memory.

 2. There are EGA cards that have dip-switch settings to set the card
    into high- or low-resolution modes. Some BIOS ignore these dip
    switches and set the mode to high resolution. However, the
    _setvideomode() function does its own checking and may honor the
    dip-switch settings depending on the particular card. Setting the
    dip switches properly for the high-resolution modes should resolve
    the problem.

 3. The video card may not support the requested mode. If the card does
    not support the mode, then _setvideomode() cannot set it into that
    mode.

 4. Many VGA cards have non-standard extended modes that are unique to
    those cards. _setvideomode() supports only standard video modes
    and, thus, will not recognize the extended modes.


 373. C: Loop Optimization Causes Internal Compiler Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 26-SEP-1989    ArticleIdent: Q43700

 The two programs shown below demonstrate the following internal
 compiler error. The error occurs in the Microsoft C Optimizing
 Compiler Version 5.10, when compiled with loop and alias relaxation
 optimization enabled, and either the compact or large-memory models.

     fatal error C1001 : Internal Compiler Error
        (compiler file '@(#)regMD.c:1.117', line 1861)
        Contact Microsoft Technical Support

 An easy workaround is to not use the /Oal combination, or use a
 different memory model.

 The first program is as follows:

 int flags = 0;                         /* change to int j, flags = 0 */
 void main(int argc, char *argv[])
 {
     int i,j;                           /* change to int i; */
     for (i=1; i<argc; i++)
         switch(argv[i][0]) {
             case '-':
                 for (j=1; argv[i][j]; j++)
                     switch (argv[i][j]) {
                         case 'a' : flags |= 0x1; break;
                         case 'b' : flags |= 0x2; break;
                         case 'c' : flags |= 0x4; break;
                         case 'd' : case '?': default: flags = 0x8; break;
                     }
        }
 }

 To work around this problem, move the declaration of "j" outside of
 main().

 The second program is as follows:

 typedef struct  LINE {
         short   l_used;
         char    l_text[1];
 }       LINE;

 typedef struct  WINDOW {
         LINE *w_dotp;
 }       WINDOW;

 extern  WINDOW  *curwp;

 void main()
 {
         int    nicol;
         int    c;
         int    i;

         for (i=0; i< curwp->w_dotp->l_used; ++i) {
                 c = curwp->w_dotp->l_text[i]&0xFF;
                 if (c!=' ' && c!='\t')
                         break;
                 if (c == '\t')
                         nicol |= 0x07;
                 ++nicol;
         }
 }

 You can work around this problem by adding a new variable of type
 pointer to WINDOW and then using this pointer in the assignment to the
 variable "c". For example, you can change the for loop in the code to
 appear as follows:

         for (i=0; i< curwp->w_dotp->l_used; ++i) {
               WINDOW *foo1;
                 foo1 = curwp;
                 c = foo1->w_dotp->l_text[i]&0xFF;

                 if (c!=' ' && c!='\t')
                         break;
                 if (c == '\t')
                         nicol |= 0x07;
                 ++nicol;

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


 374. C: srand() Sample Program Does Not Print Out the Array Values

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | DOCERR S_QuickC
 Last Modified: 22-MAY-1989    ArticleIdent: Q43808

 In the following manuals, the sample program given for the function
 srand() implies that it will print out random values for each of the
 array elements. Although the array is filled with random values, these
 values are not printed because the "for" loop is implemented
 incorrectly. This example is given in both the "Microsoft C for the
 MS-DOS Operating System Run-Time Library Reference" manual for
 Versions 5.00 and 5.10, and the "Microsoft QuickC Run-Time Library
 Reference" manual for Versions 1.00 and 1.10.

 The following source code fragment is excerpted from the sample
 program found in the "Microsoft QuickC Run-Time Library Reference"
 manual on Page 564.

     srand(17);
     for (x = 0; x < 20; ranvals[x++] = rand())
       printf("Iteration %d, ranvals[%d] =%d\n",x+1, x, ranvals[x]);

 If you execute the program as written, it produces a list of all zeros
 instead of a list of the random numbers being put into the array. To
 understand why this is so, the definition of a for loop must be
 considered. The for loop defined by Kernighan and Ritchie is as
 follows:

     for (expr1, expr2, expr3)
         statement;

     is equivalent to:

     expr1;
     while (expr2)
        {
        statement;
        expr3;
        }

 If the above sample program is substituted into this definition, then
 the program reads as follows:

     srand(17);
     x = 0;
     while (x < 20)
        {
        printf("Iteration %d, ranvals[%d] =%d\n",x+1,x,ranvals[x]);
        ranvals[x++] = rand();
        }

 This program obviously prints the array elements one step before they
 are initialized, which is why the sample program prints out all zeros
 instead of the desired random numbers.

 To display the correct results, you must take the call to  the
 function rand() out of expr3 of the for statement. This can be
 accomplished as follows:

     srand(17);
     for (x = 0; x < 20; x++)
        {
        ranvals[x] = rand();
        printf("Iteration %d, ranvals[%d] =%d\n",x+1, x, ranvals[x]);
        }


 375. Casting a Pointer to a Type Equivalent to a Multidimensional

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-MAY-1989    ArticleIdent: Q43703

 In some situations you may need to cast a pointer or an address to a
 type that is equivalent to a multidimensional array. The following
 example demonstrates such a situation:

     typedef char Arr2Dim [][20] ;
     void foo (Arr2Dim) ;
     char * ptr ;
     ...
     void main (void)
     {
         ...
         foo ( (Arr2Dim) ptr ) ;  /* illegal */
         ...
     }

 Casting the variable "ptr" to the array type "Arr2Dim" is illegal. The
 Microsoft C Compiler displays the following error message:

    error C2067: cast to array type is illegal

 The correct procedure is to cast the pointer "ptr" to a pointer type
 equivalent to the array type Arr2Dim. This pointer type can be defined
 as follows:

    typedef char (*Ptr2Dim) [20] ;

 Casting "ptr" to the type of "Ptr2Dim", as follows, is legal and
 produces no warning messages when compiled at warning level 3:

    foo ( (Ptr2Dim) ptr ) ;

 The address (or pointer) passed to the function will be used
 correctly.

 A similar solution could be applied to the problem of dynamically
 allocating a multidimensional array. For example, the following code
 fragment will allocate a memory block, which can be used as a 10 x 20
 x 30 three-dimensional array:

     typedef char (*Ptr3Dim) [20][30] ;
     Ptr3Dim ptr3arr ;
     ...
     void main (void)
     {
         ...
         ptr3arr = (Ptr3Dim) malloc (10 * sizeof(char) * 20 * 30) ;
         ...
     }

 After the allocation, "ptr2arr" can be used as a three-dimensional
 array, as follows, provided i, j, and k are integers within the proper
 range:

    ptr2arr [i][j][k] = 'a' ;


 376. Changes in scanf() and printf() for Long Types in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 19-SEP-1989    ArticleIdent: Q43809

 As of Version 5.10 of the Microsoft C Optimizing Compiler and Version
 1.00 of the QuickC compiler, the scanf() and printf() functions no
 longer support the uppercase D, O, and I type characters, which
 represented long-integer fields.

 Current versions of Microsoft C compilers precede the type characters
 in the format portion of the printf() and scanf() functions with an
 "l"  (lowercase letter "l") to specify long-type fields.

 The uppercase "X" format specifier also has been changed; it now
 specifies that uppercase letters are to be used when displaying
 hexadecimal numbers in a printf() statement.

 The following code fragment reads an integer into a variable and then
 displays the value of the variable:

 int i;
 scanf( "%d", &i );
 printf( "%d", i );

 The following code fragment accepts and displays the value of a long
 integer variable:

 long i;
 scanf( "%ld", &i );
 printf( "%ld", i );


 377. C: PUSH CS Caused by Far Call Translation

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 22-MAY-1989    ArticleIdent: Q43810

 Question:

 When I look at an assembly listing generated by the Microsoft C
 Version 5.10 Optimizing Compiler, I notice that the compiler produced
 PUSH CS instructions. Should the compiler be generating PUSH CS
 instructions?

 Response:

 One of the optimizations made by the Microsoft C 5.10 compiler is Far
 Call Translation. Far Call Translation optimization results in
 slightly faster code and smaller executable files.

 The compiler normally generates far calls and corresponding far
 returns for large and medium-memory-model programs. Far Call
 Translation is performed if optimizations are enabled and a call is
 being made from one function to another in the same source file. The
 usual CALL FAR LABEL is replaced with the following instruction
 sequence:

         PUSH CS
         CALL NEAR LABEL

 The called function is in the same code segment because it is located
 in the same source file, so a near call is possible in this case. The
 PUSH CS instruction allows the far return from the called function to
 retrieve CS from the stack and return to the correct location.


 378. Fscanf() and White-Space Characters

 Product Version(s): 5.00 5.10  |  5.10
 Operating System:   MS-DOS     |  OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50116

 Problem:

 I try to read one integer on a line from a data file and then advance
 the file pointer to the next line using the following:

     fscanf("%d\n", &INT);

 However, I am unable to do this. The file pointer seems to jump to the
 next character in the data file, wherever it may be, instead of
 stopping at the first position of the next line.

 Response:

 According to the "Microsoft C for the MS-DOS Operating System Run-time
 Library Reference," Page 501:

    A white-space character (in the format string) causes scanf to
    read, but not store, all consecutive white-space characters in the
    input up to the next non-white-space character. One white-space
    character in the format matches any number (including 0) and
    combination of white-space characters in the input.

 In other words, because you have white space in your format specifier,
 "\n", after the %d, fscanf() eats up all white space AFTER the
 integer, including newline until the first nonwhite-space character is
 found.

 The following are possible workarounds:

 1. Use the following fscanf() statement:

       fscanf("%d[^\n]%*c}, &INT)

    This tells fscanf() to read an integer and then read UNTIL it finds
    the "\n". At that point, it is necessary to read in the \n. The
    "%*c" reads, but does not store, one character.

 2. Use fgets() to read in the line and then use sscanf to get the
    value, as follows:

       fgets( line, MAX_LINE_SIZE, stream );
             sscanf( line, "%d", &INT);


 379. Determining the Memory Model for Conditional Compilation

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_QuickC
 Last Modified: 25-JUL-1989    ArticleIdent: Q44386

 There is a predefined identifier that can be used to allow the
 preprocessor to determine which memory model has been chosen for the
 current compilation. The identifier is M_I86?M, where "?" is an
 identifier for one of the following five memory models:

    S = Small
    M = Medium
    L = Large
    C = Compact
    H = Huge

 This identifier can be used with a preprocessor command to produce
 conditional compilation dependent upon the memory model. An example of
 its use is shown below. For more information, refer to the include
 file MALLOC.H, which uses the identifier to determine which variant of
 the memory allocation function "malloc" should be used in the current
 compilation.

 Code Example
 ------------

 /*
  *
  * This example demonstrates how to use the C compiler M_I86?M values.
  * It also shows other various preprocessor components. The
  * memory model is displayed using the message() pragma. If the memory
  * model is not recognized by the program, the compilation terminates
  * using the #error preprocessor directive. The identifier _MEMORY_MODEL_
  * has been chosen arbitrarily, and has no special value to the C compiler.
  *
  */

 #include <stdio.h>

 #if defined (M_I86CM)
     #define _MEMORY_MODEL_ "compact"
 #elif defined (M_I86SM)
     #define _MEMORY_MODEL_ "small"
 #elif defined (M_I86MM)
     #define _MEMORY_MODEL_ "medium"
 #elif defined (M_I86LM)
     #define _MEMORY_MODEL_ "large"
 #elif defined (M_I86HM)
     #define _MEMORY_MODEL_ "huge"
 #else
     #error "ERROR: unknown memory model!!"
     #define _MEMORY_MODEL_ "**UNKNOWN**"
 #endif

 #pragma message ("Using the " _MEMORY_MODEL_ " memory model...")

 void main(void);

 void main(void)
 {
    printf("hello, world\n");
 }


 380. C: Finding the Length of Double Precision Decimals

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890424-17022 s_quickc
 Last Modified: 22-MAY-1989    ArticleIdent: Q43913

 Question:

 Is there a straightforward way to determine how many decimal digits
 are required to fully represent the integer and fractional portions of
 a double floating-point number?

 Response:

 The most straightforward method is to convert the double to a string,
 locate the decimal point, and then calculate the length of the
 substrings before and after it.

 The following example demonstrates the technique:

         #include <stdio.h>
         #include <string.h>
         #include <ctypes.h>

         char str[30];
         double stuff;
         int dec_pos, places_after, places_before;

         ...

         sprintf(str, "%f", stuff);
         dec_pos = strcspn( str, "." );
         places_after = strlen( str ) - dec_pos - 1;
         places_before = dec_pos - !isdigit( str[0] );

 The strcspn function returns the position in str at which "." is
 found. The isdigit() function accounts for the presence or absence of
 a minus or plus sign. The sequence of steps in the string "-1253.356"
 results in the following values:

     dec_pos == 5
     places_after == (9 - 5 - 1) == 3
     places_before == (5 - 1) == 4


 381. C: Text Modes Don't Return Pixel Information

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 11-JAN-1990    ArticleIdent: Q43914

 After a call to _getvideoconfig () from text modes, the structure
 videoconfig contains zero (0) for numxpixels, numypixels, and
 bitsperpixel. This is expected behavior because only the graphics
 modes return pixel information.

 Both text and graphics modes return information about the number of
 text columns and rows.

 The following example demonstrates the absence of pixel information
 in text modes. The name of each text mode begins with "_TEXT."

 #include stdio.h
 #include graph.h

 struct videoconfig vc;  /* variable vc of type videoconfig */

 /* define an array of video modes and mode names
    since the numbers are not continuous */

 int modes[12] = {_TEXTBW40, _TEXTC40, _TEXTBW80, _TEXTC80,
     _MRES4COLOR, _MRESNOCOLOR, _HRESBW, _TEXTMONO,
     _MRES16COLOR, _HRES16COLOR, _ERESNOCOLOR, _ERESCOLOR};

 char *modenames[] = {"TEXTBW40", "TEXTC40", "TEXTBW80",
                       "TEXTC80", "MRES4COLOR", "MRESNOCOLOR",
                       "HRESBW", "TEXTMONO", "MRES16COLOR",
                       "HRES16COLOR", "ERESNOCOLOR", "ERESCOLOR"};s0
 main()
 {

    int i;
    /* test all video modes */
    for (i=0; i<= 11; i++) {
        _setvideomode (modes[i]);
        _getvideoconfig (&vc);
        printf ("\n video mode: \t%s\n",modenames[i]);
        printf (" x pixels: \t%d\n",vc.numxpixels);
        printf (" y pixels: \t%d\n",vc.numypixels);
        printf (" text columns: \t%d\n",vc.numtextcols);
        printf (" text rows: \t%d\n",vc.numtextrows);
        printf (" # of colors: \t%d\n",vc.numcolors);
        printf (" bits/pixel: \t%d\n",vc.bitsperpixel);
        printf (" video pages: \t%d\n",vc.numvideopages);
        printf (" Hit return for next video mode");
        getchar();
        _clearscreen (_GCLEARSCREEN);
    }
    _setvideomode (_DEFAULTMODE);
 }

 The definition of structure videoconfig and the arguments to
 _setvideomode() are contained in the include file graph.h. The
 arguments for _setvideomode() are also present on Page 539 of the
 "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference."


 382. qsort(): Parameters to the Compare Function

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 22-MAY-1989    ArticleIdent: Q43971

 When you define or prototype a comparison function for the run-time
 library function qsort(), the formal parameters should be of type
 "pointer to the type of the array element." This is because qsort()
 passes the addresses of the array elements to the comparison function.

 If the declaration of the array to be sorted is

    ELEMENT_TYPE arr[10] ;

 where ELEMENT_TYPE is the type of the array elements, then the
 function for comparison should be prototyped as follows:

    int comp( ELEMENT_TYPE *, ELEMENT_TYPE * ) ;

 If arr is declared instead as an array of pointers to structure foo,
 then the declaration and prototype should be as follows:

    struct foo * arr[10] ;
    int comp( struct foo **, struct foo ** ) ;


 383. How to Flush the Keyboard Typeahead Buffer

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-MAY-1989    ArticleIdent: Q43993

 To flush the BIOS keyboard typeahead buffer, the DOS function 0xC may
 be used. This function clears the keyboard typeahead buffer and then
 invokes a reading function specified in the AL register. The AL
 register can be 0x01, 0x06, 0x07, 0x08, or 0x0A to specify a valid
 reading function. If you do not intend to read after flushing the
 buffer, you may specify an invalid number in AL.

 Another method of flushing BIOS's buffer is to call the console I/O
 function getch() until the function kbhit() becomes false. This
 method is demonstrated in the program below and has the advantage of
 being usable under OS/2 as well as DOS.

 The buffer implemented by the C run-time functions for the stream
 "stdin" is different from the BIOS keyboard typeahead buffer. To clear
 the buffer for stdin, use the function fflush(). However, this method
 will not flush BIOS's buffer. To be totally flushed, you must both
 flush BIOS's buffer as described above in this article AND call fflush
 for stdin.

 The following sample program is provided for demonstration:

 // sample program
 #include <stdio.h>
 #include <time.h>
 #include <conio.h>
 #include <dos.h>

 void main (void)
 {
 time_t start, work ;
 char str [50] ;

 puts ("type for getchar(). Go to stdin's buffer.") ;
 // user can type more than one character and an Enter.
 getchar () ;

 puts ("Type fast, 5 seconds. Go to BIOS buffer.") ;
 // user can type anything including multiple Enters.
 time (&start) ;
 work = start ;
 while ( (work - start) < 5 ) time (&work) ;

 bdos (0xC, 0, 0) ;       // clear BIOS keyboard buffer

 //  Alternative method:
 //  while (kbhit()) getch();

 fflush (stdin) ;         // clear stdin's buffer
 puts ("Should be waiting again.") ;

 gets (str) ;
 puts (str) ;
 }


 384. SETUP /L Does Not Create SETARGV.OBJ in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 22-MAY-1989    ArticleIdent: Q44001

 Invoking C Version 5.10 SETUP with the /L command (to rebuild the
 libraries) should create xSETARGV.OBJ (where x = S,M,C,L) for each
 memory model chosen if a "C 4.00 compatible names for SETARGV.OBJ"
 option is requested during setup. However, when the Setup program is
 invoked with the /L command, it does not generate SETARGV.OBJ for any
 memory model. Setup does not even copy that file to the destination
 drive; only the setup for the whole compiler creates xSETARGV.OBJ for
 different memory models.

 C 4.00 has four model-specific object modules, xSETARGV.OBJ (where x =
 S,M,C,L), which you can link into a program to get wild-card expansion
 for program arguments. In C 5.10 there is only one object SETARGV.OBJ
 needed for ALL memory models. However, if you have MAKE files which
 rely on the C 4.00 convention, you may want to tell the Setup program
 to make COPIES of this file with the appropriate model-specific name.
 In fact, the modules of xSETARGV.OBJ are all identical and differ only
 in their names. Renaming SETARGV.OBJ is all that is required.

 Therefore, if you are using SETUP just to rebuild the libraries and
 have chosen C 4.00 compatibility, you must find SETARGV.OBJ on the
 disk labeled "Floating-Point Libraries" and you must copy/rename that
 file to suit the memory model(s) you have built.


 385. DOS Append Interfaces with execvp() in C

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q44033

 The versions of the exec and spawn (with P_OVERLAY) functions that
 search the path for the child program to be run, fail with run-time
 error "R6005 not enough memory on exec" if the child is not in the
 current directory and the DOS APPEND command points to the child's
 directory.

 The DOS Versions 3.30 and later APPEND command is used to specify
 directories for locating data files.

 APPEND incorrectly finds .EXE and .COM files when DOS interrupt 21
 hex, function 3D hex (open file) is called. This can cause the C
 library function sopen() to mistakenly report that it has succeeded in
 finding a .COM or .EXE file in the current directory when, in fact,
 the file is in another directory that is pointed to by APPEND.

 The path-searching versions of the exec and spawn (with P_OVERLAY)
 functions use sopen() to first try to open the .COM or .EXE file in
 the current working directory. If sopen() fails because the file is
 not there, successive directories specified by the PATH are prepended
 to the child's filename, and sopen() is called again until it
 successfully opens the child's file in one of the directories
 specified by the PATH.

 If the child is not in the current working directory, but is pointed
 to by APPEND, sopen() mistakenly reports that it has successfully
 opened the child in the current directory and the necessary path is
 not prepended to the child's filename. When the exec/spawn functions
 call DOS interrupt 21 hex, function 4B hex, subfunction 3 (load and
 execute overlay program), the child can't be found in the current
 working directory, and the exec fails. (Unlike DOS function 3D hex to
 open a file, DOS function 4B hex is not affected by APPEND.) At this
 point, the only error C exec/spawn functions are designed to report is
 that there isn't enough memory available for the child process, and
 the R6005 error is issued.

 The path searching exec/spawn functions that can be adversely affected
 by APPEND are execlp, execlpe, execvp, execvpe, spawnlp, spawnlpe,
 spawnvp, and spawnvpe. The spawn functions using P_WAIT are not
 affected by APPEND since they do not use sopen().

 The Microsoft C run-time library functions do not support the use of
 APPEND. There are no plans to do so in the future.

 To work around problems caused by APPEND, disabling APPEND with the
 DOS command "APPEND;" is recommended. Or, within a program, you may
 use the system() library function for this purpose (except for
 versions of DOS that support the /E APPEND option to place APPEND in
 the environment table). If your program needs to accommodate APPEND,
 you could use the _searchenv() function to obtain the path. Then
 traverse the path prepending successive drive and directory names to
 the child's filename for use with sopen() until an sopen() call
 returns a valid file handle indicating the child program has been
 found. Once you have the exact path of the .EXE or .COM file, pass
 the complete path the the appropriate exec?? or spawn?? function.

 Note: DON'T use one of the functions that has a "p" in its name --
 these functions search the path for the file, something you've
 already done if you've followed these directions.


 386. Using Presentation Graphics/Fonts with C 5.00 and C 5.10

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 25-JUL-1989    ArticleIdent: Q44076

 It is possible to use the QuickC Version 2.00 presentation graphics
 and fonts library functions with C 5.00 or C 5.10. However, you must
 be certain that all of the header files and libraries are from the
 QuickC 2.00 package. If you attempt to compile a presentation graphics
 program with C 5.10 and keep getting "unresolved external" messages
 after carefully linking in GRAPHICS.LIB and PGCHART.LIB, reinstall the
 default library and GRAPHICS.LIB from the QuickC 2.00 distribution
 disks. Mixing the C 5.10 and QuickC 2.00 libraries results in this
 behavior.

 Please note that the QuickC 2.00 libraries do not support alternate
 math. The QuickC 2.00 and the C 5.10 libraries cannot be mixed.
 Therefore, there is no support for the alternate math package under C
 5.10 when using presentation graphics or font library functions.

 The unresolved externals that you get when mixing libraries are not
 functions; they are the names of support routines and new variables
 that do not exist in the default library or GRAPHICS.LIB from the C
 5.10 package.


 387. Allocation of Variables within Blocks in C

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 23-MAY-1989    ArticleIdent: Q44078

 The "Microsoft C for the MS-DOS Operating System: Language Reference"
 manual in Section 3.5.2 states the following:

    An item with a local lifetime (a "local item") has storage and a
    defined value only within the block where the item is defined or
    declared. A local item is allocated new storage each time the
    program enters that block, and it loses its storage (and hence its
    value) when the program exits the block.

 This statement is true for function blocks. All nonstatic variables
 within a function, whether they are within a block or not, are
 allocated space from the stack upon entry to the function.

 According to the ANSI standard, the C language should support jumps
 into blocks. To ensure that variables always are allocated, regardless
 of the entry point into the block, the space for local variables
 within a block must be allocated upon entry of the function, not the
 block. Consider the following code example:

 int checkup (int var)
 {
       .
       .
       .
     if (var)
        goto test2;
     else
     {
        char buffer[80];
          strcpy (buffer, "This is a different test");
        test1:
          strcpy (buffer, "This is a test");
            .
            .
            .
     }
     test2:
        printf("testing stuff is coming up next");
        goto test1;
     return (0);
 }

 Although this is not the best way to implement this code sample, this
 method should be legal, according to the ANSI standard. If the block
 is entered through the label test1, and the array of characters has
 not been allocated on the stack previously, the strcpy after the test1
 label does not work properly. To ensure that "buffer" is allocated
 space, it is allocated stack space upon entry to the function, and not
 upon entry to the block.

 Note: The 80-character buffer is removed from the stack upon exit from
 the block, and not upon exit from the function.


 388. File Buffers Are Not Allocated until First Accessed

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 22-MAY-1989    ArticleIdent: Q44178

 Problem:

 I am using _memavl() to determine the amount of free space on the near
 heap. When I use fgets(), the amount of near heap space decreases by
 512 bytes.

 Response:

 File buffers are not allocated when the file is first opened. The
 512-byte buffer is allocated on the near heap when the file is first
 accessed. The buffer will be used by the file until the file is
 closed. At that time, the buffer space will be freed to the system.

 File buffers are allocated in the near heap for small and medium
 memory models and in the far heap for compact and large memory models.
 _memavl() returns the amount of free space on the near heap only.

 The following program, compiled in small or medium memory model,
 illustrates this behavior:

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

 FILE *fp;

 void main(void)
 {
   char bufs[64];

   printf("Start of program \n");
   Bytes_free();
   fp=fopen("file1.txt","r");

   printf("file1.txt has been opened \n");
   Bytes_free();

   fgets(bufs,5,fp);
   printf(" file has been accessed \n");
   Bytes_free();

   fclose(fp);
   printf(" file has been closed \n");
   Bytes_free();
 }

 Bytes_free()
 {
   printf("\nHeap bytes free: %u \n", _memavl()  );
 }


 389. BIND: "Structure Error in .EXE File" Caused by Non-FAPI Call

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890502-17544
 Last Modified: 22-MAY-1989    ArticleIdent: Q44205

 A possible cause of the BIND error message "Structure error in .EXE
 file" is calling a non-FAPI function from within the program to be
 bound.

 The solution is to be sure to call only FAPI functions or to follow
 the directions in the BIND documentation for programs that make
 non-FAPI calls.


 390. Example for freopen Is Incorrect in C, QuickC Manuals

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC docerr
 Last Modified: 19-SEP-1989    ArticleIdent: Q44207

 There is an error in the sample program given on Page 295 of the
 "Microsoft C Optimizing Compiler Run-Time Library Reference" for the
 freopen() function. The first fprintf() function call should be
 changed to a printf().

 This error is also present in the QuickC Versions 1.00, 1.01, and 2.00
 run-time library reference manuals. The sample program has been
 changed in the QuickC 2.00 on-line help example and is correct there.


 391. How to Use the ERROUT Utility

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | H_FORTRAN H_MASM docerr
 Last Modified: 19-SEP-1989    ArticleIdent: Q44388

 Question:

 How do I use the ERROUT utility? Examples in the "Microsoft C 5.1
 Optimizing Compiler/CodeView and Utilities" manual do not seem to
 work.

 Response:

 ERROUT divides its output into two parts: the standard output and the
 standard error output. If ERROUT is used without the /f switch, error
 output is sent to standard output. (Normally, error output is sent to
 the console regardless of where standard output is redirected.) The
 printed documentation on ERROUT is in error on this point.

 Therefore, you must use the ERROUT utility with DOS redirection
 operators ">" or ">>", as in the following example:

    ERROUT /f err.doc cl test.c > std.doc

 The file STD.DOC contains the standard output and the file ERR.DOC
 contains the errors. If there is no error output, the file ERR.DOC
 will be zero bytes long.

 To send error output and standard output to the printer, use the
 following commands:

    ERROUT cl test.c > PRN

 To send error output to the printer and standard output to the
 console, use the following commands:

    ERROUT /f PRN cl test.c

 To send error output to the console and standard output to the
 printer, use the following commands:

    cl test.c > PRN


 392. Only Certain C Library Functions Have an Intrinsic Form

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-MAY-1989    ArticleIdent: Q44389

 The /Oi compiler option generates intrinsic functions instead of
 function calls only for specified run-time library functions. It does
 not generate intrinsic functions for all run-time library functions or
 for application program functions.

 To approximate intrinsic functions with application code, use the
 #define directive or the /D compiler option to define a macro.

 For more information on the /Oi option and the list of functions
 having intrinsic forms, refer to the "Microsoft C 5.1 Optimizing
 Compiler User's Guide," Pages 93-94, and the C 5.10 README.DOC, "Part
 2: Notes for the 'Microsoft C Optimizing Compiler User's Guide.'"


 393. How to Spawn C 5.10 Compiler Passes without CL.EXE

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890503-17633 c1.exe c2.exe c3.exe
 Last Modified: 22-NOV-1989    ArticleIdent: Q44413

 Question:

 How can I run the individual compiler passes, C1, C2, and C3, instead
 of CL.EXE? There isn't enough memory available from my editor to spawn
 to CL.EXE, but I suspect there may be enough if I call the individual
 compiler passes.

 Response:

 There are a number of problems here. First, the CL.EXE program passes
 many flags and command-line options to the various passes. You must
 get these all exactly right. The /d, /Bd, or /Bz CL command-line
 options, or the PEEK.C program below, can help show what is passed
 to the various passes. The PEEK program is easiest to use. To use it,
 we "trick" the CL driver into calling our program instead of the
 various compiler passes. For instance, to find out what is passed on
 each of the three passes, you would use the following commands:

    cl /B1 peek.exe /B2 peek.exe /B3 peek.exe [options] [file]

 When you do this, the CL driver spawns your program PEEK.EXE rather
 than the various compiler passes. The switches are too complicated to
 guess at, so either use this program or one of the /B or /d options.
 Note that no compilation will be done because you called PEEK.EXE
 rather than the three compiler passes.

 The second major problem is that because these command strings can
 easily exceed the DOS 128-character limit on the length of a command
 line, the CL driver uses the environment string area rather than the
 command line to pass options to the passes. To duplicate this, you
 must do one of the following two things:

 1. Write a batch file that sets the environment properly and calls
    the various passes. This file fails if any of the strings are
    longer than the DOS command-line limit of 128 characters. Since
    this is likely to be the case, you'll probably need to use the
    second method.

 2. Write a small C program that spawns (using one of the spawnle,
    spawnlpe, spawnve, or spawnvpe functions with the P_WAIT option)
    the three passes, setting up the environment first. This is a
    simple procedure and provides you with 30K or so in savings. This
    program is not provided here -- you must write it yourself.

 PEEK.C Program
 --------------

 #include <stdio.h>

 void main(int argc, char **argv, char **envp)
 {
     int i;

     printf("Command line arguments:\n\n");
     for (i = 0; i < argc; i++)  {
         printf("argv[%d]**********\n%s\n\n", i, argv[i]);
     }
     printf("**********End of command line arguments\n\n\n");

     printf("Environment strings:\n\n");
     for (i = 0; envp[i]; i++)  {
         printf("envp[%d]**********\n%s\n\n", i, envp[i]);
     }
     puts("**********End of environment strings\n");
 }


 394. -Zg Won't Handle Untagged Aggregate typedef Parameters

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified:  1-JUN-1989    ArticleIdent: Q44452

 The -Zg switch causes the Microsoft C Version 5.10 Optimizing Compiler
 to generate a list of function prototypes from the input file. This is
 documented on Page 86 of the "Microsoft C for the MS-DOS Operating
 System: User's Guide."

 It is noted on Page 87 of the same manual that structure, enumerated,
 and union types that are used as formal parameters must be tagged.
 Using untagged aggregate types as formal parameters results in the
 following message being generated for each instance of untagged
 aggregate type parameters:

    warning C4032 : unnamed struct/union as parameter

 Typedefs are expanded in the prototype listing. If an aggregate type
 has no tag then the prototype is commented out and the type of the
 parameter is labeled, in the case of a structure, as follows:

    struct UNNAMED

 There is no way to prevent the compiler from expanding the typedefs
 and from disliking the untagged aggregate types.

 The program below, when compiled in the following manner

    cl -Zg whack.c

 produces the following output:

     extern  void main(void );
     extern  int Woof(struct ure a);
     /* int Heave(struct UNNAMED a); */
     whack.c(29) : warning C4032 : unnamed struct/union as parameter

 /* Demonstration of typedef expansion when compiling with /Zg
  */
 typedef struct ure      // This one's tagged
 {
     int     x;
     int     y;
 } URE;

 typedef struct          // This one's not tagged
 {
     int     x;
     int     y;
 } IME;

 void main()
 {
     URE     Ok;         // Tagged type variable
     IME     NotOk;      // Untagged type variable

     Woof( Ok );
     Heave( NotOk );
 }

 int Woof( URE a )
 {
     return( 0 );
 }

 int Heave( IME a )
 {
     return( 0 );
 }


 395. Using ILINK in the Development Process in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr S_QuickC
 Last Modified: 19-SEP-1989    ArticleIdent: Q44462

 The incremental linker is available with the Microsoft C Optimizing
 Compiler Version 5.10 and QuickC Version 2.00. The information below
 is excerpted from the "Microsoft CodeView and Utilities Software
 Development Tools for MS OS/2 and MS-DOS Operating Systems Update" for
 Version C 5.10, Section 9, "The ILINK Utility."

 Note: The incremental linker supplied with C Version 5.10 CANNOT be
 used to develop DOS applications other than Windows applications. It
 can be used for Windows applications and OS/2 applications. This
 limitation is documented at the beginning of "The ILINK Utility"
 section in the Version 5.10 utilities update.

 To develop a software project with ILINK when compiling and linking
 from the command line, do the following:

 1. Use the full linker, LINK.EXE, during early development stages
    until you have a number of different code and data segments.

 2. Prepare for incremental linking by using the /INC (incremental)
    option, for example:

       link /INC file1 file2 ... filen;

 3. Use the incremental linker, ILINK.EXE, after any small changes
    are made, for example:

       ilink /i file1 file2 ... filen

    To view ILINK options, type ILINK at the DOS prompt and press
    ENTER.

 4. Relink with LINK after any major changes are made. Often, a
    major change causes ILINK to fail and then calls a full LINK.
    Relinking with LINK alleviates this unnecessary step.

 5. Repeat Steps 3 and 4 as necessary.

 To use the same development process with the QuickC Version 2.00
 environment, you can toggle on and off the incremental compile and
 incremental link switches. You can find these switches under the
 Options menu, Make option, in the Compiler Flag selection and Linker
 Flag selection, respectively.

 Linking with the /INC option may take longer than without the option
 because of additional overhead involved in preparing for incremental
 linking.

 The /INC linker option is not compatible with the /EXEPACK option.

 If you compile and link at the command line with QCL using the /Gi
 (incremental compile) option, then incremental link is automatically
 invoked. If you do not want an incremental compile you can still
 request incremental link with the /Li compiler option.


 396. Difference between Arrays and Pointers in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890510-18105 S_QuickC
 Last Modified: 19-SEP-1989    ArticleIdent: Q44463

 Question:

 My program is divided into several modules. In one module, I declare
 an array with the following declaration:

    signed char buffer[100];

 In another module, I access the variable with one of the following:

    extern signed char *buffer;           /* FAILS */
    extern signed char buffer[];          /* WORKS */

 Using CodeView reveals that the program is using the wrong address
 for the array in the first case. The second case works correctly.

 What is the difference between an array and a pointer.

 Response:

 This is a C programming mistake. The following declarations are NOT
 the same:

    char *pc;
    char ac[20];

 The first declaration sets aside memory for a pointer; the second sets
 aside memory for 20 characters.

 A picture of pc and ac in memory might appear as follows:

     pc  +--------+
         |   ???  |
         +--------+

     ac  +-----+-----+-----+-----+     +-----+
         |  ?  |  ?  |  ?  |  ?  | ... |  ?  |
         +-----+-----+-----+-----+     +-----+

 The same is true for the following:

    extern char *pc;
    extern char ac[];

 Thus, to access the array in ac in another module, the correct
 declaration is as follows:

    extern signed char ac[];

 In your case, the correct declaration is the following:

    extern char buffer[];

 The first declaration says that there's a pointer to char called pc
 (which is two or four bytes) somewhere out there; the second says that
 there's an actual array of characters called ac.

 The addressing for pc[3] and ac[3] is done differently. There are some
 similarities; specifically, the expression "ac" is a constant pointer
 to char that points to &ac[0]. The similarity ends there, however.

 To evaluate pc[3], we first load the value of the pointer pc from
 memory, then we add 3. Finally, we load the character which is stored
 at this location (pc + 3) into a register. The MASM code might appear
 as follows (assuming small-memory model):

    MOV     BX, pc          ; move *CONTENTS* of pc into BX
                            ; BX contains 1234
    MOV     AL, [BX + 3]    ; move byte at pc + 3 (1237) into AL
                            ; ==> AL contains 'd'

 A picture might appear as follows, provided that pc had been properly
 set to point to an array at location 1234 and that the array contained
 "abcd" as its first four characters:

 address:   1000                  1234  1235  1236  1237
     pc  +--------+--->>>>>------v-----v-----v-----v-----+
         |  1234  |          *pc |  a  |  b  |  c  |  d  | ...
         +--------+              +-----+-----+-----+-----+
                                  pc[0] pc[1] pc[2] pc[3]
                                  *pc   *(pc+1) etc.

 Note: Using pc without properly initializing it (a simple way to
 initialize it is "pc = malloc(4);" or "pc = ac;") causes you to access
 random memory you didn't intend to access (and causes the strange
 behavior).

 Since ac is a constant, it can be built into the final MOV command,
 eliminating the need for two MOVs. The MASM code might appear as

    MOV     AL, [offset ac + 3]     ; mov byte at ac + 3 into AL
                                    ; offset ac is 1100, so move
                                    ; byte at 1103 into AL
                                    ; ==> AL contains 'd'

 and the picture appears as follows:

 address: 1100  1101  1102  1103        1119
     ac  +-----+-----+-----+-----+     +-----+
         |  a  |  b  |  c  |  d  | ... |  \0 |
         +-----+-----+-----+-----+     +-----+
         ac[0] ac[1] ac[2] ac[3]       ac[19]
         *ac   *(ac+1)  etc.

 Note: If you first initialize pc to point to ac (by saying "pc =
 ac;"), then the end effect of the two statements is exactly the same.
 (This change can be shown in the picture by changing pc so it contains
 the address of ac, which is 1100.) However, the instructions used to
 produce these effects are different.

 Note: If you declared ac to be as follows, the compiler would generate
 code to do pointer-type addressing rather than array-type addressing:

    extern char *ac;  /* WRONG! */

 It would use the first few bytes of the array as an address (rather
 than characters) and access the memory stored at that location. This
 is what you're doing and why you're having problems.


 397. Use /ND Instead of #pragma data_seg

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 26-MAY-1989    ArticleIdent: Q44477

 Support for the data_seg pragma may be eliminated from future versions
 of the Microsoft C Optimizing Compiler. Microsoft strongly recommends
 that you use the /ND option at compile time instead of embedding the
 data_seg pragma in your source code.

 When you use /ND to change the name of the default data segment for a
 given module, your program can no longer assume that the address
 contained in the stack segment register (SS) is the same as the
 address in the data segment (DS). You must also compile with /Au or
 use the _loadds keyword. A _loadds function loads its own data segment
 upon entry.

 All modules whose data segments have the same name have these segments
 combined into a single segment at link time, including all data that
 would otherwise be allocated in the _DATA segment, i.e., all
 subsequent initialized static and global data.

 See the "Microsoft C 5.1 Optimizing Compiler User's Guide," Section
 6.7, "Naming Modules and Segments," Pages 157-159, for more detail.

 The data_seg pragma specifies the name of the data segment that
 subsequent _loadds functions should use and also causes the named
 segment to contain all data that would otherwise be allocated in the
 _DATA segment.

 Note that the use of pragma data_seg by itself does not cause
 subsequent functions to load DS. You must also compile with /Au or use
 the _loadds keyword.


 398. Ellipse Not Bounded Correctly

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 26-MAY-1989    ArticleIdent: Q44523

 The _ellipse function does not behave as defined. The Microsoft QuickC
 and Optimizing C 5.x run-time library reference manuals state that
 "the bounding rectangle [is] defined by the logical points (x1,y1) and
 (x2,y2)." However, the bound specified by y2 may be two pixels distant
 from the lowest point reached by the ellipse.

 This behavior can be demonstrated in any video mode, but not all
 possible bounding points will produce this behavior.

 This "off by two" behavior is especially troublesome when floodfilling
 a region bounded by the ellipse and a line on y2. The floodfill will
 bleed out of what should be an enclosed region. The following program
 demonstrates this situation:

 #include <graph.h>

 void main (void)
 {
   int x1=0, y1=0, x2=639, y2=349;

   _setvideomode (_ERESCOLOR);

   /* Draw the boundary. */
   _setcolor  (15);
   _rectangle (_GBORDER, x1, y1, x2, y2);
   _ellipse   (_GBORDER, x1, y1, x2, y2);

   /* Define _floodfill attributes. */
   _moveto    (x1+1, y2-1);
   _setcolor  (12);

   /* This should not 'bleed' to the right region. */
   _floodfill (x1+1, y2-1, 15);
 }

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


 399. UNLINK Does Not Work If the File Is Not Closed

 Product Version(s): 4.00 5.00 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified:  1-JUN-1989    ArticleIdent: Q44608

 Question:

 I am using the function UNLINK to delete a file. UNLINK seems to
 delete the file, but I do not get the disk space back. Why?

 Response:

 The C run-time function UNLINK does not work properly if the file you
 are trying to delete is not closed. If the file is not closed, the
 File Allocation Table is not be updated properly and CHKDSK reports
 lost clusters. These lost clusters are the unclosed files which tried
 to delete.

 You can recover the lost disk space by running CHKDSK /F. This
 information also applies to the C run-time function REMOVE.


 400. printf() and 512-Byte I/O Buffer

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 15-AUG-1989    ArticleIdent: Q44725

 Question:

 Why does the function printf() take up 512 bytes from the near heap
 (in small and medium memory model) when compiled with QuickC 2.00 but
 does not seem to take up any memory using C 5.10 or QuickC 1.01?

 Response:

 In QuickC 2.00, the standard I/O buffer gets allocated only when
 needed. This gives the program an extra 512 bytes of near heap space
 in small and medium memory model or an extra 512 bytes of far heap
 space in compact and large model. Therefore, when the printf()
 function is used for the first time, a 512-byte buffer is reserved
 for I/O, and the subsequent calls to printf() use that buffer.

 In C 5.10 and QuickC 1.01, a 512-byte buffer is always reserved at
 start-up. It doesn't matter if the program uses standard I/O or not.
 The buffer is also always allocated in the near heap, no matter what
 memory model is used.

 The following program prints the amount of space left in the near
 heap. When complied under C 5.10 or QuickC 1.01, the number is the
 same before and after the execution of printf().

 The program also uses _fheapwalk to show that C 5.10 and QuickC 1.01
 always allocate the buffer in the near heap in any memory model, and
 QuickC 2.00 allocates it in the near or far heap according to the
 memory model.

 When compiled under QuickC 2.00, the number printed after the printf()
 function is executed is 512 bytes fewer than the number printed before
 the execution of printf().

 #include <stdio.h>
 #include <math.h>
 #include <dos.h>
 #include <malloc.h>

 void heapdump (void);
 void main (void)
 {
   unsigned n1, n2;

   n1 = _memavl();
   heapdump();
   printf("first printf has been executed\n");
   n2 = _memavl();
   printf("space left in the near heap before printf %u\n",n1);
   printf("space left in the near heap after printf %u\n",n2);
   heapdump();
 }

 void heapdump (void)
 {
   struct _heapinfo hinfo;
   int heapstatus;

   hinfo._pentry = NULL;
   while ((heapstatus = _fheapwalk(&hinfo)) == _HEAPOK)
   {
      printf("%6s block at %p of size %d in the far heap\n",
            (hinfo._useflag == _USEDENTRY ? "USED" : "FREE"),
            hinfo._pentry, hinfo._size);
   }
   switch (heapstatus)
   {
     case _HEAPEMPTY:
         printf("OK - empty far heap\n");
         break;
     case _HEAPEND:
         printf("OK - end of far heap\n");
         break;
     case _HEAPBADPTR:
         printf("ERROR - bad pointer\n");
         break;
     case _HEAPBADBEGIN:
         printf("ERROR - bad start\n");
         break;
     case _HEAPBADNODE:
         printf("ERROR - bad node\n");
         break;
   }
 }



 401. Using Third-Party Libraries Produced for C Version 4.00

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 31-MAY-1989    ArticleIdent: Q44793

 Third-party libraries made for C Version 4.00 can be used with C
 Versions 5.00 and C 5.10. An attempt was made to make third-party
 libraries as compatible as possible. However, a few functions were
 changed to conform to the ANSI C draft and may cause problems.
 Functions such as rename() and memcpy() had their arguments reversed
 from the C 4.00 to C 5.00 libraries; thus, calls to these functions
 from C 4.00 libraries do not work properly. This also applies when
 using third-party libraries with QuickC 1.x and QuickC 2.00.

 To use libraries made for C 4.00 under C 5.00 or above, you must link
 with /NOD and specify the C 5.00 combined library to use, as follows
 (the /NOD tells the linker not to use the default libraries for C 4.00):

    LINK /NOD file.c ,,, oldlib slibce.lib

 In QuickC, this can be done as follows by setting the environment
 variable LINK to /NOD and specifying the QuickC combined library to
 use in a program list:

    set LINK=/NOD

 If there are still linker errors, you must request library updates
 from the third-party vendor.


 402. printf Appears to Print Incorrect Results for Floats

 Product Version(s): 5.10 | 5.10
 Operating System:   DOS  | OS/2
 Flags: ENDUSER |
 Last Modified:  1-JUN-1989    ArticleIdent: Q44816

 Question:

 The printf() below does not print out the correct values for the float
 if I print the float with a hexadecimal specifier before the float
 specifier. Is this a problem with the code or printf()?

 Response:

 The problem here is that we are using a 2-byte format specifier for an
 8-byte value. To correct this problem, replace "%x" and "%lx" with
 "%lx %lx".

 Code example
 ------------

 #include <stdio.h>
 main()
 {
         float flt  = 1.701411e+038;
         double dbl = 1.701411e+038;

  printf("\nFLOAT         %x   %e", flt,flt);
  printf("\nDOUBLE        %lx  %le",dbl,dbl);
 }

 The above code produces incorrect output. However, the source code is
 incorrect. When printing, the above code is using a 2-byte hex format
 specifier %x or a 4-byte hex format specifier %lx with an 8-byte
 double argument (the float is also passed as a double). This produces
 the incorrect results. To solve this problem, use two %lx format
 specifiers to remove 8-bytes off the stack before printing the second
 double. An example is as follows:

    printf("\nFloat  %lx %lx %e",flt,flt);
    printf("\nDouble %lx %lx %le",dbl,dbl);

 This works correctly for Microsoft C under MS-DOS or OS/2; however,
 this code may not be portable under other systems that support types
 of different sizes.

 Eight bytes are passed, independent of the fact that one argument is a
 float and the other a double, because the float is being promoted to a
 double. This is because all floats are passed as doubles unless they
 are specified as floats in the prototype. Because printf() has
 variable number of parameters, the arguments are not prototyped and
 therefore all floats are promoted up to doubles.


 403. Software/Hardware Required for Writing Windows Applications

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC P_WinSDK
 Last Modified: 26-MAY-1989    ArticleIdent: Q44834

 To write programs for Windows, you need the following software
 packages:

 1. Microsoft Windows/286 or Windows/386 Version 2.00 or later.

 2. Microsoft Windows Software Development Kit (SDK) Version 2.00 or
    later.

    Note: The version number for the Windows package must match
    the version number for the SDK, e.g. Windows 2.0x with SDK 2.00
    or Windows 2.1x with SDK 2.10.

 3. Microsoft C Compiler Version 4.00 or later, Microsoft QuickC
    Version 2.00, or another compiler suitable for compiling Windows
    programs.

 4. Microsoft Macro Assembler 4.00 or later (for writing DLLs).

 To run Windows and the Windows Software Development Kit, you need the
 following hardware:

 1. An IBM personal computer (or compatible) with a fixed disk and
    640K of memory running MS-DOS Version 3.00 or later. (A machine
    based on an 80286 or 80386 microprocessor with a fast fixed disk is
    best.)

 2. A graphics display and video board, preferably an Enhanced Graphics
    Adapter (EGA) or Video Graphics Array (VGA). A Color Graphics
    Adapter (CGA), Hercules Graphics Card or compatible, or an IBM 8514
    can also be used.

 3. A mouse (optional).

 To debug with CodeView (CVW) you need the following:

 1. 1.5 MB of LIM 4.00 expanded memory (2 MB or more is recommended).

 2. Either dual monitors (the second of which is monochrome, the first
    a CGA, EGA, or VGA) or a dumb terminal connected to COM1.

    Note: In a dual-monitor setup, when the primary monitor is a CGA,
    the Windows on the CGA is in monochrome due to resolution and the
    monochrome monitor is in text.

 Windows/286 can run under DOS or in the DOS compatibility box under
 OS/2 on an 80286 or 80386. Windows/386 requires an 80386 where it can
 run under DOS but not in the DOS compatibility box. Typing "WIN86"
 (without the quotation marks) at the DOS prompt (or DOS box) initiates
 a 80286 (not a 80386) session.


 404. kbhit() Does Not Take Character Out of Buffer

 Product Version(s): 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 26-MAY-1989    ArticleIdent: Q44895

 If you are repeatedly testing the value of "!kbhit()", you must fetch
 the character out of the keyboard buffer yourself after entering a
 keystroke. If you do not, kbhit() returns TRUE and the test repeatedly
 fails.

 The following code demonstrates the situation:

 #include <conio.h>

 void main (void)
 {
  while (!kbhit ());    /* waits for keystroke */
  while ( kbhit ())
     getch ();          /* empties buffer */

  while (!kbhit ());    /* waits for keystroke */
  while (!kbhit ());    /* does not wait for keystroke */
 }


 405. system() Returns an Exit Code Under OS/2

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-MAY-1989    ArticleIdent: Q44897

 The system() function under OS/2 returns the exit code of the process
 executed, unlike MS-DOS. Under MS-DOS the system() function always
 returns 0 to indicate successful completion.

 Under both operating systems, if the system() function fails then a
 value of -1 is returned.


 406. How Does _osmode Get Set?

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890523-18896
 Last Modified: 21-AUG-1989    ArticleIdent: Q44927

 The Microsoft C Run-time Library variable _osmode is set to one (1)
 when running under OS/2 and to zero (0) when running under DOS. A C
 program can look at this variable and easily determine whether it's
 running under DOS or OS/2, without calling DosGetMachineMode.

 To declare the variable, use the following line:

    #include <stdlib.h>

 An examination of the start-up code (included with the compiler) shows
 how the value of this variable is determined. The DOS start-up code
 just initializes the variable to zero. The OS/2 code initializes it by
 making a call to the OS/2 API DosGetMachineMode, which sets it to zero
 for DOS or one for OS/2. Thus, you don't need to make the call.

 If you compile for DOS (/Lr or /Lc), the DOS start-up code is included
 because the linker links your program with the appropriate DOS library
 (xLIBCyR, where x is the memory model and y is the math option). By
 the same token, when you compile with /Lp, the linker links the proper
 library for OS/2 (xLIBCyP). If you don't specify one of these options,
 your code is linked with xLIBCy.


 407. setbuf() Does Not Control Buffering of DOS or Keyboard Buffer

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 25-JUL-1989    ArticleIdent: Q45563

 Question:

 Why does getchar() still wait for a carriage return even though I used
 setbuf() to unbuffer stdin?

 Response:

 The function setbuf() affects a stream file buffer like stdin, but has
 no effect on the keyboard or DOS device buffers. The stream I/O
 function getchar() can only read a character from the keyboard buffer
 when the keyboard buffer is flushed by either being filled, by a
 carriage return, or by an interrupt 0x21, function 0xC call.

 To read typical characters directly from the keyboard, you can use
 the console I/O function getch(). To read control codes such as
 ALT+Q (echo subsequent output to printer) or ALT+R (pause output), you
 can use the _bios_keybrd() function. Query on the following:

    _bios_keybrd()

 The following example demonstrates the difference between using
 getchar() and getch():

 #include <stdio.h>
 #include <conio.h>

 void main (void)
 {
    setbuf (stdin, NULL);        /* cause stdin to be unbuffered */
    if (getchar () != EOF )
       printf ("getchar() still waits for return key\n");
    if (getch () != EOF )
       printf ("getch() does not wait for return key\n");
 }


 408. Installing C 5.10 to Compile Both DOS and OS/2 Programs

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890523-18896
 Last Modified: 18-SEP-1989    ArticleIdent: Q45145

 If you'd like to install your C compiler so that you can create both
 DOS and OS/2 applications, you have three options. The option you
 select affects the compiler options you must set when you compile for
 the two operating systems.

 The three options are as follows:

 1. Rename none of the libraries.

 2. Rename the protected-mode libraries to the default names.

 3. Rename the real-mode libraries to the default names. This
    renaming can also be done while setting up the product.

 To install for both OS/2 and DOS, select both operating systems when
 using SETUP to install the product. If you've already installed the
 product for only one operating system, the easiest method is to
 reinstall again from the beginning.

 Once the dual installation is done, you have the following two sets of
 libraries (unless you tell SETUP to rename libraries for you when it
 asks):

 1. Those whose names are of the form xLIBCyR.LIB (where x is S, M, C,
    or L for the memory model and y is E, 7, or A for the math option --
    see the Version 5.10 "Microsoft C Optimizing Compiler for the MS-DOS
    Operating System User's Guide" for more information) for "R"eal mode.

 2. Those whose names are of the form xLIBCyP.LIB for "P"rotected mode.

 If you install medium model emulator math only, and don't tell SETUP
 to rename libraries, the libraries will be named "MLIBCEP.LIB" and
 "MLIBCER.LIB". There will be no library named with the default name,
 which is "MLIBCE.LIB".

 You can leave the libraries named in this way; however, if you do, you
 must always compile with one of the /Lr (link real mode), /Lc (link
 compatibility mode -- a synonym for real mode), or /Lp (link protected
 mode) compiler options.

 None of the /Lp, /Lc, or /Lp options affects the compilation process;
 they only affect what libraries the linker is asked to link in.
 Whether the final executable program is a real-mode executable or a
 protected-mode executable is determined solely by the library with
 which you link.

 The /Lp option tells the linker to ignore the default library and to
 use xLIBCyP.LIB instead (x and y depend on the memory model and math
 option selected by the /Ax and /FP switches). The /Lr and /Lc options
 tell the linker to use xLIBCyR.LIB rather than the default. xLIBCy is
 the library generated if none of these options is used. This is shown
 in the following table:

    Compiler Flags                          Library Used
    --------------                          ------------

       -AS                                     SLIBCE
       -AL -FPi87                              LLIBC7
       -AM -FPa -Lp                            MLIBCAP
       -AH -FPc -Lr                            LLIBCER

 If you do most of your programming for one operating system or the
 other, you can rename the appropriate libraries (xLIBCyR or xLIBCyP)
 to xLIBCy and avoid having to use /Lp or /Lr. You still must use /Lp
 or /Lr when compiling for the other mode. For instance, if you rename
 the xLIBCyP libraries to xLIBCy, then when you compile without a /Lc
 or /Lr option, your executable will be a protected-mode executable.
 To generate a DOS executable, you must use /Lr or /Lc. Instead, if you
 rename the xLIBCyR libraries to xLIBCy, the default mode will be DOS
 -- you must use /Lp to produce an OS/2 program.


 409. Initialization and Discarding of DLLs Built with C Run Time

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | softlib CRTDLL.ARC S12104.EXE
 Last Modified:  5-OCT-1989    ArticleIdent: Q45180

 Question:

 Is there a C run-time DLL de-install function provided with
 LLIBCDLL.LIB that, among other things, removes the DosExitList
 functions? Using DosFreeModule doesn't work properly.

 Response:

 You must do some DLL initialization and cleanup to prevent our default
 DLL initialization and exit code from including the exit list set up
 by LLIBCDLL.LIB, and we have files and suggested procedures for this
 purpose.

 The OnLine Software/Data Library file CRTDLL contains the files
 DLLINIT.OBJ and DLLTERM.OBJ, which contain initialization and
 termination functions for LLIBCDLL. Link these functions in with your
 own DLL's initialization and termination functions. (CRTDLL also
 contains CRTDLL_I.OBJ, but this is to replace CRTDLL.OBJ for use with
 the multiple thread CRTLIB.DLL.)

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

 The prototypes for the functions in DLLINIT.OBJ and DLLTERM.OBJ are,
 respectively, the following:

    void far pascal C_INIT(void);
    void far pascal C_TERM(void);

 To specify the entry point into your own DLL initialization routine,
 you must have a MASM file specifying the name of your DLL
 initialization function with the MASM "END" InitRoutineName statement,
 as in the following:

 ; MASM routine
 ...
 END InitRoutineName

 The InitRoutineName can specify a MASM or C routine. For C, the DLL
 initialization routine would appear similar to the following:

 void far pascal C_INIT(void);

 int _export _loadds InitRoutineName() {
         C_INIT();

         // ... your own initialization code

         return(1);  //Indicates to OS/2 that the DLL init succeeded.
                  //If return(0), OS/2 won't load .EXE's using the DLL
         }

 Your own initialization code must not use C run-time library function
 calls before C_INIT() is called.

 Link the MASM entry code .OBJ, the module containing the above
 InitRoutineName() and other DLL functions, and DLLINIT.OBJ together
 with LLIBCDLL and DOSCALLS.LIB (for OS/2 1.00, or OS2.LIB for OS/2
 1.10).

 The DLL's .DEF file must contain the following statements:

    LIBRARY dllname INITINSTANCE
    DATA MULTIPLE

 To eliminate your DLL, write an initialization function in your DLL
 (or add to the one above) that registers one or more exit routines
 with DosExitList. The exit routines should free all resources acquired
 by the DLL that are no longer needed. The C_TERM() function must be
 called to clean up for LLIBCDLL.

 Link in DLLTERM.OBJ with this module. DLLTERM.OBJ will suppress our
 standard use of DosExitList for cleaning up after LLIBCDLL to allow you
 to create your own exit routine list. (For cleaning up after DLL's use
 of the multithread CRTLIB.DLL, you must create your own exit routines
 with C's atexit() or DosExitList.)

 All the DLL function entries in the exit list must be removed before
 the .EXE can detach itself from the DLL. To actually discard the DLL,
 your .EXE must call a final termination routine in the DLL. The final
 DLL termination routine must remove the other functions in the exit
 list and then call "DosExitList(EXLST_EXIT, 0L);" to remove itself
 from the exit list. Then, the DosFreeModule of the DLL should succeed.


 410. Documented Search Order for Include Files

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 18-SEP-1989    ArticleIdent: Q45187

 I am having trouble determining the precise search order for include
 files. The Version 5.10 "Microsoft C for the MS-DOS Operating System:
 User's Guide" states the following on Page 34:

    The compiler always searches the current working directory first
    before searching the locations given in the environment variable.

 (Except when using < >).

 The Version 5.10 "Microsoft C for the MS-DOS Operating System:
 Language Reference" on Page 203 discusses searching in terms of the
 "parent" file's directory, then also mentions the current working
 directory in a subsequent paragraph.

 From my experimenting, it seems that all references to the current
 working directory are incorrect. The compiler actually searches based
 on the parent's directory. The MS-DOS current directory is never
 searched unless it is included on the command line or in the INCLUDE
 variable.

 The above assumptions are correct. All references to the "current
 working directory" should be referring to the "parent" directory. This
 is a documentation error. If include files are nested, then this error
 becomes important. With nested include files, the current working
 directory can be very different from the parent directory. The parent
 directory is always the one that is searched.


 411. Run-Time Library FP Signal Handler Assumes SS=DS

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | softlib CFPLIBS.ARC S12318.EXE
 Last Modified: 25-JUL-1989    ArticleIdent: Q45195

 Note that the Microsoft Run-Time Library Exception handler will call
 another routine that calls the task's SIGFPE signal handler, if one
 exists.

 However, this intervening routine assumes that the stack segment is
 that of the program that caused the 8087 exception. It is known that
 certain 8087 instructions can take a (relatively) long time to
 execute. It is also known that other interrupt routines, such as the
 timer or the disk interrupt or one belonging to a TSR, may in fact be
 running when the 8087 interrupt occurs.

 As the NMI, it will nest, and the run-time library routine's
 assumption about the stack segment may not be valid.

 This problem is very rare; however, it is a valid concern. Instead of
 sacrificing speed, the decision was made to take the small chance that
 SS=DS. Checking for SS=DS would slow the floating-point libraries
 considerably.

 There is a file in the OnLine Software/Data Library that contains two
 floating-point libraries. These libraries should protect you from the
 unlikely event of SS!=DS. These libraries are approximately 10%
 slower than the retail floating-point libraries.

 This file can be found in the Software/Data Library by searching on
 the keyword CFPLIBS, the Q number of this article, or S12318. CFPLIBS
 was archived using the PKware file-compression utility.

 These libraries eliminate the possibility of SS!=DS within a
 floating-point signal handler. However, these libraries are about 10%
 slower than the original floating-point libraries. To include these
 files in your combined libraries, first make backup copies of the
 original floating-point libraries, rename these new libraries to
 EM.LIB and 87.LIB, and then run SETUP with the /L option to rebuild
 libraries. This will rebuild the combined libraries with these new
 floating-point components.

 The libraries provided with this archived file are fully tested.
 However, they are not regularly released with Microsoft C 5.10.
 Consequently, they will not be maintained, and any problem reported
 with them will not result in a patch or any other immediate fix.
 Please report all problems experienced with these libraries.

 The archived file contains the following files:

    README.DOC
    PIEM.LIB
    PI87.LIB


 412. _ERESNOCOLOR Is a Monochrome/Graphics Mode

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 22-NOV-1989    ArticleIdent: Q45219

 On Page 359 of the "Microsoft C for the MS-DOS Operating System:
 Run-Time Library Reference" for C Versions 5.00 and 5.10 and for
 QuickC, the video mode specified by _ERESNOCOLOR is incorrectly
 listed as being a monochrome/text mode. This is really a
 monochrome/graphics mode. The incorrect line reads as follows:

    _ERESNOCOLOR   M/T   640x350   1   EGA

 This line should read as follows:

    _ERESNOCOLOR   M/G   640x350   2   EGA


 413. Tzset Sample Program Redefinition Errors in Large Model

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC docerr
 Last Modified: 25-JUL-1989    ArticleIdent: Q45228

 The TZSET sample program given on Page 619 of the "Microsoft C 5.1
 Run-time Library Reference" may yield the following errors:

    error C2086: 'daylight' : redefinition
    error C2086: 'timezone' : redefinition
    error C2086: 'tzname'   : redefinition

 These errors occur only when compiling for the large or compact-memory
 models.

 The errors occur because under the large and compact-memory models,
 the variable references default to far addresses, which contradicts
 the external near declarations contained within the include file
 TIME.H.

 You may correct this problem by declaring the three variables in
 your source as follows:

    int    near daylight;
    long   near timezone;
    char * near tzname[];

 The include file, TIME.H, declares the variables as follows:

    extern int     near    cdecl daylight;
    extern long    near    cdecl timezone;
    extern char *  near    cdecl tzname[2];


 414. Unsigned Characters and Arithmetic Operators

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 13-SEP-1989    ArticleIdent: Q45237

 Question:

 In the sample program below, I compare two unsigned character
 variables.  The conditional always evaluates to true, even when x and
 y are complements. When I examine the assembly code produced, it
 appears as though the compiler is generating code to compare two
 unsigned integers, not unsigned characters. Is this a bug?

 Sample Program
 --------------

 #include <stdio.h>
 void main (void)
 {
    unsigned char x, y;
    x = 0;
    y = 255;

    if (x != (~y))
        printf ("y is not a complement of x\n");
    else
        printf ("y is a complement of x\n");
 }

 Response:

 The code generated in this case is correct. The Microsoft C language
 reference guide clearly states that operands of unsigned character
 type are promoted to unsigned integer type when using arithmetic
 operators. Refer to Point 5, Page 116, in the "Microsoft C for the
 MS-DOS Operating System: Language Reference."

 For this sample code to work as you intended, cast the "~y" as
 unsigned character, as follows:

    if (x != (unsigned char)(~y))
        printf ("y is not a complement of x\n");
    else
        printf ("y is a complement of x\n");


 415. Can't Take Address of Frame Variable in DLL (SS!=DS)

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890605-19757
 Last Modified: 25-JUL-1989    ArticleIdent: Q45584

 Question:

 In my .DLL, whenever I take the address of an automatic variable, the
 compiler issues the following warning:

    "address of frame variable taken, DS != SS"

 Whenever the DLL is called, it causes a GP fault. What is causing this
 problem and how do I correct it?

 When I added "NONSHARED" to the DATA directive in the .DEF file, the
 GP trapping stopped. Why did the trapping stop?

 Response:

 If you're using small or medium memory model, your pointers are
 2-byte pointers, which contain only the offset of the variable into
 the data segment.

 In compact, large, and huge models, pointers are 4 bytes, containing
 both a segment and an offset.

 When a .DLL is executing, it uses your stack (normally in your
 data segment) and the .DLL's default data segment. Thus, you must
 compile with /Au or /Aw, telling the compiler that it should not
 assume (as it normally does) that DS (the default data segment
 selector) and SS (the current stack segment selector) are the same.

 All near (2-byte) pointers are assumed to be relative to current DS.
 When you take the address of a frame (automatic) variable, this
 address is relative to SS. When SS == DS, as is the usual case, this
 is not a problem. However, it does cause problems in .DLLs, where SS
 cannot be equal to DS.

 There is no way to take a near address of a stack variable when
 DS!=SS. You do have several alternatives, however:

 1. Change to compact, large, or huge model. Since the pointers are far
    pointers, you'll be able to represent the address properly. In
    addition, all the run-time library functions accept such far
    pointers.

 2. Use a far pointer to hold the address. You can do this without
    changing memory models. This method has the advantage that the only
    pointer accesses that are slowed are the individual far pointers
    used to access the stack. The disadvantage is that most small and
    medium model library routines do not support far pointers, so
    you must either avoid those routines or copy the far data into
    the default data segment before calling the routine. Please note
    that this is only necessary with routines that accept pointers;
    routines that accept variables by value aren't affected because the
    value of the expression doesn't change when the pointer size does.
    It is strongly recommended that you use prototypes and new-style
    declarations for ALL your functions to prevent errors.

 3. Rework the code to avoid the need for taking the address of frame
    variables.

 The reason the trapping seems to stop when you changed the .DEF file
 probably has more to do with the sizes of the segments involved -- in
 one case, the address generated was larger than the maximum for that
 segment; in the other, it happened not to be. In each case, the
 address was wrong because the compiler used DS rather than SS.
 Therefore, changing the data directive in the .DEF file covered up but
 did not correct the error.

 .DLL's which use the C Runtime Library **ALWAYS** use NONSHARED
 default data and instance initialization.  Instance initialization is
 specified in the LIBRARY statement of the .DEF file.


 416. Why There's a 128K Limit on Some Huge Arrays and halloc()s

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 21-AUG-1989    ArticleIdent: Q45705

 Question:

 Why am I limited to allocating 128K with halloc() or a huge array
 unless the size of the elements I am using is a power of 2?

 Response:

 With huge pointers and arrays, the Microsoft C Compiler produces
 32-bit pointer arithmetic only when accessing whole elements. Only the
 16-bit offset of a pointer is used when accessing the individual
 members of elements. This technique is used in the interest of speed
 and smaller code size. However, it assumes that elements do not extend
 from the end of one segment into the beginning of the next. When
 crossing a 64K segment boundary, elements must end evenly with the end
 of that segment. The following diagram illustrates the conditions
 necessary for huge pointers and arrays:

                          Seg1 Seg2
      Segment 1               FFFF 0000               Segment 2
      ----------------------------+----------------------------
     ......| Elem | Elem  | Elem  + Elem  | Elem  | Elem  |.....
     ......| X     | X+1  | X+2   + X+3   | X+4   | X+5   |.....
      ----------------------------+----------------------------
                                  ^ Elements must not cross
                    a segment boundary.

 If an element's size is not a power of 2, an array of that element
 will not fit evenly into a 64K segment. This is the root of the 128K
 limitation. To avoid breaking an element across a segment boundary in
 this case, extra space is left at the beginning of the first segment,
 pushing the entire array upwards in memory so that the element before
 the one that would have spanned the segment boundary ends exactly at
 the segment ending. The element that would have spanned the segment
 boundary is pushed to the beginning of the second segment.

 If the allocated elements do not fit evenly into a segment, there can
 be only one segment boundary onto which they fall evenly. The function
 halloc() uses the element size it is passed to calculate and return a
 pointer with an offset that results in the allocated elements falling
 evenly on this boundary. The following diagram demonstrates the way
 this is done and what can happen at the end of the second segment:

         Segment 1                     Segment 2
         0000           FFFF 0000           FFFF
      +----------------------+-------------------+
      +Pad |Elem |Elem |Elem +Elem |Elem |Elem | +
      +----------------------+-------------------+
       ^   ^                                   ^
       ^   ^                                   Next element will not fall
       ^   ^                                   on segment bounds.
       ^   ^
       ^   Offset returned to allow elements to fall on segment bounds.
       ^
       Padding area used to force element boundary to fall on segment
       boundary

 These restrictions should also be considered when allocating memory
 for very large elements. For example, a request for three 33K
 structures will fail. Two of the structures could be allocated, but
 since each would go into a separate segment, neither of the segments
 would contain enough space for the third element.


 417. L2002 When Linking Small Model Main with Other Memory Models

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 14-AUG-1989    ArticleIdent: Q45710

 An attempt to link a module that has been compiled in the small memory
 model with a module compiled in the medium or large memory model
 produces the following error:

    L2002: fixup overflow

 The cause, in this particular case, of the "fixup overflow" error
 message is not documented in the C Version 5.10 "CodeView and
 Utilities, Microsoft Editor, Mixed-Language Programming Guide" on Page
 366.

 Normally, you should NOT link programs that contain different memory
 models. All modules should be compiled using the same memory model.
 (It is possible to use the "near" and "far" keywords to produce
 mixed-model programs, but this is tricky and usually doesn't give much
 performance gain.)

 If the following module, MOD1.C

     #include<stdio.h>

     void main(void);

     void main()
     {
         printf(" module 1 \n");
         mod2();
     }

 is linked with the module, MOD2.C

     #include<stdio.h>

     void mod2(void);

     void mod2()
     {
         printf(" module 2 \n");
     }

 in various memory models, the following results occur:

     Memory Model      Result
     ------------      ------
     MOD1  | MOD2
     ------|-----
           |
      /AS  | /AM       L2002 : fixup overflow
           |
      /AS  | /AL       L2002 : fixup overflow
           |
      /AM  | /AS       Links, hangs on run
           |
      /AM  | /AL       Executes normally
           |
      /AL  | /AS       Links, hangs on run
           |
      /AL  | /AM       Links, prints trash for MOD2 on run


 418. Typographical Error in ALMUL.ASM of C Library Source

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | H_MASM docerr
 Last Modified: 13-SEP-1989    ArticleIdent: Q45763

 In the "Microsoft C Run-Time Library Source Routines" for C Version
 5.00 or C 5.10, Line 28 of the file ALMUL.ASM in the \HELPER directory
 contains a typographical error. The incorrect statement reads as
 follows:

    assume ds,code

 The statement should read as follows:

    assume ds,data

 Since no data is defined or referenced in the original ALMUL.ASM, the
 typographical error does not cause problems in the C library. However,
 if you purchased the C library source code from the end user sales
 department, defined and referenced data in ALMUL.ASM, and attempted to
 assemble the modified ALMUL.ASM with MASM, you receive the following
 error:

    error A2068: Cannot address with segment register

 Correcting the error in ALMUL.ASM, as noted above, corrects the
 problem.


 419. Using DosExecPgm() After Changing PATH Environment Variable

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q45904

 Question:

 I use the C 5.10 run-time putenv() function to change my PATH
 environment variable. I then use the OS/2 DosExecPgm() API call to
 start an executable that lies on that path. DosExecPgm() fails to
 execute the process, giving me a return code indicating that the file
 could not be found. I try the run-time spawnlp() function and it works
 correctly. What is the problem? How can I get DosExecPgm() to work?

 Response:

 The C run-time startup code copies the environment table into DGROUP.
 The putenv() run-time function modifies this copy of the environment.
 Other C run-time functions, including spawnlp(), will use this copy of
 the environment. So, when you alter your path variable

    putenv( "PATH=d:\\whack" );

 and look at it

     Path = getenv( "PATH" );

 you see that Path does indeed point to the new path. However, then
 using an OS/2 API call to check the path variable

    DosScanEnv( "PATH", &Path );

 reveals that the path is unchanged. This is because the API functions
 deal with the original environment table, not the copy in DGROUP.
 DosExecPgm() is no exception, meaning that the original PATH
 environment variable will be used rather than the altered copy.

 In order to perform a DosExecPgm() of a process that is not on the
 original search path but is known to be on another search path, you
 may wish to use the DosSearchPath() function in conjunction with
 DosExecPgm(), in the following manner:

 #define INCL_DOS

 #include <os2.h>
 #include <stdio.h>

 void main( void );

 void main()
 {
     RESULTCODES    ResCodes;
     char           Fail[256];
     USHORT         ret;
     char           Pgm[256];

     DosSearchPath( SEARCH_CUR_DIRECTORY,    // Start with cur dir
                    "d:\\;c:\\;b:\\whack",   // Search this path
                    "off.exe",               // For off.exe
                    Pgm,                     // Put result path here
                    256 );                   // It's 256 bytes long

     printf( "Pgm path: %s\n", Pgm );

     ret = DosExecPgm( Fail,
                       256,
                       0,
                       NULL,
                       0,
                       &ResCodes,
                       Pgm );

     printf( "DosExecPgm says: %u\n", ret );
     printf( "Fail: %s\n", Fail );
 }

 This program uses DosSearchPath() to generate a full path to
 "off.exe". Each directory in the path passed to DosSearchPath() will
 be searched. In this case the current directory will be searched
 first, because of the SEARCH_CUR_DIRECTORY flag.


 420. Unresolved Externals Using OS/2 Functions and INCL_NOCOMMON

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q45946

 If you are using OS/2 functions and getting "unresolved external"
 messages at link time even though OS2.H is included, check for a
 definition of the manifest constant INCL_NOCOMMON. The definition of
 this constant excludes any function group that is not explicitly
 included by the definition of another manifest constant.

 For example, to include the OS/2 system functions (DOS) and exclude
 all others, the following two statements must exist in the source
 code:

    #define INCL_NOCOMMON
    #define INCL_DOS

 Look closely at the "unresolved external" message. If the compiler has
 prepended an underscore to the function name, then the prototype is
 not being included. All OS/2 functions are defined with a PASCAL
 calling sequence. Therefore, there should never be an underscore
 prepended to the function name.

 As a quick test, remove the INCL_NOCOMMON statement from the code and
 recompile. If the program compiles and links without the INCL_NOCOMMON
 statement, then you have only to determine which manifest constant
 correctly includes the function group that includes the function in
 question.

 As an alternative, compiling at warning level three generates a "no
 prototype given" warning for the function if the function prototype is
 being excluded by the INCL_NOCOMMON statement. If this is the case,
 determine which manifest constant will include the function prototype,
 and define it along with the INCL_NOCOMMON statement.

 A comprehensive listing of these manifest constants can be found in
 the "Microsoft OS/2 Programmer's Reference," Volume #1, Pages 41-44.


 421. fopen Will Set errno Values

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 18-SEP-1989    ArticleIdent: Q46024

 Question:

 The "Microsoft C 5.10 Optimizing Compiler Run-Time Library Reference"
 manual indicates that open and sopen will set errno values. The fopen
 documentation on Pages 274-275 does not explicitly state that fopen
 will set errno. Will fopen set errno?

 Response:

 Yes, fopen will set errno values. Internally, fopen calls the same
 low-level routines that open and sopen call. These routines cause
 errno to be set.

 For more information, please refer to the documentation for open.


 422. Modifying P_tmpdir Does Not Change the Operation of tmpnam()

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 25-JUL-1989    ArticleIdent: Q46131

 The functions tmpnam() and tempnam() both state that under certain
 conditions they create a name that consists of the path prefix defined
 by the P_tmpdir entry in STDIO.H. This is ambiguous. A more correct
 way of stating this is that they create a name that consists of a path
 prefix to the root of the current drive; this is also what P_tmpdir is
 defined as. Under C Version 5.10 and QuickC Version 2.00, P_tmpdir is
 defined as the root directory on the default drive, which is where the
 created name would reside. However, any modification of P_tmpdir in
 STDIO.H does not change the filename created.

 It states on Page 611 of the "Microsoft C for the MS-DOS Operating
 System Run-Time Library Reference" that changing the definition of
 P_tmpdir or L_tmpnam does not change the operation of tmpnam(). Nor
 does it change the operation of tempnam(). These two defines are only
 provided for XENIX/UNIX portability. The two functions tmpnam() and
 tempnam() do not make any use of these two defines.


 423. Typedef of Function Pointer with _loadds Fails

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890616-20706
 Last Modified: 11-SEP-1989    ArticleIdent: Q46270

 Question:

 I have the following typedef declaration:

 typedef  void far _loadds pascal MYFUNC(void);
 typedef  MYFUNC  far *PMYFUNC;

 The second typedef gives a compiler warning (at -W3 level):

    Warning C4105: 'PMYFUNC' : code modifiers only on function
    or pointer to function

 How can I avoid the warning?

 Response:

 This compiler does not handle this situation properly.

 One solution is to use a macro as shown below:

     #define FN_FLP far _loadds pascal

     void FN_FLP myfunc1();

     void (FN_FLP *pmyfunc1)();

 This isn't as attractive as a typedef, but it does help.

 Another way to work around the problem is to put the definition of the
 function in a different source file than the calls, leaving the
 _loadds keyword in the function definition but taking it out of the
 declarations. Since _loadds does not affect the calling sequence, this
 process should not cause additional problems.

 Note: Be sure to check your generated code.

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


 424. Compiler Options for Intel 80x86 Processors

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q46381

 The following is extracted from the "Microsoft C Optimizing Compiler
 User's Guide," Page 81, Section 3.3.10, "Using the 80186, 80188, or
 80286 Processor (/G0, /G1, /G2)":

 Options
 -------

    /G0 Enables instruction set for 8086/8088 processor (default)
    /G1 Enables instruction set for 80186/80188 processor
    /G2 Enables instruction set for 80286 processor

 If you have an 80186, 80188, or 80286 processor, you can use the /G1
 or /G2 option to enable the instruction set for your processor. Use
 /G1 for the 80186 and 80188 processors; use /G2 for the 80286.
 Although it is usually advantageous to enable the appropriate
 instruction set, you are not required to do so. If you have an 80286
 processor, for example, but you want your code to be able to run on an
 8086, you should not use the 80186/80188 or 80286 instruction sets.

 The /G0 option enables the instruction set for the 8086/8088
 processor. You need not specify this option explicitly, since the
 8086/8088 instruction set is used by default. Programs compiled in
 this way also run on machines with the 80186, 80188, or 80286
 processor.

 Since DOS and existing versions of OS/2 are not 80386 operating
 systems, Version 5.10 (as well as previous versions) of the C compiler
 do not offer a /G3 switch for 80386 code generation.


 425. Spawned Processes Do Not Always Handle Signals Properly

 Product Version(s): 4.x 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified:  9-AUG-1989    ArticleIdent: Q46383

 In the following example, the CTRL+C signal is not handled as expected
 within the spawned process:

     #include <stdio.h>
     #include <process.h>

     void main( void )
     {
         int err;

         err = system( "TYPE TEST.TXT | MORE" );

         printf( "Return from system: %d\n", err );
     }

 If CTRL+C is pressed while the file is being typed, temporary files
 used by MORE to emulate pipes are left in the root of the current
 drive. The return value from the system does not indicate any
 problems.

 This is a limitation of MS-DOS and the way child processes handle
 certain signals, not a problem with the C compiler. Interrupting an
 assembly language program that simply calls DOS interrupt 0x4B to
 spawn "COMMAND /c TYPE TEST.TXT | MORE" gives the same results.


 426. Where to Find Information on Writing TSRs

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890601-19569
 Last Modified: 25-JUL-1989    ArticleIdent: Q46734

 Question:

 What is the definitive Microsoft reference that describes "the rules"
 for creating a TSR?

 Response:

 Since the DOS environment is so loosely structured, there are no hard
 and fast rules that guarantee that a TSR will work correctly with any
 application. The best source for this information is the "MS-DOS
 Encyclopedia" (published by Microsoft Press). This excellent reference
 contains a 37-page chapter on TSRs, and other related information on
 exception handlers and hardware-interrupt service routines. If you
 take care to write your TSR in the manner described in this reference,
 you will minimize interactions and other problems.


 427. Loop Optimization May Cause Improper Type Cast of int

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q46735

 In certain situations, compiling with loop optimization may cause a
 type cast of an int to a long or unsigned long to produce an incorrect
 value if the cast precedes a loop. When an int is type cast to a long,
 the correct conversion sign extends. Thus, a negative integer remains
 negative. On the other hand, when casting an int to an unsigned long,
 the correct conversion is to sign extend to long, THEN convert the
 long to unsigned long. This means a negative integer will be cast to a
 really huge positive number when cast to an unsigned long. This
 expected behavior is documented on page 141 of the "Microsoft C 5.1
 Optimizing Compiler Language Reference." Loop optimization may cause
 errors in both of these type casts. Disabling loop optimization or
 rearranging the code corrects the problem.

 The following program, when compiled with the /Oal or /Ox option,
 displays this erroneous type casting. In the third assignment
 statement, -31536 is cast to a long and assigned to lNum. The result
 should still be -31536, but lNum ends up being 34000. The fourth
 assignment statement casts this same number to an unsigned long and
 assigns it to ulNum. The expected result, as described above, is the
 huge positive number 4294935760, but the value assigned to ulNum is
 again 34000.

 Program Sample
 --------------

 #include <stdio.h>

 void main(void)
 {
    int iNum;
    unsigned uNum;
    long lNum;
    unsigned long ulNum;

         lNum = 34000;
         printf ("lNum = %ld\n", lNum);
         iNum = (int) lNum;
         printf ("iNum = (int) lNum = %d \n", iNum);
         lNum = (long) iNum;
         printf ("lNum = (long) iNum = %ld \n", lNum);
         ulNum = (unsigned long) iNum;
         printf ("ulNum = (unsigned long) iNum = %lu \n", ulNum);

         for (lNum = 0L; lNum < 17 ; lNum += 1)
                ;
         printf ("%s", "done");
 }

 The following is the program output:

 lNum = 34000                                <== Correct
 iNum = (int) lNum = -31536                  <== Correct
 lNum = (long) iNum = 34000                  <== WRONG! (should be -31536)
 ulNum = (unsigned long) iNum = 34000        <== WRONG! (should be 4294935760)
 done


 428. Mixed-Model Programming and long int Helper Library Routines

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890606-19866
 Last Modified: 25-JUL-1989    ArticleIdent: Q46738

 Question:

 I notice that the Microsoft C Optimizing Compiler Version 5.10
 implicitly generates calls to "helper" routines in to handle long
 integer arithmetic for operations such as division, left-shift,
 right-shift, etc.

 I see a problem in situations such as the following:

 My program is compiled in small model, so all code and data pointers
 are near. However, I explicitly declare a far pointer to a long
 integer, and then I perform a left-shift on this long integer.

 Won't the library routines be expecting near pointers to data and,
 therefore, fail?

 Response:

 The compiler is aware of this mixed-model programming issue and
 generates appropriate calls to ensure that the helper routines don't
 make the wrong assumption as to near versus far pointers.

 To demonstrate this, consider the following test program:

 long lNear;                     /* this resides in DGROUP */
 long far lFar;                  /* this goes in a FAR_BSS segment */

 void main(void);

 void main(void)
 {
     long lStack;                /* this goes in SS, part of DGROUP */

     lNear = 30000;
     lFar  = 15000;
     lNear <<=4;                 /* force call to helper routines */
     lFar <<= 4;
     lStack = lNear + lFar;
     lStack <<= 4;

 }

 The above comments point to the salient points of this test. There are
 three long variables, one in DGROUP, one in a far segment, and one on
 the stack. The compiler is asked to left-shift the near and far longs
 by 4 bits to force a call to the helper routines. Some of the compiled
 code generated by the above source is shown in the following:

 ...

 EXTRN   __acrtused:ABS
 EXTRN   __chkstk:NEAR
 EXTRN   __aNNalshl:NEAR
 EXTRN   __aNFalshl:NEAR
 _BSS      SEGMENT
 COMM NEAR       _lNear: BYTE:    4
 COMM FAR        _lFar:  BYTE:    4

 ...

 ;|***     lNear <<=4;
 ; Line 12
         *** 000029      b0 04        mov     al,4
         *** 00002b      50           push    ax
         *** 00002c      b8 00 00     mov     ax,OFFSET DGROUP:_lNear
         *** 00002f      50           push    ax
         *** 000030      e8 00 00     call    __aNNalshl
 ;|***     lFar <<= 4;
 ; Line 13
         *** 000033      b0 04        mov     al,4
         *** 000035      50           push    ax
         *** 000036      b8 00 00     mov     ax,OFFSET _lFar
         *** 000039      ba 00 00     mov     dx,SEG _lFar
         *** 00003c      52           push    dx
         *** 00003d      50           push    ax
         *** 00003e      e8 00 00     call    __aNFalshl

 Note that even though this program compiled in small model, it created
 a far segment (FAR_BSS), and it put lFar in it with the declaration
 "COMM FAR _lFar: Byte: 4". Note also the difference between how it
 left-shifted the lNear variable (__aNNalshl) versus the way it shifted
 the lFar variable (__aNFalshl). The routine __aNNalshl is for small
 model (near code pointer plus near data pointer), whereas __aNFalshl
 is compact model (near code pointer plus far data pointer); this makes
 complete sense for the mixed-model program.

 To summarize, the compiler knows about these near/far dependencies
 between source code and library routines, and puts in requests for the
 appropriate routines even if you're in a memory model that wouldn't
 normally use them (in this case, you wouldn't normally generate a call
 to __aNFalshl in small model).


 429. Possible Cause for Slow Stream I/O

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 25-JUL-1989    ArticleIdent: Q46741

 Question:

 I have an application program that does intensive file manipulation
 with the stream level I/O routines. Normally it works very fast, but
 lately the file operations have become increasingly slower and now it
 can take several minutes to process a single file. What causes this
 time delay in the stream I/O routines and how can I prevent it?

 Response:

 The stream level I/O routines inherit their speed and flexibility from
 the buffering system they use. Upon opening a file with the fopen
 function, a file record is created that contains pointers into a
 stream buffer. This buffer is then allocated (malloc-ed) when the
 first I/O operation is performed. If there is not enough room in the
 heap for this buffer allocation, the file operation continues with a
 buffer size of one character.

 A stream I/O routine that takes an excessive amount of time is most
 likely the result of a failure to allocate the 512-byte buffer on the
 heap (near or far, depending on the memory model). Without this
 buffer, the I/O routines are extremely slow, requiring disk access for
 all I/O operations.

 To get around this problem, you can do one of two things. Reduce the
 amount of allocation on the heap. Or, change memory models to compact
 or large (if you are in small or medium). If you change memory models,
 you may need to use the /Gt switch to push static data out of DGROUP.


 430. Some Causes of Differences in Floating-Point Results

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890124-10419
 Last Modified: 25-JUL-1989    ArticleIdent: Q46749

 This article discusses some reasons why programs might produce
 different floating-point results when compiled with different compiler
 options.

 The program below produces different results when complied using

    cl -AM -FPi prog.c

 than when using the following:

    cl -AM -FPa prog.c

 Part of the reason for these differences is that /FPa and /FPi
 generate math routines that work differently. /FPi math emulates the
 80x87, to the point of actually converting 8-byte doubles to 10-byte
 internal format and doing the math in internal format. /FPa uses an
 8-byte format for calculations; therefore, it is less accurate. This
 often accounts for differences in results.

 Also of special interest is the fact that the second number printed in
 the /FPi case is smaller than DBL_MIN, as defined in FLOAT.H. This
 situation is also correct because DBL_MIN is the smallest possible
 NORMALIZED value. (Normalized means that the high-order bit of the
 mantissa is a one.)

 "Denormals" (numbers where there are zeros in some of the high-order
 bits of the mantissa), however, can represent numbers "x" in the
 ranges + DBL_MIN > x > 0 and 0 > x > -DBL_MIN. Although this is an
 unusual situation, it is not an error. Although it is less precise
 than a normalized number, a denormal is still more precise than 0
 (zero) (which is the next best representation). By allowing use of
 denormal numbers, we make our floating-point result slightly more
 accurate. The alternate math library (/FPa) represents denormal
 numbers as 0 (zero).

 There is a good explanation of floating point exceptions (including
 the denormal exception, which is always masked) in the FPEXCEPT.DOC
 file that comes with the C compiler. For more detailed background, see
 the Intel "80387 Programmer's Reference Manual."

 Another possible cause of differences in floating-point results is the
 inclusion or omission of the /Op option. When /Op is omitted, the
 compiler may skip storing intermediate results as 64-bit objects in
 memory, leaving them instead in the 80-bit registers of the 80x87 (or
 emulator package). This increases the speed and accuracy of the
 calculation. However, this can decrease the consistency of the
 calculations because other intermediate results may have been stored
 in 64-bit objects in memory anyway. Including /Op forces all
 intermediate results to be stored in memory, giving more consistent
 results. This option is often handy in programs involving complicated
 floating-point calculations.

 The program and its output follow:

 #include <stdio.h>    // START OF PROG.C
 #include <float.h>

 main()
 {
     double  a,d,c,prod1,prod2;

     _fpreset();
     a=9.5788979e-283;
     b=8.050847e-1;
     c=9.5588526e-28;

     prod1=a*b;
     printf("\n product1 = %1.15le \n",prod1);
     prod2=c*prod1;
     printf("\n product2 = %1.15le \n",prod2);

 }  // END OF PROG.C

  // RESULTS OBTAINED USING CL -AM -FPi  PROG.C

  product1 = 7.711824142152130e-283

  product2 = 7.371619025195353e-310 // This value is less than DBL_MIN

  // RESULTS OBTAINED USING CL -AM -FPa PROG.C

  product1 = 7.711824142152130e-283

  product2 = 0.000000000000000e+000


 431. Using C Run-Time Library Functions in .DLLs

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890705-21975
 Last Modified: 25-JUL-1989    ArticleIdent: Q46773

 Question:

 In a .DLL, what C standard library functions are usable?

 Also, one reference mentions special re-entrant libraries for use in
 .DLLs. Is that correct, and if so, how do you get at them? Is there
 some place where this information is documented?

 Response:

 There's been a lot of confusion about the proper way to write .DLLs
 because what was legal and what's not legal has changed at least once
 during the lifetime of the OS/2 SDK.

 In the past, there were restrictions on which library functions you
 could use and how you could use them. These restrictions have been
 removed because we've created several specially-modified libraries
 that can be used freely in .DLLs. All library functions can be called.
 Any serialization needed is handled by the library.

 The proper way to create .DLLs is outlined in the file MTDYNA.DOC,
 which is included with the C 5.10 compiler. There are also examples
 included with the compiler that you can compile and modify. If you are
 developing for OS/2 1.10, instead of OS/2 1.00, with the OS/2 1.10
 Software Development Kit or Tool Kit, use the OS/2 1.10 library
 OS2.LIB in place of the OS/2 1.00 library DOSCALLS.LIB. Also make sure
 to include the OS/2 1.10 include files before, or instead of, the C
 5.10 regular and multi-thread include files with the same names, such
 as OS2.H and BSE.H. These C 5.10 OS/2 API-related include files are
 for OS/2 1.00.

 Note: There are two very important details about writing your .DEF
 file that MTDYNA.DOC doesn't mention:

 1. You MUST use a DATA MULTIPLE NONSHARED statement for any .DLL that
    uses the C run-time library because each process that uses the .DLL
    needs its .DLL to have a separate data area. Otherwise, multiple
    instances of the .DLL will corrupt each other's C run-time library
    static data.

 2. You also MUST use LIBRARY INITINSTANCE in any .DLL that calls the
    C run-time library because each instance of the .DLL must have its
    run-time library data area initialized separately.

 Aside from these two details and the new OS/2 1.10 library and header
 files, MTDYNA.DOC is an excellent guide for writing .DLLs.


 432. _setvideomode Resets the Palette

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC _remapallpalette _remappalette
 Last Modified: 25-JUL-1989    ArticleIdent: Q46792

 The Microsoft C function _setvideomode resets the palette to the
 default palette colors each time it is called. Therefore, remapping
 the color palette in C lasts only as long as the video mode remains
 active.


 433. Q & A on MS Recommendation of Glockenspiel C++ and CommonView

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890705-21998 plus plus
 Last Modified: 26-JUL-1989    ArticleIdent: Q46836

 The following questions and answers concern the use of Glockenspiel
 C++:

 Q. Does Microsoft recommend the Glockenspiel C++ and CommonView?

 A. Microsoft has included their advertising literature in our C
 Version 5.10 package and has mentioned them in the new languages
 newsletter, which was sent to all registered users. Glockenspiel's C++
 is a preprocessor, which generates C 5.10 code from your C++ source
 program. (You then use Microsoft C 5.10 to compile this code.) This
 C++ product is currently the only way to use C++ while retaining the
 sophisticated code generation and tool set of Microsoft C. It is ideal
 for Microsoft customers who want to use C++ today.

 CommonView is a C++ object library, which makes programming for
 graphical user interfaces, including Windows, easier. This is also the
 only product of its type on the market today that is compatible with
 Microsoft C.

 The products included here are manufactured by vendors independent of
 Microsoft; we make no warranty, implied or otherwise, regarding these
 products' performance or reliability.

 Q. What does Microsoft think about C++? Does Microsoft recommend
 programming in C++?

 A. Microsoft has publicly stated that object-oriented programming,
 including C++, is the way of the future and that it will result in
 great productivity gains for programmers. We have already introduced
 object-oriented extensions in our new QuickPascal product and have
 announced that we are working on an implementation of C++ (release
 date is unknown). We think that this is very important technology and
 that it will make possible the sophisticated systems of tomorrow.

 Since C++ is going to be so important in the near future, it is
 certainly wise to start getting experience in it now.

 Q. Does Microsoft use C++ in-house?

 A. Microsoft uses a variety of languages in-house including Microsoft C
 and MASM. Beyond that, it is not possible to comment on which products
 use what languages.


 434. Type of Expression "&arrayname" Changes under ANSI C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890706-22068
 Last Modified: 26-JUL-1989    ArticleIdent: Q46947

 Question:

 When I compile the following program

 1:  void main(void)
 2:      {
 3:      char String[10];
 4:      char *s;
 5:
 6:      s = &String;
 7:      }

 using Version 5.10 and the command line

    cl -W3 karma.c

 the compiler generates the following message:

    karma.c(6) : warning C4046: '&' on function/array, ignored

 This is consistent with historical C behavior. However, I understand
 that ANSI C considers array names to be lvalues. The July 1989 MSJ
 article "Pointers 101: Understanding and Using Pointers in the C
 Language" validates this assumption. Does this mean that the "&" in
 "&String" is no longer benign? Under ANSI C, does this give me (in
 effect) a pointer to the address of "String"? What is the type and
 value of the expression "&String"?

 Response:

 The 5.10 compiler ignores the "&", so the type of "&String" is the
 same as "String", which is "pointer to char." This represents common
 pre-ANSI behavior.

 ANSI requires that the type of "&String" now be "pointer to array of
 10 char." The next version of Microsoft C will conform to this
 requirement.

 However, aside from type warnings that may occur, this change IS
 benign because the address generated is identical in either case --
 the address of the zeroth element of the array. In other words, it
 will not somehow generate the address of the address -- especially
 since the address is a constant.


 435. MSJ 9/88: "Using MSC for TSRs" Omission/TSRs in C Information

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890710-22224
 Last Modified: 26-JUL-1989    ArticleIdent: Q46948

 The September 1988 article in Microsoft Systems Journal (MSJ) titled
 "Using Microsoft C Version 5.1 to Write Terminate-and-Stay-Resident
 Programs" omits and misstates some important information about writing
 TSRs. In addition, the example calls BIOS from within a TSR, which is
 not guaranteed to be safe. Although this article is an excellent
 introduction to writing TSRs, especially in C, it does not contain all
 of the needed information. The article on TSRs in the "MS-DOS
 Encyclopedia" is a much more definitive reference.

 There are two problems in the article: first, the program calls BIOS
 functions from within the TSR. Since BIOS is not re-entrant, you can't
 always call BIOS from within a TSR. Second, it is not good advice to
 say that it's OK to compile with -AS rather than -Asnw. Unless you're
 going to switch to your own stack in the TSR, you should always use
 -Asnw.

 The article is correct when it says that, in general, you may NOT call
 DOS functions from within a TSR without taking special precautions.
 DOS is not re-entrant.

 Although the MSJ article does prepare you for the concepts you'll need
 to write TSRs, the best reference is the "MS-DOS Encyclopedia," which
 has a 40-page chapter on the topic. Among the topics are descriptions
 of how to safely call BIOS and DOS from within a TSR. The "MS-DOS
 Encyclopedia" is available in hardcover and paperback from Microsoft
 Press at (800) 888-3303 and is an exceptionally useful reference book.

 Programming TSRs in C is a very complicated task. Microsoft is unable
 to offer assistance beyond the "MS-DOS Encyclopedia" to help you with
 TSR programming. There are a number of small problems: many library
 functions call DOS, do stack checks, or make memory allocations (or
 all three); so they can't be called. However, you can often work
 around this problem by buying the library source from Microsoft [call
 (800) 426-9400] and modifying offending routines.

 A bigger problem is that there is no routine supplied to change the
 stack from the user's stack to your own. It's not wise to rely on the
 user's stack being big enough for your needs. To change to your own
 stack, you'll need an assembly-language subroutine, which may be a
 part of some function packages for writing TSRs in C.

 It's a bit easier to program TSRs in assembly language. With assembly
 language, you know exactly what's going on all the time. This is a big
 help in debugging. For a TSR that's going to be reliable, you'll need
 to know exactly what's going on.

 There are third-party packages that make programming TSRs in C
 easier and safer. You may want to contact one of the PC programmers'
 software houses about this.


 436. VRES Video Modes Have 30 Lines Using Graphics Text Functions

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 15-JAN-1990    ArticleIdent: Q47021

 When using the Output Text routines in the Microsoft run-time library
 (Version 5.10 "Microsoft C for the MS-DOS Operating System: Run-Time
 Library Reference," Pages 54-55), the two graphic modes, _VRES2COLOR
 and _VRES16COLOR, have 30 text lines by default, due to their
 increased vertical resolution. All other graphics modes have 25 text
 lines when using these routines.

 The following graphics functions are the routines concerned with text
 placement and output:

    _displaycursor()
    _gettextcolor()
    _gettextposition()
    _outtext()
    _settextposition()
    _settextcolor()
    _settextwindow()
    _wrapon()

 The line numbers stated above are based on the default 8 x 8 font size
 of the IBM ROM BIOS. Note that when using fonts, the number of text
 lines in any video mode depends on the height of the font. For
 information concerning changing from the default font size, see the
 interrupt 10, function 11 entries in "IBM ROM BIOS," a Microsoft Press
 book by Ray Duncan.


 437. Using _pgmptr to Get the Full Path of the Executing Program

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  8-AUG-1989    ArticleIdent: Q47037

 Question:

 On Page Update-23 of the "Version 5.10 Update" to the Microsoft C 5.10
 Optimizing Compiler, there is a description of the variable _pgmptr.
 The documentation states that _pgmptr points to a string containing
 the full pathname of the invoked program, but does not describe how to
 use it. I can't find _pgmptr in any of the include files. Where is
 _pgmptr declared and how do I use it?

 Response:

 The variable _pgmptr is not defined in an include file. It is declared
 in CRT0DAT.ASM, which is part of the C start-up code. This code is
 linked in to any module that contains a main() function. To use
 _pgmptr, you must first declare it as an external far character
 pointer, as follows:

    extern char far *_pgmptr;

 Since _pgmptr is automatically initialized at start-up to point to the
 full pathname of the executing program, this declaration is all that
 is required to make the full pathname available to your program.

 The following program demonstrates the usage of _pgmptr:

 #include <stdio.h>

 extern char far *_pgmptr;

 void main(void)
 {
   printf ("The full path of the executing program is : %Fs\n", _pgmptr);
 }

 In OS/2 real mode or DOS 3.x, argv[0] also contains a pointer to the
 full pathname of the executing program. In OS/2 protected mode,
 argv[0] contains only the information typed at the command line to
 invoke the program. Therefore, in OS/2 protected mode, using _pgmptr
 is the only way to easily access the executing program's full pathname
 string.


 438. Best to Avoid C Run-Time Library Routines in TSRs

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890601-19569
 Last Modified: 30-AUG-1989    ArticleIdent: Q47105

 Question:

 I have two questions about using the C run-time library in a TSR
 (terminate-and-stay-resident program):

 1. Will I encounter any problems with calling the following routines
    from a TSR? What about other library routines?

       _strncmp    __aFFalshr   __chkstk   _sprintf  _free
       __acrtused  _memcpy      _realloc   _strlen   _malloc
       _strcmp     __aFFaulshr

 2. What DOS system calls (INT 21) do the C library references shown
    above generate? I want to avoid calling DOS because it's not
    re-entrant.

 Response:

 Microsoft does not recommend using standard library routines in TSRs
 at all, even though they may appear to be safe. The main problem is
 that although they may be safe in this version of the compiler, they
 may change in future versions. Microsoft does not support using the
 run-time code in a TSR.

 In particular, you can have severe problems with chkstk, sprintf,
 malloc, realloc, and free. It is likely that the other routines won't
 present too much of a problem, but without digging through the source
 and knowing EXACTLY what you're doing, there is no way to be sure.

 There is, however, an excellent alternative. Microsoft offers the
 run-time library source for sale. Call our sales number at (800)
 426-9400 for pricing and to order. With this source, you have almost
 total control over what your TSR looks like and how it acts. You can
 inspect each routine you use to ensure that it won't cause any
 interactions you don't want, and you can modify those routines that
 do. You're also better insulated against later modifications to the
 run-time library; since you control the code, you can modify it when
 you need to. This is by far your best alternative. You'll KNOW what's
 going on and you'll be able to ensure that you can maintain your
 applications. The only routines not included in this source are the
 floating-point and graphics routines.

 You may be able to find a source for routines written to support TSR
 programming even though Microsoft does not offer such software. Look
 for ads in the programmer-oriented PC magazines and/or call some of
 the programming-oriented software dealers.

 The run-time source allows you to determine which functions call DOS
 via INT 21h and which don't. Having the source also allows you to come
 up with alternative strategies for those functions that make calls.

 The "MS-DOS Encyclopedia" (published by Microsoft Press) is an
 excellent source of information about writing TSRs.


 439. Warning C4051: Data Conversion from Constant to float

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q47158

 Question:

 Why does the following program cause the C compiler to issue warning
 C4051 data conversion at warning level 2 or 3?

    void main(void)
     {
       float  num1 = 3.4;
     }

 Response:

 The data conversion results from a type conversion between a float and
 a double. Num is declared as a float while 3.4 is a constant. Floating
 point constants have a default type of double. You may eliminate this
 warning error in one of two ways:

 1. Declare the constant as a float as follows:

       float num1 = 3.4f;

    where the "f", or an "F", following "3.4" indicates that the constant
    is a 4-byte float instead of an 8-byte double.

 2. Type cast the constant to a float as follows:

       float num = (float) 3.4;


 440. .DEF File Optional Internal Names Not Supported by Implib

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | OPSYS PMWIN BUSLANG
 Last Modified: 17-AUG-1989    ArticleIdent: Q47225

 The implib utility does not put the optional internal name of a
 dynamically linked function into the import library it creates. Implib
 puts only the entry name of the function (the function name that
 external modules call) into the import library.

 The use of optional internal names is supported only by linking with
 the module definition file (.DEF) that specifies the internal function
 names (the actual function names in the source file) within a Dynamic
 Link Library (DLL) for OS/2 or DOS Windows.

 In a .DEF file, you can optionally specify aliases for the entry
 points into your DLL as in the following .DEF file statement:

 EXPORTS
     ENTRYNAME=INTERNALNAME

 ENTRYNAME is the name of a DLL routine called by other modules, and
 the optional INTERNALNAME is the actual name of the function or
 procedure in the DLL. By default, the INTERNALNAME is the same as the
 ENTRYNAME, but you may want to provide more meaningful entry names to
 the users of your DLL in addition to the actual internal function
 names.

 The names of dynamically linked functions in a DLL must be specified
 in either a .DEF file or in an import library, which has a .LIB
 extension, so that the linker can resolve all references (calls) to
 the DLL functions. Attempting to link an application that calls DLL
 functions without an import library or .DEF file results in LINK :
 error L2029: Unresolved externals: for the DLL function names.

 Import libraries, consisting of little more than the names of the
 modules in the DLL and the externally callable functions within the
 DLL, are created by the implib utility from an existing .DEF file with
 a command such as the following, which creates the import library
 "myimport.lib" from the existing module definition file "myfile.def":

    implib myimport.lib myfile.def

 Commonly used import libraries for OS/2 are DOSCALLS.LIB for the OS/2
 1.00 API (Application Program Interface) DLL routines, OS2.LIB for
 OS/2 1.10, or CRTLIB.LIB for the multi-thread C 5.10 run-time
 CRTLIB.DLL. The Windows Software Development Kit for creating DOS
 Windows applications comes with memory model-specific import libraries
 such as SLIBW.LIB.


 441. _makepath() and _splitpath Examples Are Incomplete

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr S_QuickC
 Last Modified: 17-AUG-1989    ArticleIdent: Q47226

 In the C 5.x "Microsoft C for the MS-DOS Operating System: Run-Time
 Library Reference" documentation for _makepath (Page 407) and
 _splitpath (Page 559), the examples do not compile without generating
 an indirection error. This is due to the variables being declared as
 pointers. Also, the file should include <stdlib.h>, not <dos.h>. Below
 is an example of how the file should read to compile on warning level
 3 without errors.

 In the QuickC Versions 1.00 and 1.01 "Microsoft QuickC Run-Time
 Library Reference," the documentation for _makepath (Page 407) and
 _splitpath (Page 559) also contain an error. The example program
 declares the ext variable as a 4-byte character array. This should be
 changed to a 5-byte array as shown below. This second problem appears
 when the file extension has a three-character extension such as
 ".doc".

 The following code should be used in place of the examples for
 _makepath and _splitpath in the QuickC 1.x run-time documentation as
 well.

 #include <dos.h>
 #include <stdlib.h>
 #include <stdio.h>

 void main( void )
 {
     char path_buffer [40];
     char drive [3];
     char dir [30];
     char fname [9];
     char ext [5];

     _makepath (path_buffer, "d:", "\\src\\test\\", "new","dat");
     printf("path created with _makepath: %s\n\n", path_buffer);

     _splitpath (path_buffer, drive, dir, fname, ext);
     printf("path extracted with _splitpath\n");
     printf("drive: %s\n", drive);
     printf("dir: %s\n", dir);
     printf("fname: %s\n", fname);
     printf("ext: %s\n", ext);
 }


 442. BSEARCH Does Not Find the First Occurrence of Key in the Array

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr S_QuickC
 Last Modified: 31-AUG-1989    ArticleIdent: Q47234

 The run-time library function bsearch() is documented on Page 147 in
 the "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference" as returning a pointer to the first occurrence of key in
 the array pointed to by base. This may not be true when multiple
 elements of the array match the key. In the case where multiple
 elements match the key, bsearch returns a pointer to the first element
 that it finds, not necessarily the first element of the array that
 matches the key. This is the proper action for bsearch to take. The
 documentation should read as follows:

    Return Value:

    The bsearch function returns a pointer to the occurrence of key in
    the array pointed to by base. If there is more than one occurrence
    of key, the pointer returned by bsearch may point to any of them.
    If key is not found, the function returns NULL.

 The behavior occurs because of the nature of the binary search
 algorithm. If you need to find the first matching element, use the
 lfind() (linear find) function instead of bsearch(). Note: Linear
 finds are much slower than binary searches.

 Below is a sample program that demonstrates this behavior:

 #include <search.h>
 #include <string.h>
 #include <stdio.h>

 int qcompare();  /* declare a function for qsort's compare   */
 int bcompare();  /* declare a function for bsearch's compare */

 main (argc, argv)
 int argc;
 char **argv;
 {
     char **result;
     char *key = "Brad";
     int i;

     /* Sort using Quicksort algorithm: */

     qsort((char *) argv, argc, sizeof(char *), qcompare);
     for (i = 0; i<argc; ++i)                        /* Output sorted list */
         printf("%s\n", argv[i]);

     /* Find item that begins with "Brad" using a binary search algorithm: */

     result = (char **) bsearch((char *) &key, (char *) argv, argc,
         sizeof(char *), bcompare);
     if (result)
         printf("%s found\n", *result);
     else
         printf("PATH not found !\n");
 }

 int qcompare (arg1, arg2)
 char **arg1, **arg2;
 {                      /* Compare all of both strings: */
     return (strcmp(*arg1, *arg2));
 }

 int bcompare (arg1, arg2)
 char **arg1, **arg2;
 {                      /* Compare to length of key: */
     return (strncmp(*arg1, *arg2, strlen(*arg1)));
 }

 The program sorts the command line args and then compares them with
 the key "Brad". If you enter the command line arguments, Brad1 Brad2
 Doug, you find that the bsearch routine returns Brad2. Note: The
 number is not checked because the bcompare function checks only the
 first four characters.

 Since BSEARCH cuts the array section being searched in half with each
 check, it finds Brad2 before Brad1. Instead of continuing to search
 for the first occurrence of Brad (as is documented), it immediately
 returns with a pointer to Brad2 (which is the proper action).


 443. scanf Unable to Match Extended Characters in Format String

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified:  9-AUG-1989    ArticleIdent: Q47369

 Note: In this article, the "??" symbol is used to represent an
 extended ASCII character. Because extended ASCII characters appear
 differently on many systems, it is unreliable to use a real character.
 Therefore, whenever you see the "??" symbol, it is meant to represent
 a character with an ASCII code of 128 to 255.

 When using the scanf functions (scanf, cscanf, fscanf, sscanf), you
 may place literal characters in the format string and scanf will read
 an input string as long as the input string matches these characters
 in position and value. Once the input string conflicts with the
 format, scanf terminates. The allowable characters are the standard
 ASCII values only and attempts to use extended ASCII characters in the
 format result in failure. The scanf function terminates as soon as it
 reads an extended character, even if it is the same as the expected
 character in the format. For example, if the format string contains
 "??%d", and "??45" is input, scanf quits reading at "??" even though
 it matches, since it does not recognize the extended ASCII value.

 This problem does not occur in QuickC Versions 2.00 and 2.01.

 The following program demonstrates this situation. In the first case,
 scanf expects "sqrt" to be typed in followed by a number. If this is
 done correctly, then scanf reads the number and the square root is
 displayed. In the second case, scanf should be expecting the "??"
 symbol followed by a number, but if this is typed in, scanf still
 fails to read the number since it was unable to correctly match the
 "??" to the format string.

 /* Before running this program, replace all occurrences of "??" with
    extended ASCII character 251. (Hold down the ALT key and type 251
    on the numeric keypad, then release the ALT key.)              */

 #include <stdio.h>
 #include <math.h>

 void main(void)
 {
     int    values_read;
     double num;

     /* THIS PART WORKS - scanf recognizes "sqrt" in format string */

     printf( "Enter sqrtNUMBER by typing \"sqrt\" followed by any "
             "NUMBER >= 0\n(e.g sqrt87.6) : ");
     values_read = scanf( "sqrt%lf", &num);
     printf( "values_read = %d\n", values_read);
     printf( "sqrt%lf = %lf\n\n", num, sqrt(num));
     fflush(stdin);

     /* THIS PART DOES NOT WORK - scanf fails to recognize "??" in
        the format string */

     printf( "Enter ??NUMBER by holding down the <ALT> key while "
             "typing\n\"251\" on the numeric keypad followed by "
             "any NUMBER >= 0\n(e.g. ??87.6) : ");
     values_read = scanf( "??%lf", &num);            /* returns 0 */
     printf( "values_read = %d\n", values_read);
     printf( "??%lf = %lf\n\n", num, sqrt(num));
 }


 444. FP_SEG(), FP_OFF() Need Pointer Rather Than Address

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 31-AUG-1989    ArticleIdent: Q47497

 Because FP_SEG() and FP_OFF() macros de-reference the pointer values
 passed to them, the address of a variable cannot be passed as a
 parameter.

 The FP_SEG() and FP_OFF() macros are defined in DOS.H as follows:

    #define FP_SEG(fp) (*((unsigned *)&(fp) + 1))
    #define FP_OFF(fp) (*((unsigned *)&(fp)))

 The first step of the macro is to take the address of the pointer that
 is passed to it. Because of this, the code

    unsigned val;
    unsigned i;
    i = FP_OFF(&val);

 produces the following error in C 5.00 and 5.10, as well as QuickC
 1.01:

    C2102:  '&' requires lvalue

 QuickC 2.00 produces the following warning, which does not hinder
 compilation:

    C4046:  '&' on function/array, ignored

 These messages occur because the macro cannot take the address of an
 address. However, the code

    unsigned val, *valptr;
    unsigned i;
    valptr = &val;
    i = FP_OFF(valptr);

 returns the offset of the variable val, as the address of valptr can
 be taken.


 445. Determining the Number of Valid Drives in DOS

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM H_MASM O_MSDOS
 Last Modified:  9-AUG-1989    ArticleIdent: Q47484

 Question:

 I have an application that needs to determine the number of logical
 drives installed on a given computer. I have tried using the DOS
 function "SelectDisk" (0x0E), but it seems to return the number 5 on
 all machines, no matter how many drives are installed. Is there a way
 to get this information from DOS?

 Response:

 There are no DOS calls for determining the number of logical drives
 installed on a computer. The DOS call SelectDisk returns only the
 value stored in the DOS variable LASTDRIVE. This variable normally
 contains 5 (maximum drive letter is "E") unless LASTDRIVE is
 specifically set in the CONFIG.SYS file.

 The LASTDRIVE value is useful, however, when determining which drives
 are valid and which are not. Since LASTDRIVE reflects the highest
 available drive letter, we can use DOS calls to determine which of the
 available drives are valid. The DOS calls SelectDisk (0x0E) and
 GetDisk (0x19) can be used to provide this information.

 Note: Any network drives to which you're attached are also considered
 valid. If you need to distinguish between network and non-network
 drives, modify the program below to use INT 21h function 44h (IOCTL),
 subfunction 09h ("Check if block device is remote"). For more
 information, see a good DOS reference such as "Advanced MS-DOS
 Programming" (by Duncan, published by Microsoft Press), or the "MS-DOS
 Encyclopedia" (also published by Microsoft Press).

 If you try, one at a time, to change the current drive to each of the
 available drive letters, you will see which ones are valid. Since
 SelectDisk does not return an error code in the event that it fails to
 select a new disk, call GetDisk afterwards to determine if it was
 successful.

 The following C source code illustrates this method:

 /*

 Will not run under OS/2.  For DOS only.

 The following program displays all of the logical drives installed on
 a DOS system. This program uses DOS function calls to obtain the
 current drive and change it to a new drive.

 */

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

 /* simple types */

 #define BYTE unsigned char
 #define BOOLEAN int

 /* function prototypes */

 BYTE DosGetDisk(void);
 int DosSelectDisk(BYTE);
 BOOLEAN ValidDrive(BYTE);

 void main(void)
 {
 BYTE CurDrive;
 int  NumDrives;
 int  x;

 CurDrive  = DosGetDisk();                // currently active drive
 NumDrives = DosSelectDisk(CurDrive);     // returns number set in
                                          // LASTDRIVE

 for (x = 0; x < NumDrives; x++)   // go through all possible drives
   if (ValidDrive((BYTE)x))        // print message if drive x valid
     printf("Drive %c is valid\n",(char)x+'A');

 DosSelectDisk(CurDrive);          // set default drive back

 }  /* end of main */

 BOOLEAN ValidDrive(BYTE drive)  // returns true if drive valid,
 {                               // false otherwise
   DosSelectDisk(drive);         // attempt to make drive current

   return (DosGetDisk() == drive);  // did it succeed?
 }

 BYTE DosGetDisk(void)   // returns drive number of current drive
 {
   union REGS reg;

   reg.h.ah = 0x19;           // call DOS to find
   int86(0x21,&reg,&reg);

   return (reg.h.al);
 }

 int DosSelectDisk(BYTE drive)      // sets current drive
 {
   union REGS reg;

   reg.h.ah = 0x0e;                 // set by calling DOS
   reg.h.dl = drive;
   int86(0x21,&reg,&reg);

   return ((int) reg.h.al);
 }


 446. Variable Width, Precision Available with printf

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC 1.00 1.10 2.00 2.01 S_QuickASM
 Last Modified:  9-AUG-1989    ArticleIdent: Q47663

 The Microsoft run-time library function printf() allows the width of
 the format specifier to be supplied at run time. This is done with the
 use of the * with the format specifier. This is mentioned on Pages 460
 and 461 of the "Microsoft C 5.1 Optimizing Compiler Run-Time Library
 Reference." The following code sample demonstrates this capability.

 Code Sample
 -----------

 /* This program defines a procedure to print out a floating point
    number with variable width and precision.
 */
 #include <stdio.h>

 void print(int, int, float);

 void main(void) {
    print (10, 2, 1234.5678f);
    print (9, 4, 1234.5678f);
    print (5, 2, 1234.5678f);
 }

 void print(int w, int p, float value)  {
    printf ("Printf format :%*.*f\n", w, p, value);
    printf ("Width =        0123456789012\n");
 }


 447. errno Values Not Used under MS-DOS Indicate Other Problem

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified:  9-AUG-1989    ArticleIdent: Q47692

 When an error occurs in some library routines, the errno variable is
 set to a value that can be used to indicate the nature of the error.
 These error codes are defined in the file errno.h. The codes
 originally were set up for use with UNIX to conform to errors
 occurring under that operating system. Because of this, and the
 differences between MS-DOS and UNIX, many of the codes have no
 relevance to the MS-DOS environment.

 In order to maintain compatibility with UNIX and XENIX, all the codes,
 whether meaningful in MS-DOS or not, are defined in errno.h. Appendix
 A of the "Microsoft C 5.1 Optimizing Compiler Run-Time Library
 Reference" lists only those codes that have meaning under MS-DOS along
 with their description and causes. These specific codes have
 corresponding error messages that can be printed out with the perror
 function.

 If you are working under MS-DOS and you obtain an errno value that is
 not one of the listed codes, then you can assume that the code was
 generated incorrectly and it is not indicative of the true problem.
 The documentation for the specific function you are using says which
 errno values, if any, may be set by an error in that function.

 The following is a listing of all the errno values defined in errno.h
 along with brief descriptions of their meanings. Only the values that
 are marked with "*" may be considered valid under DOS. For more
 information on these, see Appendix A of the "Microsoft C 5.1
 Optimizing Compiler Run-Time Library Reference." For more information
 on the others that are not marked with an asterisk (*), see a UNIX or
 XENIX system manual.

 * Used under MS-DOS

 Value     Define      Description
 -----     ------      -----------

 EPERM         1       Not owner
 ENOENT        2      *No such file or directory
 ESRCH         3       No such process
 EINTR         4       Interrupted system call
 EIO           5       I/O error
 ENXIO         6       No such device or address
 E2BIG         7      *Arg list too long
 ENOEXEC       8      *Exec format error
 EBADF         9      *Bad file number
 ECHILD       10       No child processes
 EAGAIN       11       No more processes
 ENOMEM       12      *Not enough space
 EACCES       13      *Permission denied
 EFAULT       14       Bad address
 ENOTBLK      15       Block device required
 EBUSY        16       Mount device busy
 EEXIST       17      *File exists
 EXDEV        18      *Cross-device link
 ENODEV       19       No such device
 ENOTDIR      20       Not a directory
 EISDIR       21       Is a directory
 EINVAL       22      *Invalid argument
 ENFILE       23       File table overflow
 EMFILE       24      *Too many open files
 ENOTTY       25       Not a teletype
 ETXTBSY      26       Text file busy
 EFBIG        27       File too large
 ENOSPC       28      *No space left on device
 ESPIPE       29       Illegal seek
 EROFS        30       Read-only file system
 EMLINK       31       Too many links
 EPIPE        32       Broken pipe
 EDOM         33      *Math argument
 ERANGE       34      *Result too large
 EUCLEAN      35       File system needs cleaning
 EDEADLOCK    36      *Would deadlock


 448. Initializing Unions Initializes the First Member of the Union

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-AUG-1989    ArticleIdent: Q47693

 When you initialize a union, the initialization value is applied to
 the first member of the union even if the type of the value matches a
 subsequent member. As stated in the ANSI Standard, Section 3.5.7:

    A brace-enclosed initializer for a union object initializes the
    member that appears first in the declaration list of the union
    type.

 Since you cannot initialize the value of any member of a union other
 than the first one, you must assign their values in a separate
 statement. Initializing a union with a value intended for a subsequent
 member causes that value to be converted to the type of the first
 member.

 The following example demonstrates the issue:

 #include <stdio.h>
 union { int   a;         /* only external unions may be initialized */
         float b;
       } test = {3.6};    /* this is intended to initialize 'b'      */
                          /* however, the value will be converted    */
                          /* (first to a long and then to an int)    */
                          /* in order to initialize 'a'              */

 void main (void)
 {
    float dummy = 0.0;            /* this causes the floating point  */
                                  /* math package to be initialized  */

    printf ("test.a = %d,  test.b = %f\n", test.a, test.b);
 }

 The output from the example, though not what is intended, will be as
 follows:

 test.a = 3, test.b = 0.00000

 To associate a value with "b", you can reverse the order of the
 members, as in the following:

 union {
         float b;
         int a;
       } test = {3.6};

 Or, you can retain the order of the elements and assign the value in a
 separate statement, as in the following:

 test.b = 3.6;

 Either of these methods creates the following output:

 test.a = 26214, test.b = 3.600000


 449. Network License Agreement for All Microsoft Language Products

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM S_PasCal S_QuickPas
 Last Modified:  4-JAN-1990    ArticleIdent: Q47724

 Network license agreements do not exist for any of the Microsoft
 language products. These agreements are currently available only for
 our application products.

 According to the licensing agreement printed on the envelope that
 contains the disks, our languages are licensed as single-user,
 single-workstation products and cannot be used by more than one user
 simultaneously. Running off of a network server or installing copies
 on more than one workstation is specifically prohibited by this
 agreement. However, the agreement does allow users to share the
 software if they run it off the same workstation at different times.

 In a networked environment, each node on the network that will be used
 for development must have a copy of the product installed on a local
 drive. Work files can be shared over the network, but neither
 compilers nor the associated utilities of a package can be shared over
 the network.


 450. Filelength() Includes EOF Character in Return Value

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC 2.00
 Last Modified: 14-AUG-1989    ArticleIdent: Q47737

 The return value of the filelength function is the full length of the
 file in bytes, including any EOF characters. The return value returns
 the same file size value as the DIR command from the DOS or OS/2
 prompt.


 451. Closing stdprn and stdaux May Not Increase Available Handles

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890728-23559
 Last Modified: 16-AUG-1989    ArticleIdent: Q47741

 Question:

 We are trying to close the handles for stdaux and stdprn so that we
 can open additional files before hitting the limit of the FILES=
 parameter in CONFIG.SYS (which we set to 11). In that mode, regardless
 of whether or not we close handles 3 and 4 (stdaux and stdprn), we are
 able to open only 8 files (FILES= - 3). The "MS-DOS Encyclopedia"
 states that stdin, out, and err are mapped to one device, but use
 three handles.

 We noticed that if FILES= in CONFIG.SYS is set to 20 or above, the
 program DOES get additional files opened when handles 3 and 4 are
 closed. Apparently we're getting some sort of interaction between the
 process file-handle table/limit (of 20) and the system table/setting
 from CONFIG.SYS.

 How can we gain access to those two file handles, keeping our FILES=
 setting in CONFIG.SYS at 11? We want to be able to open 10 files in
 our program, with FILES= set to 11.

 Response:

 Due to a limitation of DOS, you can't do this. The workaround is to
 simply set FILES=13, for the reasons described below.

 In order to open a file using the C run time, ALL of the following
 conditions must be true:

 1. There must be a space in the C run-time library's internal file
    tables. This is normally limited to 20 files, but this limit can be
    increased by modifying the start-up code if you're using DOS 3.30
    or later.

 2. There must be DOS file handles available to your particular
    process. Again, the normal limit is 20, but this can be increased
    with a call to function 67h of INT 21h (only under DOS 3.30 or
    later). This can also be modified in the start-up code.

 3. Finally, there must be files available from DOS's system-wide pool,
    as set by FILES= in CONFIG.SYS. (This defaults to 8, but can be set
    as high as 20 under DOS Version 3.30 and earlier or 255 under
    Versions 3.30 and later.)

 The results of comparing a C program that uses the C run-time library
 and a MASM program that calls DOS directly are shown below. Each was
 run with stdprn and stdaux, closed and open.

                             C Program               MASM Program
                             ---------               ------------

    FILES=         W/o Closing    W/ Closing  W/o Closing   W/ Closing
    ------         -----------    ----------  -----------   ----------

    17 (Note 1)        14             14          14            14
    18 (Note 1)        15             15          15            15
    19                 15             16          16            16
    20                 15             17          17            17
    21 (Note 2)        15             17          17            17

 Please note the following:

 1. The formula for the number of files you can open for FILES=n, where
    n is less than 19, is n - 3.

 2. No matter how high you set FILES=, you'll be limited to these
    numbers in C unless you modify the start-up code as described in
    README.DOC. In MASM, you'll be limited to these numbers unless you
    raise the per-process limit on file handles by calling INT 21h,
    function 67h.

 3. Running the program from a batch file doesn't change these numbers;
    however, reduce each number by 1 for each input or output
    redirection you do.

 4. The MASM program doesn't get any additional handles freed up when
    it closes handles 3 and 4 because, contrary to what the "MS-DOS
    Encyclopedia" implies, DOS won't allow you to reuse those two
    handles.

 Without closing handles, C programs give you a constant 15 or n - 3,
 whichever is smaller. The upper limit is 15 because, unless you modify
 the start-up code, the limit is 20 minus the five default files.

 When you close handles 3 and 4, they are closed for C but not for DOS.
 Therefore, you can open exactly as many handles as DOS normally
 allows.


 452. _amblksiz Affects Memory Allocation in Near and Far Heaps

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-AUG-1989    ArticleIdent: Q47766

 The documentation on Page 33 of the "Microsoft C for the MS-DOS
 Operating System: Run-Time Library Reference" states that adjusting
 the value of the global variable _amblksiz has no effect on halloc or
 _nmalloc() in any memory model.

 This statement in the manual is incorrect. In fact, _amblksiz is used
 to determine how much to expand both the near heap and the far heap
 segments, and is used by calls to _nmalloc(). The only difference
 between calls to _nmalloc() and _fmalloc is that _nmalloc() doesn't
 actually request memory from DOS, it takes it from the pre-allocated
 heap (in DOS).

 However, since the the memory allocated by a call to halloc() is
 maintained independently of the near and far heaps, the value of
 _amblksiz does not affect calls to halloc().

 The default value of _amblksiz is 8K (8192) bytes. The variable is
 declared in malloc.h. For more information about the use of _amblksiz,
 refer to the "Microsoft C for the MS-DOS Operating System: Run-Time
 Library Reference," Section 3.2.


 453. Linking without /NOI Causes SYS2070 in Program Calling CRTLIB

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890807-24188
 Last Modified: 16-JAN-1990    ArticleIdent: Q47779

 Programs that are linked with the C run-time library DLL (CRTDLL),
 without the /NOI switch, fail with the following message:

    SYS2070:  The system could not demand load the application's
    segment.  CRTLIB __STDOUT is in error.

 To avoid the problem, use the /NOI switch when linking. The proper use
 of /NOI is described in Section 5.2 of the MTDYNA.DOC file supplied
 with Microsoft C Version 5.10.


 454. Blinking Text May Be Eliminated with BIOS Call

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM EGA
 Last Modified: 16-JAN-1990    ArticleIdent: Q47780

 Blinking text can be accessed by setting the foreground text color to
 a value of 16 or greater. However, this can be affected by a BIOS call.
 BIOS call 10, subfunction 3 toggles the interpretation of the
 intensity bit of the foreground color. By making a call to this BIOS
 function you can access additional background colors. Without blinking
 foreground text, you can access 16 background colors. With blinking
 text you are limited to 8 background colors. The program shown below
 demonstrates this.

 The example prints 16 lines of text with varying background colors.
 The intensity interpretation is then toggled, limiting the output to
 only 8 background colors.

 This problem also occurs in Microsoft QuickC Versions 1.00, 1.01,
 2.00, and 2.01.

 Sample Program:
 --------------

 #include <stdio.h>
 #include <graph.h>
 #include <dos.h>
 #include <conio.h>

 #define TRUE 1
 #define FALSE 0

 void toggle_intensity(int);

 void main(void)  {
    long i;
    char buf[80];
    _clearscreen(_GCLEARSCREEN);
    toggle_intensity(0);
    for (i=16; i < 32; i++) {
       _setbkcolor (i);
       _settextcolor (i+1);
       _settextposition (i-15, 10);
       sprintf(buf, "  Background = %2ld  Foreground = %2d  \n",i,i+1);
       _outtext (buf);
    }
    getch();

    _setbkcolor (_BLACK);
    _clearscreen(_GCLEARSCREEN);
    toggle_intensity(1);
    for (i=16; i < 32; i++) {
       _setbkcolor (i);
       _settextcolor (i+1);
       _settextposition (i-15, 10);
       sprintf (buf, "  Background = %2ld  Foreground = %2d  \n", i, i+1);
       _outtext (buf);
    }
    getch();
 }

 /*  If onoff is True, intesity bit will indicate blinking text  */
 void toggle_intensity(int onoff)  {
     #define         VIDEO_IO        0x10
     #define         BIOS_CALL       0x10
     #define         INTENSITY_TGL   0x03
     union REGS regs;

     regs.h.ah = VIDEO_IO;
     regs.h.al = INTENSITY_TGL;
     if (!onoff)
        regs.h.bl = 0x0;
     else
        regs.h.bl = 0x1;
     int86 (BIOS_CALL, &regs, &regs);
 }


 455. Effective Limit of 52 Threads Per Process with DosCreateThread

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | docerr OpSys PMWin
 Last Modified: 16-JAN-1990    ArticleIdent: Q47933

 A single process running under OS/2 Version 1.10 or 1.00 is limited to
 creating 52 threads with DosCreateThread.

 Attempting to create additional threads results in a return value
 from DosCreateThread of 155, which is defined as ERROR_TOO_MANY_TCBS
 (Thread Control BlockS) in BSEERR.H.

 The "Microsoft OS/2 Programmer's Reference," Volume 3, Page 34,
 incorrectly states "DosCreateThread can create up to 255 threads per
 process." The Reference also fails to note that DosCreateThread could
 return ERROR_TOO_MANY_TCBS.

 The only way to work around the current OS/2 1.x limitation with
 DosCreateThread is by starting additional processes, with each process
 being limited to 52 threads. OS/2 1.10 and 1.00 can support up to 255
 threads total for all processes in the entire system.

 An increase in the limit will be considered for inclusion in a future
 release.

 Note that threads that will be calling C run-time library functions
 should be created with _beginthread, which performs essential library
 initializations that DosCreateThread does not perform. The library
 function _beginthread is limited to creating 31 threads in C 5.10, for
 a total of 32 threads. The next version of C will support the creation
 of substantially more threads with its _beginthread.


 456. Patching malloc() to Reuse Memory within an Allocated Block

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JAN-1990    ArticleIdent: Q47958

 The malloc() family of functions properly reuse the blocks of memory
 that they allocate from DOS. The size of a block that malloc()
 allocates is 8K bytes by default, but can be modified by assigning a
 different block size in bytes to the C run-time library variable
 "_amblksiz", as noted on Page 33 of the "Microsoft C 5.1 Optimizing
 Compiler Run-Time Library Reference."

 However, for small suballocations of "chunks" (author's terminology)
 within an 8K block, previously freed chunks will not be immediately
 reused and fragmentation within blocks can occur; this can cause DOS
 programs that make many small (e.g. 10-byte) allocations to
 prematurely run out of memory. This problem occurs because the "rover"
 pointer that points to the next chunk of memory to be allocated points
 to the memory after the last chunk allocated without being set to
 point to the beginning of chunks that were freed.

 Reducing the size of allocated blocks by declaring _amblksiz as above
 and assigning values under 8096 to it may help reduce fragmentation
 within blocks in some cases simply because there is less memory to
 lose to fragmentation per block and your allocations and frees are
 more likely to be on reusable block boundaries.

 A better alternative would be to allocate large blocks yourself, then
 perform your own memory management within them to prevent
 fragmentation within blocks.

 For those who purchase the C run-time library source code for C 5.10
 available through our Sales department at (800) 426-9400, you can
 force the rover pointer to point at the bottom of the block prior to a
 memory request as noted below, so that any adequately large freed
 chunks will be reused. This technique will result in executable speed
 degradation, but will more fully allocate the last bytes of memory.

 To change the behavior of the rover pointer to reallocate freed chunks
 of memory within a block, make the following change to line 83 of
 AMALLOC.ASM, the workhorse module called by malloc() functions:

 1. Delete or comment out line 83 with a semicolon (;), as follows:

     ;   mov     si,[bx].roveroff; si = starting rover offset

 2. Replace the line above with the following two lines:

         mov     si,[bx].bottom
         mov     [bx].roveroff,si ;*** put rover at bottom each time

 3. Reassemble AMALLOC.ASM with MASM, as follows

         masm /Mx /Dmem_L amalloc;

    where the /Mx option preserves symbol name case sensitivity, and
    /Dmem_L defines the constant to indicate large memory model for
    pointers defined by macros in AMALLOC.ASM and other .ASM files used
    for the C library. The constant "mem_L" is for large model, "mem_S"
    for small, "mem_C" for compact, and "mem_M" is for medium model.

 4. Either link with the new AMALLOC.OBJ (and /NOE), or use lib to
    replace the module in the appropriate memory model library, as
    follows:

         lib llibcer.lib -+amalloc;


 457. Description of a .MAP File's "Program Entry Point"

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 16-JAN-1990    ArticleIdent: Q47959

 The "Program entry point" is the last item in a .MAP file. It refers
 to the segment:offset address of the first instruction of the program
 to be executed, relative to the lowest memory address in the .EXE load
 image (the program loaded into RAM). A more detailed description and
 the use of entry point(s) are noted below.

 The load address can be obtained by adding 10h to the segment address
 of the PSP. (In C, this is available in the variable _psp.)

 An entry point is where code in a module actually begins execution
 via the loading of the CS:IP (CodeSegment:InstructionPointer --
 segment:offset) registers with the entry point address. The entry
 point could be the actual beginning of a program executed by the
 operating system, or it could be an exported function from an
 OS/2 or DOS Windows dynamic link library (DLL).

 The "Program entry point" specified at the end of a .MAP file is where
 the operating system will begin executing the program, RELATIVE to the
 lowest memory address where the program's code will be loaded. In DOS
 or real-mode OS/2, the lowest memory address will be the lowest
 physical address in RAM. In protected-mode OS/2, the lowest relative
 address will be segment selector 1, offset 0.

 The lowest address your code occupies in RAM is usually the first
 routine (function, procedure, or main program body) defined at the
 beginning of your main source file, and it is assigned a RELATIVE
 address of 0000:0000 [or, typically, 0:10 for main()] in DOS or
 real-mode OS/2, or an address of 0001:0000 in protected-mode OS/2.

 For our current high-level languages (except Microsoft QuickPascal
 1.00), the entry point is at the beginning of the routine "__astart".
 Our high-level languages require initialization code before executing
 C's main() function or the main program code for other languages such
 as Microsoft Pascal 3.3x or 4.00, and currently __astart is where the
 initializations begin.

 The "Program entry point" is a segment:offset address above the
 program's relative address of 0:0. For a C program, the entry point
 will be __astart. If the entry point is something like 2:0abc hex, the
 absolute DOS physical address or the virtual OS/2 address where
 __astart will be located can be calculated as follows:

      lowest address of your program's load image  1234:0400
    + relative entry point                         +  2:0abc
    ---------------------------------------------  ---------
    = DOS absolute or OS/2 virtual address of      1236:0e34
      the entry point (__astart)


 458. Extracting a Function ptr from a Variable arg List Function

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_quickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q47961

 To remove an item from a variable argument list, you use the va_arg()
 macro. However, when the element to be removed is complex, you may
 have to typedef the item type. This is necessary because the va_arg()
 macro requires you to provide the type of the item to be removed from
 the list. For a pointer to a function, if you were to put the item
 type (the declaration of the function ptr) as follows

       FuncPtr = va_arg (arg_list, (int(*)(void)) );

 the compiler would yield the following error:

       C2059: Syntax Error : ')'

 You could attempt to get around this by grabbing the function pointer
 as a data pointer, and then typecasting it to a function pointer, as
 in the following line:

       FuncPtr = (int (*)(void)) va_arg (arg_list, char *);

 This would work; however, you will get the following warning:

       C4074: Non-standard extension used, cast of data pointer
              to function pointer

 The best solution to this dilemma is to typedef the function pointer.
 With a typedef, you avoid both the error and the warning.

 This problem occurs in C Version 5.10 and in QuickC Version 2.00 and
 2.01.

 The following example passes a function pointer to a variable argument
 list function, changes that pointer, and returns it to the calling
 procedure. To implement this, however, you need to pass the function
 pointer by reference. For this reason, a pointer is typedef'd to a
 function pointer. Once in the variable argument list function, the
 pointer is dereferenced to the function pointer to get at the actual
 function pointer.

 #include <stdio.h>
 #include <stdarg.h>

 typedef void (*FuncPtr)(void);
 typedef FuncPtr *PFuncPtr;

 void hello(void);
 void varfunc(int, ...);

 FuncPtr func1, func2;
 int i;

 void main(void)  {
    func1 = hello;
    printf ("Function pointer: func1 now points to Hello()\n");
    printf ("About to use func1 to make a call to Hello()\n\n");
    func1();
    printf ("Now lets pass these function pointers to our variable");
    printf (" argument list\n");
    varfunc(2, &func1, &func2);   /* To alter ptr, pass by reference */
    printf ("\nAfter the call to the variable argument procedure,\n");
    printf ("function pointer: func2 now points to Hello()\n");
    printf ("About to use func2 to make a call to Hello()\n\n");
    func2();
 }

 void hello(void)  {
    printf ("Hello, I'm in the procedure HELLO()\n");
 }

 void varfunc(int i, ...)  {
    va_list arg_ptr;
    PFuncPtr tmpfptr;                /* Temporary ptr to function ptr */

    printf ("\nIn function VARFUNC\n");
    va_start (arg_ptr, i);
    printf ("%d arguments were passed\n", i);
    tmpfptr = va_arg (arg_ptr, PFuncPtr);  /* Grab pointer to fnptr */
    *tmpfptr = hello;                      /* Assign fnptr addr of fn */
    tmpfptr = va_arg (arg_ptr, PFuncPtr);  /* Grab pointer to fnptr */
    *tmpfptr = hello;                      /* Assign fnptr addr of fn */
 }


 459. Calling Order Undefined -- Function Calls in Single Expression

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 15-JAN-1990    ArticleIdent: Q47985

 When C evaluates more than one function call in a single expression,
 the calls usually are made in reversed or arbitrary order, rather than
 in the stated order. Since there is no defined precedence in C for the
 order in which multiple function calls are made within a single
 expression, the result is compiler-dependent. In Microsoft's products,
 these functions are usually evaluated from right to left.

 This occurs in C Versions 5.00 and 5.10 and in QuickC Versions 1.01,
 2.00, and 2.01.

 The following code demonstrates this:

 void main( void )
 {
    printf( "First: %d Second: %d", getch(), getch() );
 }

 When this code is compiled and run, it returns first the second
 keyboard code that is scanned. For example, if the F5 key is pressed,
 returning first a null character followed by its extended code, the
 program returns "First: 63 Second: 0." The null character that is
 generated by the keyboard first, is written second.


 460. _bios_serialcom Sends and Receives Single Character Data

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr S_QuickC S_QuickASM
 Last Modified:  7-DEC-1989    ArticleIdent: Q47987

 Question:

 In the "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference" manual, _bios_serialcom() is documented as taking an
 unsigned integer as the data byte. Since this is 16 bits (large enough
 for two characters), can I pass two characters (or receive two
 characters) with each call to _bios_serialcom()?

 Response:

 No, _bios_serialcom() sends (and receives) character data. Two
 characters cannot be sent (or received) with one call because the
 function call is a simple interface to the BIOS interrupt 0x14. This
 interrupt expects the data to be sent (or received) to be in the AL
 register (an 8-bit register). Therefore, the data is limited to 8
 bits, even though the function requires an unsigned integer as the
 data parameter.

 The parameter is an unsigned integer because the _bios_serialcom()
 function also uses the data parameter in initialization and status
 checks. In the send (and read) functions of the interrupt, however,
 only a single byte in the low-order 8 bits of the unsigned integer
 passed as the data parameter are sent. For more information, see
 interrupt 0x14 in "IBM ROM BIOS" by Ray Duncan. This book clarifies the
 interrupt calls that are being made, and what is actually passed to
 the machine.

 This lack of clarification for _bios_serialcom() occurs in the
 documentation for C Versions 5.00 and 5.10; in Microsoft QuickC
 Versions 1.00, 1.01, 2.00, and 2.01; and the QuickC with
 QuickAssembler on-line help Version 2.10.


 461. Possible Causes of "'__iob' : Unresolved External"

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890807-24188 _iob iob
 Last Modified: 16-JAN-1990    ArticleIdent: Q47990

 When linking with CRTLIB.LIB, the problems listed below can cause the
 following message when linking a main program to the C run-time DLL
 created as described in the MTDYNA.DOC file supplied with the C
 Compiler Version 5.10:

    ....  error : L2029 : '__iob' : unresolved external

 The problems that can cause this message include the following:

 1. Compiling with the wrong include files. Typically, this involves
    compiling without the /I option, as described in MTDYNA.DOC.

 2. Compiling without defining the symbol DLL. DLL must be defined in
    any program that calls the C run-time library DLL.

 These options, as well as other important information, are covered in
 Section 5.2 of MTDYNA.DOC.


 462. Using a Wildcard Argument with the remove() Function

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48090

 Question:

 I'm using the remove() function to delete my files, but when I pass
 the wildcard as an argument, the function does not delete any files.
 Is there any why I can use the remove() function to delete all the
 files in the directory when I specify it to?

 Response:

 Yes; use the _dos_findfirst and _dos_findnext functions to search for
 each file and then use the remove() function to delete each file. The
 following example demonstrates how to write a code equivalent to
 remove("*.*"):

 Code Example
 ------------

 #include <stdio.h>
 #include <dos.h>
 #include <io.h>

 main ()
 {
    struct find_t  c_file;
    char fn[12];

    printf ("Enter file to delete: ");
    scanf ("%s", fn);

 /* This code section will delete all the files in the directory. */
    if (strcmp(fn, "*.*") == 0) {
      _dos_findfirst ("*.*", _A_NORMAL, &c_file);
      do {
             remove (c_file.name);
         } while (_dos_findnext (&c_file) == 0);
      }
    else

 /* This section will delete only one file. */
      if (remove (fn) == -1)
         printf ("File not found\n");
      else
         printf ("File successfully deleted\n");
 }


 463. Mixed-Language Examples for Calling Pascal Are Incorrect

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr H_MASM S_PasCal
 Last Modified: 16-JAN-1990    ArticleIdent: Q48251

 In the "Microsoft Mixed-Language Programming Guide" provided with C
 Versions 5.00 and 5.10, MASM Versions 5.00 and 5.10, and Pascal
 Version 4.00, there is a sample Pascal module that is incorrect. This
 module is called Pfun and it appears in three different sections of
 the manual. Pfun can be found in the following locations:

 1. Page 30, Section 2.5.2 "Calling Pascal from Basic -- Function Call"

 2. Page 44, Section 3.5.2 "Calling Pascal from C -- Function Call"

 3. Page 57, Section 4.5.2 "Calling Pascal from FORTRAN -- Function Call"

 If the Pascal source code shown on these pages is compiled, the
 following errors occur:

   21  7   begin
 = 22  8     Fact := Fact * n;
       8  --------------^Warning 171 Insert (
       8  ----------------^268 Cannot Begin Expression  Skipped
       8  -------------------^Warning 155 ; Assumed ,
       8  -------------------^257 Parameter List Size Wrong Begin Ski

 To get the code to compile correctly, all of the incorrect references
 to Fact must be removed and replaced by a temporary variable. The
 following source code contains the necessary changes to the Pfun
 module so that it will compile and run without any errors:

 module Pfun;
   function Fact (n : integer) : integer;

 {Integer parameters received by value, the Pascal default. }

   var   temp : integer;

   begin
      temp := 1;
      while n > 0 do
         begin
             temp := temp * n;
             n := n - 1;
         end;
      Fact := temp;
   end;
 end.

 Note: There is an incorrect reference to the errors in the Fact
 function in the Pascal Version 4.00 README.DOC file. This correction
 does not work.


 464. Mixed-Language Examples for Calling Fortran Are Incorrect

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr H_MASM S_PasCal
 Last Modified: 16-JAN-1990    ArticleIdent: Q48424

 In the "Microsoft Mixed-Language Programmer's Guide" provided with C
 Versions 5.00 and 5.10, MASM Versions 5.00 and 5.10, and Pascal
 Version 4.00, the C and Pascal sample programs for calling a FORTRAN
 subroutine are incorrect. The documentation error appears in two
 different sections of the manual. The documentation error may be found
 in the following locations:

 1. Page 40, Section 3.4.1, "Calling FORTRAN from C -- Subroutine Call"

 2. Page 67, Section 5.5.1, "Calling FORTRAN from Pascal -- Subroutine
    Call"

 The source code in the manual compiles, but when linked with the
 FORTRAN subroutine, the following error occurs:

    LINK : error L2029: Unresolved externals:

    MAXPAR in file(s):
     FACT.OBJ(fact.c)

    There was 1 error detected

 This error occurs because the FORTRAN subroutine has a different name
 than is used by the calling programs (maxparam instead of maxpar). To
 get the two modules to link correctly, the following changes must be
 made:

 In C (Page 40), change

    extern void fortran maxpar (int near *, int near *);
                 .
                 .
    maxpar (&a, &b);

 to the following:

    extern void fortran maxparam (int near *, int near *);
                 .
                 .
    maxparam (&a, &b);

 In Pascal (Page 67), change

    procedure Maxpar (var i,j : integer) ; extern;
                 .
                 .
    Maxpar (a,b);

 to the following:

    procedure Maxparam (var i,j : integer) ; extern;
                 .
                 .
    Maxparam (a,b);


 465. Macros ceil and floor Incorrectly Listed As Functions

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-JAN-1990    ArticleIdent: Q48431

 Page 94, Section 3.3.13 of the "Microsoft C 5.1 Optimizing Compiler
 User's Guide" incorrectly lists ceil and floor as functions that have
 intrinsic forms.

 As correctly noted in the "Microsoft C 5.1 Optimizing Compiler
 Run-Time Library Reference" on Pages 152 and 270, ceil and floor are
 macros defined in the include file MATH.H.


 466. The Interrupt Attribute Pushes Registers on the Stack

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC  S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48444

 The interrupt attribute can be applied to a function to tell the
 compiler that the function is an interrupt handler.

 When an interrupt function is called, all registers (except SS) are
 saved on the stack. Examining the assembler code the compiler
 generates for an interrupt handler could cause confusion. When
 compiling without the /G1 or /G2 switch (these switches inform the
 compiler to generate 186 or 286 code accordingly) the assembler code
 appears as it should, however, when using one of the two
 aforementioned switches, the assembler output may be deceiving in that
 the registers appear as though they are not being saved on the stack
 as advertised.

 This potential misinterpretation results from the use of the PUSHA
 instruction, which does not exist in the 8086 instruction set, but
 does apply to the 80186 and more recent sets. The PUSHA instruction
 pushes the general purpose registers onto the stack in the following
 order: AX, CX, DX, BX, SP, BP, SI, DI.  For further information
 regarding the PUSHA instruction, you should consult an reference
 manual for Intel's 80x86-based assembly.

 The text that follows displays two partial assembler listings of an
 interrupt handler called foo. The second case demonstrates the usage
 of the 186, 286, 386 specific instruction PUSHA (for load all).

 /* Without G1 or G2 */

 _foo    PROC FAR
         push    ax
         push    cx
         push    dx
         push    bx
         push    sp
         push    bp
         push    si
         push    di
         push    ds
         push    es

  /* With G1 or G2 */

  _foo    PROC FAR
         pusha              ; This pushes all general purpose registers
         push    ds         ; for the 80186 processors and above.
         push    es


 467. How to Find the Total Stack Size from within a Program

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890831-26299
 Last Modified: 16-JAN-1990    ArticleIdent: Q48686

 Question:

 How can I find the total size of the stack from within my program?

 Response:

 The program below calculates the total size of the stack. Note that
 this works slightly differently for protected-mode and bound programs
 than for real-mode programs. (Normally, the two-byte difference
 shouldn't be important.)

 The symbol "_end" is declared just below the lowest location in the
 stack. At any given time, the amount of space left on the stack is SP
 - offset _end. (The C program doesn't use the underscore because C
 automatically prepends an underscore to all identifiers.)

 The start-up code stores the maximum (initial) value of SP in the
 variable __atopsp. (The program below uses only one underscore rather
 than two for the reason described in the previous paragraph.)

 Default stack checking on function entry fails when the amount left is
 less than 256 bytes for DOS, or less than 512 bytes for OS/2. When
 stack checking fails, you receive the following run-time error:

    run-time error R6000
    - stack overflow

 The program to calculate the total stack size follows:

 #include <stdio.h>

 extern unsigned int end;

 extern unsigned int _atopsp;

 void main(void)
 {
     unsigned stksize;

     stksize = _atopsp - (unsigned)&end + 2;
         /* don't add 2 for protected-mode or bound programs */

     printf("Total stack size is %u bytes (%x hex bytes)\n",
         stksize, stksize);
 }


 468. int86x() and int86() Trap for Interrupts 25h, 26h

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48744

 Interrupts 25h (absolute disk read) and 26h (absolute disk write)
 require special handling when being used because they leave the CPU
 flags on the stack upon termination.

 Functions int86x() and int86() work reliably with these interrupts.
 The int86() functions trap for these two interrupts, and take care of
 the stack appropriately. Use one of the int86() functions to make
 these calls as you would any other DOS interrupt call. You need take no
 extra precautions with these interrupts.

 The following example demonstrates the straight-forwardness of the
 function call:

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

 /*****            WARNING!!!!!          ******/
 /* If you change the following line so that DRIVE_A is assigned a 2 or
    above, you could destroy data on your hard drive. This test program
    segment was written to read and write from the floppy disk A:        */
 #define DRIVE_A 0                    /* 0=A, 1=B, 2=C, etc. */
 #define ONE_SECTOR 1
 #define ABS_WRITE 38                 /* Decimal value of int call */
 #define ABS_READ 37                  /* Decimal value of int call */
 unsigned int far *out;               /* Pointer to Data to be output */
 unsigned int far *input;             /* Pointer to Data Transfer Area */
 unsigned int output;                 /* Data to be output */
 union REGS inregs, outregs;
 struct SREGS segregs;

 void main(void)  {
    out = &output;
    input = (unsigned int far *) malloc (1024 * sizeof(unsigned int));
    *out = 11;
    inregs.h.al = DRIVE_A;              /* Write to Drive A */
    inregs.x.cx = ONE_SECTOR;           /* Write one sector only */
    inregs.x.dx = 3;                    /* Logical sector 3 */
    segregs.ds = FP_SEG(out);           /* Get Seg address of output */
    inregs.x.bx = FP_OFF(out);          /* Get Offset of output */
    outregs.x.ax = 0;                   /* No error */
    int86x (ABS_WRITE, &inregs, &outregs, &segregs);

    inregs.h.al = DRIVE_A;              /* Read to Drive A */
    inregs.x.cx = ONE_SECTOR;           /* Read one sector only */
    inregs.x.dx = 3;                    /* Logical sector 3 */
    segregs.ds = FP_SEG(input);         /* Get Seg address of buffer */
    inregs.x.bx = FP_OFF(input);        /* Get Offset of buffer */
    outregs.x.ax = 0;                   /* No error */
    int86x (ABS_READ, &inregs, &outregs, &segregs);
    printf ("%u was read from drive A: \n", *input);
 }


 469. Potential Problems with Identifiers Over 31 Characters

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC S_QuicKASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48790

 The #define statement in Microsoft C accepts identifiers up to 31
 characters. The compiler truncates identifiers over 31 characters, and
 on warning level 1 or greater, produces the following warning message:

    warning C4011: identifier truncated to '<truncated identifier>'

 This can cause potential problems if two or more identifiers are
 identical up to the 31st character. If this is the case, the following
 warning message appears for each additional #define that is identical
 when truncated (on warning levels 1 or greater):

    warning C4005: '<truncated identifier>' : redefinition

 All of these identifiers are assigned the value of the last identifier
 that was identical when truncated.

 This information also applies to QuickC Versions 1.01, 2.00, 2.01 and
 QuickAssembler Version 2.01.


 470. Include Filenames More Than Eight Characters Are Truncated

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48792

 When given a filename that is more than eight characters, the file
 system under MS-DOS truncates the filename to eight characters.
 Because of this, the following include statement

    #include <gefildefish.h>

 looks for the following header file to resolve the reference:

    gefildef.h

 As long as the file gefildef.h is found on the disk, no error or
 warning message is displayed.

 Under OS/2 Version 1.10, however, the file system does not truncate
 names, but filenames with more than eight characters are not used.
 Therefore, the following fatal error message appears when specifying
 an include file with more than characters:

    C1015: cannot open include file '<filename>'

 This problem also occurs in QuickC Versions 1.01, 2.00, 2.01 and
 QuickAssembler Version 2.01.


 471. exec() and spawn() with P_OVERLAY Ignore Maximum Allocation

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q48793

 Exec() and spawn() with P_OVERLAY ignore the maximum memory allocation
 information in the .EXE file header. If you exec or spawn with
 P_OVERLAY, a program whose maximum allocation is set equal to the
 minimum allocation (through EXEMOD or the LINK option /CP:1), the
 program is allocated the full 64K DGROUP.

 The effective maximum allocation for any exec'ed (or spawn'ed with
 P_OVERLAY) program is 0xffff (whatever DOS has available), regardless
 of the maximum allocation number in the program's .EXE header. When
 run from the DOS prompt, the maximum allocation information of the
 same program is honored.

 This behavior occurs because the exec() and spawn() with P_OVERLAY
 functions do not invoke COMMAND.COM, which looks at the minalloc and
 maxalloc fields in the exe header. This is expected behavior for
 exec() and spawn() with P_OVERLAY in C Versions 4.00, 5.00, and 5.10,
 and QuickC 1.00, 1.01, 2.00, and 2.01 (QuickAssembler), as documented
 in the C 5.10 README.DOC on Line 1275, in the run-time library notes
 section for the exec() functions.

 Alternatives
 ------------

 Instead of calling a program with exec() or spawn() with P_OVERLAY,
 call COMMAND.COM with the desired child program as an argument using
 exec() or spawn() with P_OVERLAY, as follows:

 spawnl(P_OVERLAY,"c:\\command.com","command.com","/c child.exe",NULL);

 COMMAND.COM then loads your application as if it was from the DOS
 prompt. Note, however, that the COMMAND.COM shell itself requires
 approximately 4K. Also, consecutive exec() or spawn() with P_OVERLAY
 calls using this method run additional shells of COMMAND.COM,
 accumulating one 4K shell per generation, as illustrated below:

           +------+    +------+    +------+    +------+
           |  P1  |--> |__P2__|--> |__P3__|--> |__P4__|
           +------+    | .COM |    |_.COM_|    |_.COM_|
                       +------+    | .COM |    |_.COM_|
                                   +------+    | .COM |
                                               +------+

 Another option is to call your program with the system() function, but
 this does not overlay the child process.

 Additional reference words: execl execle execlp execlpe execcv execve
 execvp execvpe spawnl spawnle spawnlp spawnlpe spawnv spawnve spawnvp
 spawnvpe


 472. Newline Character (\n) Is Equivalent to ASCII Linefeed (0x0A)

 Product Version(s): 5.00 5.10  | 5.00 5.10
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QuickC S_QuickAsm
 Last Modified: 16-JAN-1990    ArticleIdent: Q48885

 The newline character in Microsoft C (\n) is equivalent to the ASCII
 linefeed character (hex 0A). Thus, for files opened in text mode,
 CR/LF pairs are read in as newline characters, and newline characters
 are written as CR/LF.

 This information applies to STDIN, STDOUT, and STDERR, which are
 opened in text mode by default.

 When using strtok() to extract tokens separated by CR/LF in a file
 opened in text mode, only \n must be used as a token delimiter.


 473. Cast of Float to Long Truncates Value to 1 Less Than Expected

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickAsm
 Last Modified:  7-DEC-1989    ArticleIdent: Q48928

 Question:

 When I cast a float to a long integer, the result is one less than the
 expected value.

 The following is an example:

    double i, j;
    char  r[] = "16.49";

    i = atof(r) * 100;
    printf ("%ld\n", (long)i);

 What causes this code to produce 1648 instead of 1649?

 Response:

 When a float or double value is converted to an integer number, the
 value is truncated. You are getting 1648 and not 1649 because the
 float value is not stored exactly as 1649.0000. The value is stored as
 1648.99999...999. When you cast the double value to a long integer,
 the number is truncated at the decimal point to 1648.

 This is expected behaviour for C Version 5.10, QuickC Versions 1.01
 and 2.00, and QuickC with QuickAssembler Version 2.01.

 The workaround for this constraint is to add 0.5 to the double value
 before converting to an integer value. The following code produces the
 correct result:

 Sample Code
 -----------

 #include <stdio.h>
 #include <math.h>

 double i, j;
 char  r[] = "16.49";

 main ()
 {
         i = atof(r) * 100;
         printf ("%ld\n", (long)(i + 0.5));
 }


 474. qsort() Appears Extremely Slow in Worst-Case Situations

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 16-JAN-1990    ArticleIdent: Q48965

 Question:

 When using qsort() in a worst-case situation (e.g. the array is
 already sorted in reverse order), the qsort() library routine appears
 to take an extremely long time. Have I done something wrong in my
 program or does a problem exist with Microsoft's qsort() algorithm?

 Response:

 The qsort() routine that was provided by Microsoft was optimized for
 both speed and stack usage [stack space is important because qsort()
 is heavily recursive]. Therefore, in a worst-case situation, which
 could recurse up to the number of elements in the list, qsort()
 sacrifices speed for stack space. This behavior allows larger lists to
 be sorted without stack overflow problems. Furthermore, Microsoft's
 qsort() routine is very competitive in sorting random files, the type
 of array for which quick sorts are designed.

 If used judiciously, Microsoft's qsort() is a very effective sort
 routine. In worst-case situations, Microsoft's qsort() is slower than
 some other sorting routines, but successfully sorts larger arrays
 without stack overflow problems.

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


 475. Confusion Regarding the /Zs Switch

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC S_QuickAsm
 Last Modified: 16-JAN-1990    ArticleIdent: Q48967

 The /Zs switch instructs the compiler to scan your code and check for
 syntax errors. This switch does not generate any code. Switches that
 assume code will be generated do not have any effect when used in
 conjunction with /Zs.

 Therefore, if you are using the /Zs switch and are unaware of the fact
 that it does not generate any code, it may appear that other switches,
 such as the /Fa switch, which generates an assembly listing, do not
 function.


 476. DOS APPEND Is Not Utilized with access() Function

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 16-JAN-1990    ArticleIdent: Q49006

 The Microsoft C run-time library function, access(), determines
 whether or not a specified file exists and can be accessed in read
 and/or write mode(s). The access() function searches the current
 working directory for the particular file or the directory specified
 by a path to the file.

 The DOS APPEND command, which establishes a search path for data files
 and works similarly to the PATH environment variable, appears to be a
 way to assist access() in finding files outside the current working
 directory without having to supply a path. However, the APPEND command
 does not search the data path when locating a file to be used by the
 access() function. Consequently, access() fails when searching for a
 file issued with no path and that is not in the current working
 directory.

 As documented in the "Microsoft MS-DOS User's Guide and User's
 Reference" on Page 30, APPEND searches the data path for all files
 with only the following MS-DOS system calls:

    Code          Function
    ----          --------

    0FH           Open File (FCB)
    23H           Get (FCB) File Size
    3DH           Open Handle
    11H           FCB search first  (with /x switch only)
    4EH           Handle find first (with /x switch only)
    4BH           Exec (with /x switch only)

 The access() function makes an MS-DOS system call to interrupt 21H
 function 43H, which sets and retrieves file attributes. Since this is
 not a system call listed above, APPEND does not perform file
 searching.

 The following program illustrates the APPEND limitation. The program
 uses access() to determine whether the file named TEST exists. Assume
 that the TEST data file is not in the current working directory, but
 instead is in a directory called c:\foo, and that the APPEND command
 "APPEND=c:\foo" was issued previously to set the appropriate search
 path.

 Sample Program
 --------------

 #include <io.h>
 #include <fcntl.h>
 #include <stdio.h>

 FILE * stream;

 void main( void )
 {
   /* check for existence of TEST fails despite having APPEND set */
   if ((access( "TEST", 0 )) == -1 )
   {
         printf( "file was not found with APPEND set\n\n" );

   /* however, fopen() recognizes APPEND for successful access */
         if ((stream = fopen( "TEST", "r")) != NULL )
             printf( "file opened successfully using APPEND" );
   }
 }


 477. Declaring a Pointer to a Function: C4071

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickAsm
 Last Modified: 16-JAN-1990    ArticleIdent: Q49064

 The following usual method of declaring a pointer to a function

    type (*ptr)();
    ptr = function;

 causes the following compiler warning when compiling with the "/W3"
 option:

    C4071: 'ptr' : no function prototype given

 Use one of the following methods to avoid the error message:

 1. Use the warning level flag "/W2" instead of "/W3".

 2. Prototype the function itself and then specify actual parameters
    when declaring the pointer, as follows:

       type (*ptr)(parameter_list);
       ptr = function;

 Note: The parameter list must be exactly the same parameter list with
 which the function was declared.

 The following program compiles and links with NO warnings when
 compiling with the '/W3' warning level flag set:

 /*  Must have 'stdio.h' to prototype 'printf' */
 #include <stdio.h>

 void main (void)
 {
    /* Declare 'fun_ptr' as a pointer to a function  */
    int (*fun_ptr)(const char *, ...);
    int other_args;

    /* Assign pointer to the specific function, 'printf' */
    fun_ptr = printf;

    /* Standard usage in calling environment */
    fun_ptr("format string goes here", other_args);
 }


 478. Error in Run-Time Reference to _getcursorposition

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q49428

 Appendix B of the "Microsoft C Run-Time Library Reference" and
 "Microsoft QuickC Run-Time Library Reference" lists routines that are
 specific to MS-DOS. The lists in both references refer to the
 _getcursorposition routine. The routine referred to should be
 _getcurrentposition.

 The error can be found in the C run-time library reference on Page
 655. The same error is found on Page 655 of the QuickC Versions 1.00
 and 1.01 run-time library reference. This manual is sent upon request
 to QuickC 2.00 or 2.01 customers who desire a hard copy of the
 reference.

 The list shown in Appendix B in the manuals is not included in the
 QuickC 2.00 and 2.01 on-line help references.


 479. Ftime: C Function -- Documentation Supplement

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM docsup
 Last Modified: 17-JUL-1990    ArticleIdent: Q49501

 The ftime function takes a pointer to a timeb structure as its only
 parameter and has no return value. Ftime calculates the current time
 and returns it by modifying the timeb structure. The structure
 contains the following elements in the given order:

 Name      Type           Description
 ----      ----           -----------

 time      time_t(long)   The time in seconds since 00:00:00 Greenwich
                          mean time, January 1, 1970. This time is
                          calculated under MS-DOS by calling Int 21,
                          function 2Ah (Get Date), converting the
                          results to seconds, and adding the current
                          time, which is also converted to seconds.

 millitm   USHORT         Fraction of a second in milliseconds. This
                          value is actually not milliseconds on most
                          systems. On most IBM PCs and compatibles, the
                          clock speed is not fast enough to compute
                          milliseconds, or indeed, hundredths of
                          seconds. The ftime function calls interrupt
                          21, function 2Ch (under DOS), which returns,
                          among other information, the seconds in
                          hundredths. The hundredths information is an
                          estimation based on the clock speed, which is
                          approximately 18.2 ticks per second on most
                          PCs. The hundredths value is then multiplied
                          by ten to get the millisecond value.

 timezone  short          The difference in minutes, moving westward,
                          between Greenwich mean time and local time.
                          This is equal to the global variable
                          timezone, from a call to the tzset function.

 dstflag   short          This flag is nonzero if daylight savings
                          time (DST) is currently in effect for the local
                          time zone. This is done by a call to the
                          internal function _isindst. This function
                          takes a timeb structure as a parameter and
                          returns an integer flag. This is the rule for
                          years before 1987; a time is in DST if it is
                          on or after 02:00:00 on the last Sunday in
                          April and before 01:00:00 on the last Sunday
                          in October. This is the rule for years
                          starting with 1987; a time is in DST if it
                          is on or after 02:00:00 on the first Sunday
                          in April and before 01:00:00 on the last
                          Sunday in October. (See tzset for more
                          information on DST.)

 Other sources of information include the Version 5.10 "Microsoft C for the
 MS-DOS Operating System: Run-Time Library Reference," Pages 308-9 and
 the ftime function in the "C Run-Time Library Source Routines".


 480. sscanf with %i and a Leading 0 Gives Octal Conversion Results

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM scanf sscanf fscanf
 Last Modified: 22-NOV-1989    ArticleIdent: Q49573

 Question:

 Why does sscanf return incorrect results when I use the %i switch, yet
 it returns correct results when I use the %d switch?

 Response:

 The %i switch has the capability of reading in decimal, octal, and
 hexadecimal numbers. Hexadecimal numbers are specified with the 0x in
 front of the number, while octal numbers are specified with the 0
 (zero) in front of them. If you want only decimal numbers to be read
 in, use the %d switch.

 This is expected behavior and occurs with the entire scanf family.


 481. Inconsistent Use of fscanf %x.xf Formatting May Produce Errors

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C S_QuickC
 Last Modified: 17-JUL-1990    ArticleIdent: Q49823

 Using the Microsoft C 5.10 run-time library function fscanf() with the
 format specifier %x.xf to read floating-point values usually produces
 undesirable results. This happens especially if the file contains
 floating point information that was not recorded using the same %x.x
 specifier that is being used to read.

 This is not a problem with the fscanf() function (see below).

 The following code can be used as an example of expected behavior:

 #include<stdio.h>

 void main( void )
 {
    float a = 3.104f, b = 34.23534f, c = 834.3432f, d = 5968.394f;
    float e = 34253.2f;
    float ar, br, cr, dr, er;
    FILE *stream;

    if( (stream = fopen( "file.tst", "a" )) == NULL )
       printf( "ERROR:  Unable to open output file" );
    else
       fprintf( stream, "%f,%f,%f,%f,%f\n", a, b, c, d, e );
    fclose( stream );
    if( (stream = fopen( "file.tst", "r" )) == NULL )
       printf( "ERROR:  Unable to open input file" );
    else
                     /* NOTE:  %x.x format specifier */
    {                /*  |  */
       printf("Values: %2.4f, %f, %f, %f, %f\n", a, b, c, d, e );
       fscanf( stream, "%4f,%4f,%4f,%4f,%4f", &ar, &br, &cr, &dr, &er);
       printf("After Read: %f, %f, %f, %f, %f\n", ar, br, cr, dr, er );
    }
 }

 The output from the program is as follows:

    Values: 3.104000, 34.235340, 834.343201, 5968.394043
    After Read: 3.1000, 0.000000, 0.000000, 0.000000

 The unwanted behavior is obvious, as the "Values" above are what is
 contained in the output file "file.tst" and these are definitely not
 the values that are read back in.

 However, this is not a problem with the fscanf() function. The first
 value is read in correctly. After the first value is read, the file
 pointer points to the second 0 (zero) in 3.104000. When the second
 value is read, the information in the file does not conform to
 floating-point format, and zeros are read after that. The compiler has
 no way of knowing how far to move the file pointer to get to the next
 value.

 If the %2.4f in the fscanf() line in the code above were replaced by
 %f, the program output would be as follows:

    Values:     3.104000, 34.235340, 834.343201, 5968.394043
    After Read: 3.104000, 34.235340, 834.343201, 5968.394043

 To read truncated or formatted floating-point values from a file, use
 the %f format specifier and modify the values after they are read.


 482. Use of the /Gt Switch in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  7-DEC-1989    ArticleIdent: Q49840

 Question:

 I am using large memory model and the /Gt switch when programming and
 I still get the message "stack plus data larger than 64K." Could you
 give me some pointers about where data goes when using large model? Do
 heap and stack still remain in DGROUP when I use /Gt?

 Response:

 What goes out of the default data segment depends on how you use /Gt.
 /Gt alone is the same as /Gt256, which means that ONLY data items of
 size 256 and greater get moved out. If you have a lot of data items
 smaller than that, that data will NOT get moved out. With /Gt256, it
 is still possible that the data left in DGROUP plus the stack could
 exceed 64K.

 As the value on the /Gt switch becomes smaller, more and more data
 gets pushed out. /Gt0 pushes all of the data generated by your program
 out. However, it also generates some constants in the logical segment
 _CONST in DGROUP, 2 bytes for each extern or uninitialized variable
 moved. The following classes of variables will generate a 2-byte
 segment address in DGROUP for EACH variable of that class declared
 when /Gt0 is used:

 1. All extern declarations, such as "extern int i;"

 2. All declarations without storage class that are not initialized,
    such as "int i;"

 Initialized variables such as "int i = 0;", provided that the sum of
 their sizes is less then 64K, are treated as a group and generate only
 one segment address in DGROUP per module. Therefore, the optimal
 number for minimizing DGROUP space is /Gt3. /Gt3 is better than /Gt0
 for uninitialized and extern variables because /Gt0 will move out 1-
 and 2-byte data elements to the far heap, replacing them with 2-byte
 segment addresses. Not only does this NOT save you space in DGROUP
 V.S. /Gt3, but it will increase the overall size of the executable
 V.S. /Gt3 as you also have to pay 2 bytes in the far heap per data
 element moved. Another reason to use /Gt3 over /Gt0 is that although
 the size of DGROUP will remain the same, /Gt0 will cause character and
 integer data elements to be addressed with far pointers, slowing
 execution. With /Gt0, all that remains in DGROUP is the stack, several
 kilobytes of variables associated with the run-time library, the near
 heap (from which will be allocated some file buffers and the local
 copy of the environment), and the 2-byte segment addresses for data
 items moved out as needed.


 483. Installing In-Line 80 x 87 Assembly Instructions

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr appnote
 Last Modified: 16-JAN-1990    ArticleIdent: Q49842

 The assembler code on Page 168 of the "Microsoft C Optimizing Compiler
 User's Guide," Version 5.10, is incorrect. When assembled and linked
 with your C application, this code will cause divide by zero and
 overflows to be masked.

 This behavior occurs because the code on Page 168 is incomplete. The
 correct code is listed below. Case is important, so assemble with the
 -Mx switch. You should also link with the /NOE switch. This code is
 provided to produce in-line 8087 instructions on FORTRAN Versions 4.x
 and C Versions 5.x.

 This application note is also available from Microsoft Product Support
 Services by calling (206) 454-2030.

 ;************************************************************************
 ;rmfixups.asm -
 ;
 ;   Copyright (c) 1988-1988, Microsoft Corporation.  All Rights Reserved.
 ;
 ;Purpose:
 ;  Link with rmfixups.obj in order to prevent floating point instructions
 ;  from being fixed up.
 ;  The case of these names is important so assemble with the -Mx switch.
 ;
 ;*************************************************************************

 public  FIWRQQ,FIERQQ,FIDRQQ,FISRQQ,FJSRQQ,FIARQQ,FJARQQ,FICRQQ,FJCRQQ

 FIDRQQ  EQU     0
 FIERQQ  EQU     0
 FIWRQQ  EQU     0
 FIARQQ  EQU     0
 FJARQQ  EQU     0
 FISRQQ  EQU     0
 FJSRQQ  EQU     0
 FICRQQ  EQU     0
 FJCRQQ  EQU     0

 extrn   __fpmath:far
 extrn   __fptaskdata:far
 extrn   __fpsignal:far

 CDATA   segment word common 'DATA'
         dw      0
         dd      __fpmath
         dd      __fptaskdata
         dd      __fpsignal
 CDATA   ends

 end


 484. Mixing Case of LINK Option Causes Error L1093 or D4002

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-NOV-1989    ArticleIdent: Q49871

 When specifying linker options from the CL or the QCL command line,
 the word "link" must be all lowercase letters. If the word "link" is
 not all lowercase, the error that occurs is either:

    Command line warning D4002 : ignoring unknown flag '-xxxx'

    or

    LINK : fatal error L1093: xxxx.OBJ : object not found

 Note: xxxx is the four letters keyed in after the "/" (forward slash)
 or the "-" (hyphen).

 For example, issuing the following command from the MS-DOS or OS/2
 command prompt

    cl file.c /Link graphics.lib

 produces the following error:

    Command line warning D4002 : ignoring unknown flag '-Link'


 485. Fread() Can Read More Than 64K at a Time

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-NOV-1989    ArticleIdent: Q49872

 It is possible to read more than 64K at a time with the fread()
 function by specifying an item size greater than 1 and a count from 1
 to 64K. The resulting number of bytes read will be the product of size
 and count.

 The follow code demonstrates how to read a file 200K in length:

 /* Must be compiled in huge memory model */
 #include <stdio.h>

 char huge buffer[205000];

 void main(void)
 {
      FILE *fp;

      fp=fopen("testfile.dat","r");

      fread(buffer,4,51200,fp);     /* 51200*4=204,800 */

     /* The value returned from the line above will be the number of
        items read. This number is limited to 64K because it is of
        type size_t. But remember, the total number of bytes read is
        equal to the number of items times the size of each item, which
        is 4 bytes in this case. Therefore, the total bytes read
        is 4 times 51200 or 204,800 bytes. */
 }


 486. /Ol Causes Constant Overflow Warnings c4057 c4056

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50251

 The following small program, when compiled with loop optimization
 (/Ol), produces the following warnings on the auto-decrement statement
 in the second for loop:

    warning C4057: overflow in constant multiplication
    warning C4056: overflow in constant arithmetic

 The warnings occur as a side effect of the optimization of the second
 loop. Because the second loop has no functional value, it is optimized
 to the loop-terminating conditions by the compiler. The warnings
 appear to be benign; the program runs as expected. It is recommended,
 however, that if you encounter these errors you generate an assembly
 listing of the code and check the loop for correctness. These warnings
 do not occur in any version of QuickC, QCL, or QuickAssembler.

 Sample Code
 -----------

 #include<stdio.h>

 void main(void)
 {
      unsigned char *p1,
                       *start,
                       i,
                       j;

      start = "abcdefgh";
      for(i = 0, p1 = &start[7]; i < 7; i++){
           p1--;
           j = *p1;
      }
      for(i = 0, p1 = &start[7]; i < 7; i++){
           p1--;
      }
 }


 487. Calculating Available Memory in Large Model

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickAsm
 Last Modified: 17-JUL-1990    ArticleIdent: Q50297

 Question:

 I am using large-memory model (C Version 5.10). My program makes a
 call to the _memavl() function to see how much memory is remaining. I
 get back some number (for example, 29,320 bytes). Then I malloc some
 buffers for linked lists, data structures, and place another call to
 _memavl. I get back the same number.

 Shouldn't the number get smaller after I have malloc'd memory?

 Is there a way for me to find out how much free memory (total) is
 available?

 Response:

 There are two memory-allocation heaps when you're using large model.
 The near heap is the unused portion of the 64K DGROUP segment. The far
 heap is the unused memory above your program. malloc() uses the near
 heap for small and medium models and the far heap for compact, large,
 and huge models. [You can choose which heap to use by using _fmalloc()
 for the far heap and _nmalloc() for the near heap.]

 The _memavl() function measures only the amount of memory available on
 the near heap. Because the near heap is not used in far model until
 the far heap is exhausted, _memavl() does not necessarily change.

 To measure the amount of memory available on the far heap, you can use
 the _dos_allocmem() function. (This function calls the DOS
 memory-allocation function.) Pass the function 0xFFFF for the number
 of 16-byte paragraphs to allocate (which is 1 megabyte more memory
 than the machine has) and the address of an unsigned int. When the
 function returns, the unsigned int whose address you passed will
 contain the paragraph size of the largest contiguous block in the far
 heap. To find the number of bytes, multiply this by the 16L, which is
 the size of a paragraph. (Use 16L rather than 16 so that the
 multiplication will be done using long math, avoiding possible
 overflow.)

 The total memory available is the sum of the amount available on the
 far and near heaps. For best accuracy, you should do this calculation
 immediately after your program begins.

 The following are a few traits of the malloc() allocation family of
 which you should be aware:

 1. malloc() does NOT call DOS for each small allocation. Instead, it
    asks DOS for an 8K block (this size can be set by setting the
    global variable _amblksiz, as described on Page 33 of the
    "Microsoft C Run-Time Library Reference"), then allocate from this
    block. If the requested allocation is more than than 8K, malloc
    allocates enough 8K blocks to fulfill the allocation. Before
    malloc() asks DOS for memory, it first tries to allocate the
    request from memory it already has.

 2. free() NEVER returns memory to DOS. So, if you allocated a block,
    checked the far heap space using _dos_allocmem(), free()'d the
    block and checked again, the amount of memory available to DOS
    would NOT increase on the second call. You can get a better idea of
    how much memory is available by using _heapwalk() to find out how
    much memory is available to malloc() but not to DOS.

 Note: halloc() calls DOS directly and frees directly [using hfree()]
 back to DOS.

 A program that calculates an estimate of the total amount of free
 memory follows:

 Sample Program
 --------------

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

 void main(void)
 {
 long farheap = 0, total_free, available;
 unsigned farparaavail;
 struct _heapinfo hinfo;
 int heapstatus;

   /* Calculates the total memory available in the far heap       */

   hinfo._pentry = NULL;
   while ((heapstatus = _heapwalk(&hinfo)) == _HEAPOK)
          if (!hinfo._useflag)
                 farheap += hinfo._size;

   /* _dos_allocmem will return the maximum block size available */
   /* _memavl() will return the maximum memory in the near heap  */

   _dos_allocmem(0xFFFF, &farparaavail);
   available = (long)farparaavail * 16L + _memavl();

   /* Total memory available for allocation */

   total_free = farheap + available;
   printf("Total memory available is about %ld bytes\n", total_free);
 }

 The total memory calculated in the far heap may not be in a contiguous
 block. To see whether or not memory has been fragmented, add the
 following line to the while loop:

    printf ("%6s block at %p of size %4.4X\n,
    (hinfo._useflag == _USEDENTRY ? "USED" : "FREE"),
    hinfo._pentry, hinfo._size);

 To see how fragmented the near heap is, change the _heapwalk() in the
 while statement to _nheapwalk(). This forces the function to do a heap
 walk on the near heap. The _heapwalk() defaults to the following:

    _fheapwalk in Compact and Large model
    _nheapwalk in Medium and Small model


 488. atexit() Returns Zero if Successful

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER| | docerr S_QuickC
 Last Modified: 30-NOV-1989    ArticleIdent: Q50334

 Question:

 The "Microsoft C for the MS-DOS Operating System: Run-Time Library
 Reference" has conflicting statements regarding the return code from
 atexit(). What is the proper return code?

 Response:

 There is an error in the run-time library reference for the atexit()
 function (Page 124) under DESCRIPTION. The correct return values are
 described in the RETURN VALUE section. atexit() should return a value
 of zero (0) if successful and nonzero (-1) on error.


 489. Passing a Stream File Pointer (FILE *) Between DLLs

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50336

 Question:

 Regarding single-thread DLLs built with the C 5.10 single-thread
 DLL support library LLIBCDLL.LIB:

 My main() function calls a function in my first DLL, which fopen()s a
 buffered stream file. The function in my first DLL calls a function
 in my second DLL, passing the stream pointer (FILE *) as an argument.
 When the function in my second DLL attempts to fread() the stream for
 the first time (which causes the allocation of the stream buffer), a
 General Protect fault (segment violation Trap 13 or 0xD) occurs. What
 went wrong, and how can I work around the problem?

 Response:

 This procedure cannot be done with LLIBCDLL-created DLLs because the
 second DLL has no way to know where the internal C run-time library
 data structures are, which in this case would be the data structures
 for the file stream that was opened in the first DLL.

 To share file streams between DLLs or between an .EXE and DLLs, use
 the dynamically linked, multithread support C run-time function
 CRTLIB.DLL. The correct way to do this is to have one of your DLLs
 export a version of the fread() function and/or fopen() function. The
 fopen() and fread() that get called must be in the same DLL.


 490. Internal Compiler Error: ctypes.c:1.107, Line 474

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50337

 The program below generates the following error when compiled with the
 default command-line options under the Microsoft C optimizing compiler
 Version 5.10:

    intr.c(12) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)ctypes.c:1.107', line 474)
                    Contact Microsoft Technical Support

 The following program demonstrates the internal compiler error:

 #define  interrupt_number = 0x62     /*  any number will do */

 struct interface {
                      int counter;
                      char signature[8];
                  } far interface;

 void far*far*interrupt_vector = ( void far * )0L;

 int main( void )
 {
    /* offending line--invalid */
    interrupt_vector[interrupt_number] = interface;

    /* replace with this line */
 // interrupt_vector[interrupt_number] = &interface;
 }

 The program is not syntactically valid: the offending line attempts to
 assign a structure (rather than a pointer to the structure) to a void
 function pointer.

 Modifying the offending line of code to a pointer rather than a
 structure [i.e., using the "address of" operator ("&") on the
 interface structure] eliminates the internal compiler error and makes
 the program correct.


 491. C and Pascal Mixed Language: Declare C Libraries First

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_PASCAL S_LINK
 Last Modified: 30-NOV-1989    ArticleIdent: Q50703

 When doing mixed language programming with C Version 5.10 and Pascal
 Version 4.00, be sure to use the /NOD and /NOE linker switches, and
 then specifically link with the C libraries before the Pascal
 libraries. This will prevent the linker from finding multiply defined
 symbols.

 The linker will often report error L2025 when linking with the Pascal
 library first, depending on what functions are called from C. The
 printf() function is one example of a run-time function that will
 cause this problem. The problem occurs because some of the low-level
 routines involved in both libraries have the same name.

 The following example typifies the problems encountered:

 For instance, say that the Pascal library contains an object module
 with a routine called A, and the C library contains an object module
 with routine A as well as routine B.

 Furthermore, suppose the Pascal code makes a call to the A library
 routine and the C code makes a call to the B library routine.

 If the Pascal libraries are linked first, the A .OBJ will be found in
 the Pascal library, then the A and B .OBJ will be brought in from the
 C library to resolve the call to B. This results in the linker
 receiving two copies of routine A, which causes the error. By linking
 the C library first, only the one object module (with both A and B)
 will be found, and the symbol will not be multiply defined.


 492. Preprocessor Condenses Multi-Line Macro Invocations

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50341

 The preprocessor of the Microsoft C Optimizing Compiler versions 5.00
 and 5.10 does not preserve the source code structure of macro
 invocations upon expansion. Preprocessor macro expansion is carried
 out on one line at a time, in a left to right fashion, until the
 end-of-line is reached. Thus, when multiple-line macro invocations are
 expanded, they are converted into a single line of code.

 The following example defines a simple macro and displays this
 conversion of multi-line macro invocations:

 #define macro( arg1, arg2, arg3 ) arg1 + arg2 + arg3

      Source Code           Preprocessor Listing
     _____________          ____________________

   value = macro ( param1,  value = macro( param1 + param2 + param3 );
                   param2,
                   param3 );

 Note that the preprocessor listing replaces the three lines of code
 in the source file with only one line. As a result, the line numbers
 between the two files are different because the preprocessor does not
 perform any line number adjustment.

 This may cause problems if one must compile preprocessor listings to
 avoid errors generated by .C source files (i.e., insufficient heap
 space). When the preprocessor listing is compiled, the subtle side
 effect becomes more obvious in the form of discrepancies between
 original source-code line numbers and line numbers associated with
 compiler errors or debugger maps. This result can make debugging
 original source code difficult and can be a general nuisance when
 trying to locate erroneous lines in source code indicated by the
 compiler.

 The #line directive and the __LINE__ predefined macro can be used to
 redefine preprocessor listing line numbers and eliminate such
 differences. To compensate for the preprocessor single-line expansion
 of macro invocations, place the directive "#line __LINE__" in the
 source code line following the macro invocation.

 The #line directive, which accepts an integer constant as an argument,
 instructs the preprocessor to change the compiler's internally stored
 line number to the integer argument specified. The __LINE__ macro,
 which is supplied as the argument to the #line directive, evaluates to
 the current line number generated during preprocessing. Working
 together, they force the compiler to generate consistent line numbers
 between the the source file and the preprocessor listing.

 The program below illustrates the macro expansion behavior of the C
 preprocessor and how it can be modified to generate
 line-number-compatible source and preprocessor listings.

           /* TEST.C */           |          /* TEST.I */
                                  |
 /*1*/  #define sum( a,b,c) a+b+c | /*1*/  #define sum(a,b,c) a+b+c
 /*2*/                            | /*2*/
 /*3*/  void main( void )         | /*3*/    void main( void )
 /*4*/  {                         | /*4*/    {
 /*5*/     int i;                 | /*5*/   int i;
 /*6*/     i =  sum( 1,           | /*6*/   i =  sum( 1, 2, 3 );
 /*7*/           2,               | /*7*/   /*  #line __LINE__    */
 /*8*/           3 );             | /*8*/   i = 100000;
 /*9*/     /*  #line __LINE__  */ | /*9*/    }
 /*10*/    i = 100000;            | /*10*/
 /*11*/ }                         | /*11*/
                                  |

 When the program, TEST.C, above is compiled under warning level three,
 a data conversion warning is generated for line 10, indicating
 overflow of the integer variable i. TEST.C is then run through the
 preprocessor using the /P compiler option, where TEST.I (above) is
 generated. Compiling TEST.I under warning level three generates the
 same data conversion warning, but on line 8. The line number
 difference between TEST.C and TEST.I is quite obvious.

 By uncommenting line 9 in the TEST.C, both the source file and
 preprocessor listing contain consistent line numbers following the
 macro invocation because the line number is reset to the proper value
 (seven) after the preprocessor pass.


 493. mktemp() Creates a Maximum of 27 Unique Filenames

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC docerr
 Last Modified: 30-NOV-1989    ArticleIdent: Q50351

 It is unclear in the documentation for the mktemp() function in the
 Version 5.10 "Microsoft C Optimizing Compiler for the MS-DOS Operating
 System Run-Time Library Reference" (Page 432) exactly how many
 filenames mktemp() creates. The reference states the following:

    When creating new names, mktemp uses, in order, "0" and the
    lowercase letters "a" to "z".

 This is correct; however, the documentation fails to mention that
 these are the only filenames that are created. Any further calls to
 mktemp (after "z" has already been placed in the template) fail.
 Therefore, this limits the number of unique filenames to 27.


 494. Compiling isatty() Sample Program Gives C2146: Syntax Error

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | DOCERR
 Last Modified: 30-NOV-1989    ArticleIdent: Q50704

 On Page 376 of the "Microsoft C Run-Time Library Reference" for C
 Versions 5.00 and 5.10, the sample program for the function isatty()
 will generate a syntax error when compiled. The zero in the printf()
 statement should be changed to a double quotation mark (i.e., %s0
 should be %s"). The following is the printf() statement with the
 correct syntax:

    printf ("Is stdout redirected? %s", interactive ? "no" : "yes");


 495. Run-Time Routines Assume That Direction Flag Is Clear in C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | DOCERR S_QUICKC S_QUICKASM
 Last Modified: 30-NOV-1989    ArticleIdent: Q50712

 The C run-time routines assume that the direction flag is cleared. If
 you are using other functions with the C run-time functions, you must
 ensure that the other functions leave the direction flag alone or
 restore it to its original condition. Expecting the direction flag to
 be clear upon entry makes the run-time code faster and more efficient.

 The run-time functions that use the direction flag include the string
 manipulation and buffer manipulation routines.

 This is documented on Page 365 of the "Microsoft Macro Assembler
 Programmer's Guide," Versions 5.00 and 5.10:

    Under DOS, the direction flag will normally be cleared
    if your program has not changed it.

 This information is not included in the C 5.10 or QuickC 2.00 or 2.01
 manuals.


 496. R6009 Not Enough Space for Environment -- Possible Workarounds

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm s_quickc
 Last Modified: 21-FEB-1990    ArticleIdent: Q50714

 The "Not Enough Space For Environment" error is caused when a program
 successfully loads into memory and then attempts to load a copy of the
 environment and the argument list into the near heap. If the near heap
 does not have enough room for one or the other, or both, R6009 is
 generated.

 In standard Microsoft C programs, the functions _setargv and _setenvp
 attempt to set up the argument vector and the environment vector,
 respectively. Both of these vectors are allocated in the near heap. If
 the program has a full or nearly full near heap, the vectors will not
 be set up, thereby giving the error.

 A few ways to get around the problem are as follows:

 1. Lower the amount of environment space, with the following statement
    in the CONFIG.SYS file. This assumes that environment space is
    being allocated.

       shell=command.com /p /e:xxxx

 2. Use the large memory model when compiling in conjunction with the
    /Gt switch to get some of the global data out of DGROUP, thus
    freeing up room for the environment and/or the argument list.

 3. If there is no need for command line arguments, _setargv can be
    rewritten as follows:

       _setargv() {}

 4. If there is no need for a copy of the environment, and if the
    spawn or exec function is not needed, _setenvp can be rewritten
    as follows:

       _setenvp() {}

 For more information on workarounds 3 and 4, see Section 5.2.2,
 "Suppressing Command Line Processing," in the C user's guide.


 497. No Compiler Errors Produced When Assigning to Missing struct

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50732

 Code that assigns a value to a nonexistent structure compiles without
 warning or error in Microsoft C 5.10 and QuickC Versions 2.00 and
 2.01. This is correct behavior.

 Note that dereferencing a pointer to an undefined structure, or
 attempting to use a field will produce errors. In general, you are
 allowed to make a reference to an undefined struct as long as the
 operation doesn't have to know the size of that struct or the names of
 its fields. This method of declaration is commonly used in linked
 lists.

 void main (void)
 {
    struct non_existant *ptr;             // legal
    struct x{
             struct x *previous;          // legal, note that struct x is
             struct x *next;              // not yet defined
            }
                 .
                 .
                 .
                 .
 }


 498. Huge Indirection May not Cross Segment Boundaries

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-NOV-1989    ArticleIdent: Q50733

 Microsoft C will never generate an array element that spans a segment
 boundary. If a customer generates a scenario where this situation
 occurs, Microsoft C will generate incorrect addresses for the element
 that crosses the segment boundary. Placing elements such that they
 could cross a segment boundary is an incorrect coding technique, not a
 problem with Microsoft C and huge pointer addressing.

 For instance, if a huge character buffer has been allocated and
 structure data has been copied to this buffer, it is possible to
 access this data in structure format by first setting a huge pointer
 to the address of the structure you want and then specifying the huge
 pointer followed by the structure pointer operator (->) and the name
 of element you want to access.

 However, if the structure you are looking at crosses a segment
 boundary, then the indirection will fail. If the element of the
 structure you are referencing is in another segment, your pointer will
 usually end up offsetting by the correct number of bytes, but in the
 current segment and not the next segment.

 Code Example
 ------------

 char huge buffer[70000];                /* Any huge buffer larger than 64K */
 struct x { int x,y,z; };                /* Any structure */

 /* Assume that buffer has been filled with many structures of type x.
    Since the structures were put into the buffer via byte copy, it
    is very likely that one of the structures will cross over the segment
    boundary. */

 struct x huge *test_ptr;                /* A huge pointer to x */

 test_ptr = (struct x huge *)(buffer+( 65536 - sizeof(struct x) ) );

 /* test_ptr is now equal to some offset into huge character buffer.
    It is assumed that the user has given test_ptr a legitimate address
    of a structure that is contained in the buffer in an attempt to access
    that structure. */

 test_ptr->z = 5;

 /* The line above will create an incorrect address for the element z if
    z is in a segment other than the one specified by the huge pointer.
    This address will probably end up as the correct offset but in the
    same segment because, although the pointer is huge, it still will not
    compute the segment when used with indirection. This is also why
    huge structure arrays are padded and why huge arrays larger than
    128K must have elements whose size is a power of two. */

 Note: This problem can avoided by simply creating a huge array of
 structures instead of characters. The compiler will take care of
 padding the array so that an array element (a structure) will not
 cross a segment boundary.

 This would seem to be a bug in the compiler since the huge pointer
 cannot access data beyond a segment boundary. The situation where an
 array element crosses a segment boundary would never be generated by
 Microsoft C, however. Accordingly, the huge pointer arithmetic does
 not account for such a situation. This is not a bug in the compiler,
 but an error in the code.


 499. Graphics Mode: Getting More Than One Background Color

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER| | S_QuickC S_QuickASM
 Last Modified: 17-JUL-1990    ArticleIdent: Q50411
 It is not possible to display more than one background color on the
 screen when working in graphics mode. However, it is possible to
 present the illusion of creating different background colors for
 various windows overlaid on top of the current background color. Use
 _rectangle and _floodfill to create the windows, and either _outtext
 or _outgtext to output the text. A common application is the creation
 of a screen similar to the following:

 |-----------------------------------------------------------------|
 |                                                                 |
 |                                   Light Blue Background         |
 |                                                                 |
 |                |------------------------|                       |
 |                |                        |                       |
 |                |    Dark Blue           |                       |
 |                |    Background          |                       |
 |                |                        |                       |
 |                |------------------------|                       |
 |                                                                 |
 |                                                                 |
 |-----------------------------------------------------------------|

 This is not difficult. The primary problem is getting around the fact
 that, when using _outtext, the text always outputs on blocks of the
 current background color. The result of this is that inside of your
 dark blue window, you will have text surrounded by borders of light
 blue (not very attractive!). To work around this, you can rely on the
 fact that _floodfill() uses the foreground color as its boundary, and
 not the background color. Therefore, you can set the background and
 foreground color equal to the color of the inner window (Dark Blue
 above), and draw a rectangle with _GFILLINTERIOR to the size of the
 window you desire. Then, change the foreground color with _setcolor().
 Next, you can use _floodfill() from point (0,0) with the boundary
 color set to the same color index as the rectangle. After this, you
 can use _settextcolor() and _outtext to put text in the inner window
 without problem. An sample program, WINDOW.C, can be found in the
 "More Information:" section of this article.

 An easier alternative is to use QuickC's fonts. _outgtext does not
 reset the character background to the current background color.
 Instead, it draws the character over any existing images already on
 the screen. Therefore, all that is necessary is to create a filled
 rectangle of the desired size, register and set the desired font, and
 output text to that area of the screen by using _outgtext. An sample
 program, FONTS.C, can be found in the "More Information:" section of
 this article.

 -----------------------------------------------------------------------
 /* WINDOW.C: A sample program that illustrates changing the          */
 /* color for a window using _outtext, _floodfill, and _rectangle.    */

 #include <graph.h>                     /* for the graphics functions */
 #include <conio.h>                     /* for getch()                */

 void main(void)
 {
 _setvideomode(_ERESCOLOR);              /* set to graphics mode      */
 _setbkcolor(_BLUE);                     /* change background color   */
 _setcolor(1);                           /* set drawing color         */
 _settextcolor(3);                       /* set text color            */
 _rectangle(_GFILLINTERIOR,100,100,540,250); /* draw a window         */
 _setcolor(9);                           /* change color for fill     */
 _floodfill(0, 0, 1);                    /* fill in the background    */
 _settextposition(12, 35);               /* coordinates inside square */
 _outtext("scribble");                   /* output text inside square */
 getch();                                /* wait for a key hit        */
 _setvideomode(_DEFAULTMODE);            /* reset the video mode      */
 }

 /*--------------------------------------------------------------------*/
 /* FONTS.C : a slight modification to the "fonts.c" program from the  */
 /* QuickC 2.00 online help system, which outputs the fonted text onto */
 /* a "window" of a different color, easily producing the effect of    */
 /* a secondary, window-area-only background color.                    */

 #include <conio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <graph.h>

 #define NFONTS 6

 unsigned char *face[NFONTS] =
 {
     "Courier", "Helvetica", "Times Roman", "Modern", "Script", "Roman"
 };
 unsigned char *options[NFONTS] =
 {
      "courier", "helv", "tms rmn", "modern", "script", "roman"
 };

 main ()
 {
           unsigned char list[20];
           char fondir[_MAX_PATH]="d:\qc2\bin";  /* modify path!!!!!   */
           struct videoconfig vc;
           struct _fontinfo fi;
           short fontnum, x, y, mode = _VRES16COLOR;

           /* Read header info from all .FON files in given directory. */
           if( _registerfonts( fondir ) <= 0 )
           {
           _outtext( "Error: can't register fonts" );
           exit( 1 );
           }

      /* Set highest available graphics mode and get configuration. */
      while( !_setvideomode( mode ) )
        mode--;
        if( mode == _TEXTMONO)
          exit( 1 );
          _getvideoconfig( &vc );

      /* Display each font name centered on screen. */
      for( fontnum = 0; fontnum < NFONTS; fontnum++ )
          {
      /* Build options string. */
      strcat( strcat( strcpy( list, "t'" ), options[fontnum] ), "'");
      strcat( list, "h30w24b" );

      _clearscreen( _GCLEARSCREEN );
      if( !_setfont( list ) )
      {
      /* Use length of text and height of font to center text. */
      x = (vc.numxpixels / 2) - (_getgtextextent( face[fontnum] ) / 2);
        if( _getfontinfo( &fi ) )
          {
            _outtext( "Error: Can't get font information" );
            break;
           }
      y = (vc.numypixels / 2) - (fi.ascent / 2);
      _moveto( x, y );
        if( vc.numcolors > 2 )
       /* set up the background window & fill before text output   */
         _setcolor( fontnum + 2);            /* set window color   */
         _rectangle(_GFILLINTERIOR,100, 100, 540, 250);
         _setcolor(fontnum+1);               /* set color for text */
         _outgtext( face[fontnum] );         /* output fonted text */
         getch();
         }
         else
         _outtext( "Error: Can't set font" );
         }
         _unregisterfonts();           /* free up memory used by fonts*/
         exit( !_setvideomode( _DEFAULTMODE ) );
 }


 500. With /CP:1, _memavl() Still Shows Memory Available

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_LINK
 Last Modified: 30-NOV-1989    ArticleIdent: Q50472

 Using the /CP:1 (/CPARMAXALLOC - set maximum memory allocation) link
 option does not always leave 1 byte available for allocation in the
 near heap allocation. This becomes apparent when making a call to
 _memavl().

 Code Example
 ------------

 /* test.c */

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

 void main(void)
 {
      /* _amblksiz=1; */
      /* The above line uncommented will cause only a couple
         bytes to become available (see More Information:). */
      printf("Available memory in near heap = %d\n",
             _memavl());
 }

 /* The following options were used to create the program:

    cl /c test.c
    link /CP:1 test

    This program will show approximately 4K available when
 executed. */

 What happens is that _memavl() itself is causing the near heap to
 grow. The library functions _memavl, _freect, and _memmax all require
 the heap to be initialized for them to work. If the heap is not
 initialized then a malloc(0) call is made. The malloc call causes
 DGROUP to grow to the next _amblksiz boundary (8K by default). This
 usually does not cause a problem because malloc is usually called
 either before or after the _memavl.

 To reduce the amount of memory taken by DGROUP initialization, set
 _amblksiz to some smaller amount in order for malloc(0) to grab only
 as much it absolutely needs.


 501. GRAPHICS.LIB Not Supported in C for OS/2

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 30-NOV-1989    ArticleIdent: Q50474

 GRAPHICS.LIB is a real-mode library and its use in a protected mode
 application leads to a general protection fault or a protection
 violation.


 502. BX Register Is Popped Twice for a C Interrupt Function

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickAsm 2.00 2.01
 Last Modified: 21-MAR-1990    ArticleIdent: Q50518

 The interrupt keyword is used to designate specific C functions as
 interrupt service routines and instructs the compiler to generate
 appropriate entry and exit instructions.

 If you compile code with the /G1 or /G2 options (80186 or 80286 code
 generation) then the compiler produces pusha and popa instructions
 that save and restore all vital registers.

 However, if you compile with the default /G0 (8086 code generation)
 then the registers are each explicitly pushed and popped. One
 difference in this code, which may at first appear to be a bug, is
 that the BX register is popped twice, but the SP register is not
 popped at all.

 This is not a problem. The SP register is saved in the following
 instruction sequence:

    mov     bp, sp
    .
    .       ISR code
    .
    mov     sp, bp

 The peculiar double popping of BX can be explained by the following:

    The registers are pushed AX, CX, DX, BX, SP, BP, SI, DI, DS, ES
    (left to right)

    The registers are popped AX, CX, DX, BX, BX, BP, SI, DI, DS, ES
    (right to left)

 Notice that ES receives the old ES; DS the old DS, but BX receives the
 old SP, then BX receives the old BX.

 The first pop of SP to BX is necessary to remove the previous value of
 SP from the stack. The second pop of BX is necessary to restore the
 old BX value.

 The old value of SP was restored in the "MOV  SP,BP" instruction,
 which immediately proceeds the popping of all the registers.

 This ensures that the state of the registers are saved and then
 restored in the Interrupt Service Routine.


 503. Loader Uses Return Value from a DLL's Initialization Routine

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 21-MAR-1990    ArticleIdent: Q50519

 Question:

 How is the return value from a DLL's initialization routine used?

 Response:

 The return value from a DLL's initialization is used by the loader.

 Using an initialization routine for your DLL is optional. The
 initialization routine can be global or instance. The initialization
 routine is called when the DLL is loaded. [This is not necessarily the
 same time as when a DLL-exported function is called. For example, if
 you load the DLL using DosLoadModule() and DosGetProcAddr(), the
 initialization routine is run and the return value is examined at that
 time.]

 Every time you run a program that uses DLLs, the loader goes through
 the import list in the exehdr and attempts to load all the DLLs. As it
 tries to load each DLL, it runs its initialization routine (depending
 on whether the init routine is instance or global). If the
 initialization routine fails (even if the DLL is found) the system may
 display a message, or simply terminate at that point.

 Initialization routines are mentioned in Ray Duncan's book, "Advanced
 OS/2 Programming," in Chapter 19, "Dynamic Link Libraries," Pages
 459-469.


 504. Floating-Point Initialization Occurs at Link Time

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 21-MAR-1990    ArticleIdent: Q50523

 Floating-point initialization occurs at link time. If the compiler has
 generated any floating-point instructions, it lists an external
 symbol. When the linker sees the external symbol, it brings in the
 necessary segment.

 In C 5.10, the external symbol is __fltused. The linker brings in a
 module that has a common CDATA segment that defines the correct values
 of fpmath, fpdata, and fpsignal. If this module is not brought in, the
 CDATA segment defaults to all zeros. This is why CDATA is defined as
 common and not public.

 This process causes the floating-point support to be linked only if
 floating point is used.


 505. C Run-Time Routines Cannot Be Placed in an Overlay

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 30-NOV-1989    ArticleIdent: Q50524

 Problem:

 I want to extract a routine from the C Run-Time Library and put it in
 an overlay. The program compiles and links without warnings or errors,
 but when I run the program, my machine hangs.

 Response:

 The run-time routines for medium and large models (the only ones that
 overlays deal with) are compiled with /NT _TEXT. This puts all the
 routines in the same named segment. The linker cannot split a segment
 between the root and overlay. Segmentation takes precedence over
 overlays. The linker constructs overlays from segments, not individual
 functions.

 The first request for the segment (in an .OBJ that goes in root or in
 an overlay) determines where the linker will place the entire segment
 (root or overlay). If your extracted .OBJ is in the overlay, all the
 run time gets put into the overlay.

 Consequently, the entry point of the overlay manager is put into the
 overlay and not in the root, so the overlay manager code (also in
 _TEXT) is not present in memory at start up. This causes the machine
 to hang.


 506. Calling C Run-Time from a Single-Threaded DLL Init Routine

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50759

 You can call the C run-time routines from within your initialization
 code for a single threaded dynamic link library (DLL).

 To accomplish this, you must ensure that the C run time itself is
 initialized prior to any run-time function call. This is easiest to do
 if you write your base initialization in assembly (as required), but
 then call a routine written in C that will perform the majority of
 your init code. This C routine must be declared as a extrn, far call
 in your assembly code, and defined/prototyped as such in your C init
 code.

 The following is a code example:

 extrn   MYINIT: far                 in the assembly init module.
 int far pascal MYINIT (...) ;       in the C init module.

 Once you have satisfied these items, you must then call C_INIT() from
 within your C init module. This must be done before any C run-time
 calls have been made. The C_INIT routine must also be prototyped as
 follows:

    int far pascal C_INIT (void) ;

 Note: This information applies to single-threaded DLLs only. You
 cannot call the C run time from the init code of a multi-threaded DLL.

 The example below details the steps necessary to call any C run-time
 routine from within your single-threaded DLL initialization code.

 This example involves the following files:

    PROJ.C          Source to the EXE that calls the DLL routine
    PROJ.LIB        Library created by IMPLIB (based on DLL.DEF)
                    [resolves the exported routine(s) from DLL.DLL]
    DLL.C           Source to the DLL, and the function FOOPER()
    DLL.DEF         Definitions file for the DLL
    ASMINIT.ASM     Assembly Init code
    CINIT.C         C Init code

 The source files to the .EXE and .DLL are standard for this type of
 programming.

 The initialization routines and their requirements are discussed
 below:

 ASMINIT.ASM
 -----------

      .model large
      extrn  MYINIT:far        ; Declare the C init routine as far.
      .code
      INIT    proc    far      ; Declare init proc....

              call    MYINIT   ; Call my C init code..
              ret              ; MYINIT exit code is in AX, so return.

      INIT    endp
              end     INIT     ; <--Specifies Entry Point for Init
                               ;    routine (reason why this must be
                               ;    in assembly).

 CINIT.C
 -------

 #include <stdio.h>

      // Prototype C Run-Time init function, and my C init code...
      int far pascal C_INIT (void) ;
      int far pascal MYINIT (void) ;

      int far pascal MYINIT (void)
      {
        int RetVal ;

        // Call the C Run-Time Initialization code..
        RetVal = C_INIT () ;

        // Calls to the C Run-Time are now valid...
        printf ("Hello from the DLL init code...\n") ;

        // other C Run-Time calls can be made here...

        // exit with return value from this initialization code...
        return (RetVal) ;
      }

 The source to the remaining files are listed below:

 PROJ.C
 ------

 #include <stdio.h>

 void far pascal FOOPER (int, int) ;
 void main (void)
 {
   printf ("Hello from Main().  Calling DLL routine...\n") ;
   FOOPER (1, 2) ;
   printf ("\nDone.\n") ;
 }

 DLL.C
 -----

 #include <stdio.h>

 void far pascal FOOPER (int, int) ;
 void far pascal FOOPER (int x, int y)
 {
   printf ("Hello from DLL routine 'Fooper'.\n") ;
 }

 DLL.DEF
 -------

 LIBRARY     DLL  INITINSTANCE
 DESCRIPTION 'single threaded DLL showing C Run-Time in Init Code'
 DATA        MULTIPLE
 EXPORTS     FOOPER

 These files must be compiled and linked together as follows:

   cl   /Alfu /G2s /c dll.c
   masm /mx asminit.asm;
   cl   /Od /AL /G2 /c cinit.c

   link /CO dll asminit cinit,dll.dll/NOI,, \
            llibcdll.lib doscalls.lib, dll.def;
   copy dll.dll  c:\os2\dll

   cl      /AS /G2 /c proj.c
   implib  proj.lib  dll.def

   link /CO proj.obj, /NOI,, slibcep.lib proj.lib doscalls.lib/NOD ;


 507. Why After Edit, fopen with Mode "a" Doesn't Appear to Append

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 30-NOV-1989    ArticleIdent: Q50793

 Problem:

 If I use edlin or Wordstar to edit a file, then call the fopen
 routine with the "a" option and append to the file, the appended
 text doesn't show up when I type the file.

 Response:

 Edlin and Wordstar are examples of editors that place a CTRL+Z
 character at the end of the file. Opening a file with the "a" option
 writes to the file beginning after the last character in the file (in
 this case, the CTRL+Z). If you then edit the file again with the same
 editor, the editor ignores all characters after the CTRL+Z.

 The DOS TYPE command will display all characters up to the first EOF.
 However, if you bring the file up in the M editor or Word, which
 display the CTRL+Z character as a normal character, you can see the
 appended text and, if you want, delete the CTRL+Z character.

 If you fopen a file with the "a+" mode, the CTRL+Z character is
 deleted at the end of the file, and appended text can be seen in any
 editor or by using the DOS TYPE command.

 The following code demonstrates this behavior:

 #include <stdio.h>
 #include <time.h>

 void main(void)
 {
      FILE *fp;
      int num;
      time_t system_time;

      fp = fopen("out.dat","a");          /* change to "a+" to fix */
      time(&system_time);                 /* to demonstrate last append */
      num = fprintf(fp, "Writing to file at %s\n",
                          ctime(&system_time));
      num = fclose(fp);
 }

 Run this program once to write the current system time to the output
 file. Then edlin "out.dat". You do not need to add any lines, just
 open the file and then end the session. Then run the program again.
 Type "out.dat", and notice that you still see only the first output
 time.

 Changing the fopen "a" to "a+" and rebuilding the program will
 demonstrate the solution.


 508. Time and Date Are Written When File Is Flushed

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 30-NOV-1989    ArticleIdent: Q51123

 Changing the time and date of a file with _dos_setftime may appear to
 fail if the file is opened for write and all data has not been written
 to disk. The DOS and OS/2 update file dates whenever a file gets
 modified. Therefore, changing a file date before the operating system
 has written all data to the physical disk may appear to be ignored.
 This is because the date is changed again when the file is closed or
 flushed if there is data still to be written.

 For example, the following program will try and modify the date and
 time of the output file to 6-1-89 10:00. Because the file has not been
 flushed or closed, it is likely that there is still data in the file
 buffer waiting to be written to disk. When the file is closed, the
 program will flush all remaining data to the disk, changing the date
 and time to the current date and time in the process.

 void main(void)
 {
   FILE *fp;
   fp = fopen( "outfile.txt", "wt" );
   fprintf( fp, "Start of file\n" );
   fprintf( fp, "End of file\n" );
   _dos_setftime( fileno( fp ), 0x12c1, 0x5000)  //  10:00  6-1-89
   fclose(fp);
 }

 One way to get around this feature of the operating system is to put a
 flush statement before the call to _dos_setftime. This ensures that
 all remaining data has been written to disk before the date is changed
 and the file is closed. The following program changes the date to
 6-1-89 10:00 successfully.

 void main(void)
 {
   FILE *fp;
   fp = fopen( "outfile.txt", "wt" );
   fprintf( fp, "Start of file\n" );
   fprintf( fp, "End of file\n" );
   fflush(fp);     //       <---- flush the data to disk
   _dos_setftime( fileno( fp ), 0x12c1, 0x5000)  //  10:00  6-1-89
   fclose(fp);
 }


 509. Formal Parameters Default to Type int

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 30-NOV-1989    ArticleIdent: Q51198

 Question:

 Why doesn't the compiler generate an error for the following code?

    void main (voida)
    {
    }

 The variable "voida" is not referenced.

 Response:

 The C and QuickC compilers don't generate an error because the
 variable "voida" defaults to a variable of type int. The compilers
 understand the above function definition since they recognize the "old
 style" of ANSI C declarations as well as the new. In general, the
 equivalents of the above code are as follows:

    Old Style                           New Style
    ---------                           ---------

    void function (voida)               void function (int voida)
    int voida  <- default if missing    {
    {                                   }
    }

 Please refer to "The C Programming Language" by Brian Kernighan and
 Dennis Ritchie for a discussion on differences between old and new
 style with regards to function definition.


 510. C 5.00 and C 5.10 Compiler Exit Codes

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_EDITOR
 Last Modified: 30-NOV-1989    ArticleIdent: Q51297

 The return codes from the compiler are documented in the "Microsoft C
 Optimizing Compiler User's Guide," Appendix A.3. They are as follows:

    Code       Meaning
    ----       -------
    0          No fatal error
    2          Program error (such as compiler error
    4          System level error (such as out of disk
                  space or compiler internal error)

 The compiler returns the same exit codes when you run it from inside
 the Microsoft Editor Version 1.00.


 511. tmpfile() Creates Temporary File in the Root Directory

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC Novell docsup
 Last Modified: 30-NOV-1989    ArticleIdent: Q51326

 The Microsoft C Version 5.10 run-time library function tmpfile()
 creates a temporary file in the root directory of the current drive.
 This file has read/write access and is automatically deleted when the
 file is closed.

 The documentation for this function implies that the file will be
 created in the current working directory. This is not the case; the
 file will exist only in the root directory. To create a temporary file
 in a different directory, use the functions tmpname() or tempname() in
 conjunction with fopen().

 Some obscure side effects can occur on some systems as a result of
 tmpfile() creating a file in the root directory. On a network, you
 must have read/write privileges for the root directory of your current
 drive. Without these rights, tmpfile() will fail to open the temporary
 file, returning a NULL in the process.

 Another possible reason tmpfile() might fail is if the root directory
 is full. DOS only allows a limited amount of file entries in the root
 directory depending on the disk format; therefore, if the root is
 full, you must delete some files before you use tmpfile().


 512. strtok(): C Function -- Documentation Supplement

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC docsup
 Last Modified: 30-NOV-1989    ArticleIdent: Q51327

 The strtok() function takes two strings as arguments. The first is a
 series of zero or more tokens separated by delimiters defined by the
 second string. The first call to strtok() returns a pointer to the
 first token in the first argument. To get the next token in the
 original string, a call to strtok() must be made with NULL as the
 first argument that tells strtok() to search for the next token in
 the previous token string.

 Keep the following information in mind when using strtok():

 1. strtok() will replace a delimiter in the original string with a
    NULL each time the function is called using the same string, so the
    original string is modified by the use of strtok().

 2. The second argument to strtok() can be changed at any time to a
    different delimiter.

 3. Only single characters are considered to be delimiters.

 On the first call to strtok(), the function searches the string
 argument given as the first parameter for any token delimiter defined
 in the second string argument. Any further call to strtok() with NULL
 as the first argument will return a pointer to the next token in the
 original string. The following sample program from Page 603 of the
 "Microsoft C Run-Time Library Reference" manual for Version 5.10 shows
 how strtok() searches a token string:

 #include <string.h>
 #include <stdio.h>

 char *string = "a string,of ,,tokens";
 char *token;

 void main(void)
 {
         token = strtok(string," ,"); /*there are two delimiters here*/
         while (token != NULL){
                 printf("The token is:  %s\n", token);
                 token = strtok(NULL," ,");
         }
 }

 The output of this program is as follows:

    The token is: a
    The token is: string
    The token is: of
    The token is: tokens

 The following is a sample representation of the area in memory around
 the token pointer during execution of the above program. Note the
 replacement of the delimiter with a NULL character each time a token
 is found:

    -------------------------------------------------------------
    |a |  |s |t |r |i |n |g |, |o |f |  |, |, |t |o |k |e |n |s |
    -------------------------------------------------------------
    This is the original string before the first call to strtok()

    -------------------------------------------------------------
    |a |\0|s |t |r |i |n |g |, |o |f |  |, |, |t |o |k |e |n |s |
    -------------------------------------------------------------
     ^----- token will point here on the first call

    -------------------------------------------------------------
    |a |\0|s |t |r |i |n |g |\0|o |f |  |, |, |t |o |k |e |n |s |
    -------------------------------------------------------------
           ^------ token will point here on the second call

    -------------------------------------------------------------
    |a |\0|s |t |r |i |n |g |\0|o |f |\0|, |, |t |o |k |e |n |s |
    -------------------------------------------------------------
                                ^----- token will point here on
                                       the third call

                                 (etc.)


 513. How to Calculate Available File Handles at Run Time

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 14-MAR-1990    ArticleIdent: Q51434

 The following piece of code allows you to find out how many file
 handles are available at run time for a particular process. The
 function makes use of the predefined pointers _iob and _lastiob, which
 are set to point to the first and the last input/output information
 blocks, respectively. The I/O blocks are examined to determine whether
 they are in use, and a total number of available file handles is
 produced. There is no equivalent C library function currently
 available.

 Note: This is not necessarily an indication of the maximum number of
 physical files that can be opened. The system-wide limit is set in DOS
 by the FILES=?? in the CONFIG.SYS file. In OS/2, it is arbitrarily
 governed by system resources and is modified for each process by
 DosSetMaxFH().

 Code Example
 ------------

 #define FILE struct _iobuf
 #ifndef NO_EXT_KEYS           /* extensions enabled */
     #define _CDECL  cdecl
     #define _NEAR   near
 #else                         /* extensions not enabled */
     #define _CDECL
     #define _NEAR
 #endif                        /* NO_EXT_KEYS */

 #define _IOREAD 0x01          /* Open for read bit */
 #define _IOWRT  0x02          /* Open for write bit */
 #define _IORW   0x80          /* Open for read/write bit */

 FILE                          /* File handle table entry */
 {
     char *_ptr;
     int   _cnt;
     char *_base;
     char  _flag;
     char  _file;
  }_NEAR _CDECL _iob[], /*Set to first I/O block at runtime*/
                _lastiob[];   /* Set to last I/O block */

 /*
    All of the above definitions were taken from the STDIO.H header
    file except for _lastiob[], which is not defined. This information
    was extracted to make the example more clear.
 */

 /*
    The following macro will check the availability of a file handle
    by examining the _flag member of the I/O block
 */

 #define inuse(s) ((s)->_flag & (_IOREAD|_IOWRT|_IORW))

 /*
    The following routine loops through the total number of I/O blocks
    and checks the flags to see if it is used or not. The number of
    unused handles is returned, which can be 1 to the maximum number of
    file handles as set by the operating system or the FILES=xx command
    in the CONFIG.SYS file.
 */

 int Number_Of_Handles(void)
 {
    FILE *stream = _iob;
    int count;

    count = 0;
    do
       if (inuse(stream)) count++;
    while(stream++ < _lastiob);

    return(((_lastiob - _iob)+1)-count);
 }

 void main(void)
 {
    int i;

    i = Number_Of_Handles();
 /* i is now set to the number of available file handles */
 }

 The table of I/O blocks that is being checked here was allocated at
 run time according to the maximum number of file handles allowed per
 process.


 514. Character Parameters May Be Prototyped As Integers

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 14-MAR-1990    ArticleIdent: Q51474

 There are some functions in the run-time library that take character
 values as parameters (i.e., memccpy, memset, etc.) and that are
 prototyped as taking integers. This is not a documentation error and
 your program will work correctly if a character value is passed in the
 place of the integer parameter (automatic casting takes care of this).

 The integer value is specified because when the compiler pushes
 parameters on the stack so that the function being called can use
 them, it always pushes them in word increments. In other words,
 regardless of whether the value is an integer or a character, 2 bytes
 will be pushed on the stack. Therefore, to simplify, the function is
 prototyped as receiving an integer.


 515. Missing Semicolon in Sample Average() Function

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-MAR-1990    ArticleIdent: Q51486

 In the "Microsoft C Run-Time Library Reference," Page 634, there is a
 missing semicolon (;) in the sample function called average(). Add a
 semicolon at the end of the for-loop and the sample program will work
 properly.

 Note: There are two average() functions on Page 634, both need a
 semicolon at the end of the for-loop.


 516. OS/2 1.1 EXE May Fail under 1.2 Due to Small Thread Stack Size

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 20-DEC-1989    ArticleIdent: Q51512

 If a multithread program runs correctly under OS/2 Version 1.10, but
 the identical program fails under OS/2 Version 1.20, the problem may
 be the size of the thread stack. Under OS/2 1.20, a thread has more
 overhead and requires more space. If you maintain the recommended 2K
 minimum stack size for each thread, then you should never run into
 this problem.

 If your program has been running successfully under OS/2 1.10 with a
 thread stack that is smaller than 2K, and the program fails under OS/2
 1.20, then the first thing you should try is a larger thread stack
 size.

 Some of the early examples of multithreaded programming that were
 included in the OS/2 SDK used a thread stack size of 400 bytes. These
 programs run fine on the previous versions of OS/2, but fail with a
 trap 000C under OS/2 1.20. A check of the Intel 80286 documentation
 shows that 000C is a stack overflow problem.

 The exact increase necessary in thread stack size between OS/2 1.10
 and 1.20 was not determined, but increasing the stack to 1000 bytes
 allowed these SDK examples to run without problem. Regardless of the
 actual difference needed, the best thing to do is to maintain the
 minimum of at least a 2K thread stack to prevent problems in general.


 517. The /Gm Switch Really Does Move Constants to _CONST

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-DEC-1989    ArticleIdent: Q51613

 Question:

 I am using the /Gm switch to move near string constants into the
 _CONST segment, but it doesn't seem to work properly. My program is
 shown below:

    char foo[] = "hello";

    void main(void)
    {
    }

 When I examine the map file generated, it tells me that foo is stored
 in _DATA. Why isn't the string constant "hello" being stored in
 _CONST?

 Response:

 The /Gm switch is behaving as it should. In the above case, the string
 constant "hello" is not stored as a constant, it is merely a shorthand
 way of initializing the array foo. For example,

    char foo[] = "hello";

 is equivalent to saying the following:

    char foo[] = {'h','e','l','l','o','\0'};

 The data in the array foo is not a string constant, and therefore,
 should not be moved to the _CONST section with the /Gm switch.

 The following code demonstrates a few string constants:

    #include <stdio.h>

    void main(void)
    {
        char array[] = "This is NOT a string constant.";

        char *foo = "This would be moved out to _CONST with /Gm";
        printf("This string will be moved to _CONST\n");
     }


 518. C4056: Overflow in Constant Arithmetic

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1990    ArticleIdent: Q51615

 The following code, when compiled at warning level 1 or greater,
 causes the Microsoft C 5.10 optimizing compiler to produce warning
 C4056:

    test.c(5) : warning C4056: overflow in constant arithmetic

 This warning occurs because the compiler is reordering the addition of
 the unsigned constants. This practice is no longer allowed according
 to the ANSI standard.

 To work around the problem, perform the arithmetic using long integer
 constants where necessary (use 65535L rather than 65535u, for
 example).

 QuickC Versions 2.00 and 2.01 handle this code correctly because these
 versions conform to more recent releases of the draft ANSI standard.

 The following is the code that produces the error:

    void
    test ( unsigned dummy )
    {
        dummy = 65535u - (dummy - 1);
    }


 519. Recursive CL Setting Can Cause D2002 Command-Line Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-DEC-1989    ArticleIdent: Q51616

 The command-line error D2002 is produced by the Microsoft C 5.10
 optimizing compiler under certain circumstances when the CL
 environment variable is set recursively.

 The following situations cause the error:

    SET CL=CL
    CL -Ax woof.c           where x is M, C, or L

    SET CL=CL -Ax           where x is M, C, or L
    CL -Ay woof.c           where y is S, M, C, or L

 The error is produced even if -Ax is the same as -Ay in the latter
 case.

 D2002 will, of course, also occur when CL is set to a model other than
 the one specified or implied (-AS) on the command line.

 The following is the exact text of the error message:

    Command line error D2002 : a previously defined model
                               specification has been overridden


 520. No Warning When Passing Long to Int Prototyped Function

 Product Version(s): 5.10   | 5.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 21-MAR-1990    ArticleIdent: Q51620

 If you prototype a function to accept an integer, and then pass a long
 integer to the function, Microsoft C Version 5.01 and Microsoft QuickC
 Versions 1.00, 1.01, 2.00, and 2.01 fail to give a warning about the
 data conversion if the value being passed is between -65536 and
 +65535. Instead, the value is converted to a valid integer (between
 -32768 and 32767) and passed to the function, causing unexpected
 results.

 This is also a problem with the Microsoft QuickAssembler Version 2.01.

 The following code demonstrates this problem:

 #include <stdio.h>

 void func(int,int);

 void main(void)
 {
      func(50000L,1L);    /* Can also pass in (long)50000,long(1)     */
 }                        /* and have no warnings.                    */
                          /* Try changing to 100000, notice correct   */
                          /* warning.                                 */
 void func(int a, int b)
 {
      printf("a=%d  b=%d",a,b);
 }

 If you declare two long integers and pass them to func, as in the
 following, you receive a data conversion warning as expected:

    long a=50000,b=1;
    func(a,b);


 521. How to Use the Token Pasting Operator in Microsoft C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC S_QUICKASM 2.00 2.01
 Last Modified: 15-MAR-1990    ArticleIdent: Q51712

 The token pasting operator (##) is used to replace tokens within a
 preprocessor string. The (##) can be used to mark off the first
 portion of the string as a token, the last part of the string as a
 token, or the middle of a string as a portion. See the examples shown
 below.

 The token pasting operator cannot be the first or the last token in a
 preprocessor string (see Page 197 of the "Microsoft C Language
 Reference" manual for Version 5.10). The first example below (GLUE)
 demonstrates the use of the token pasting operator to concatenate two
 tokens. There is a replaceable token in front of the operator and one
 following the operator. The token pasting operator effectively divides
 the string into the two pieces.

 A more complex situation arises when using the token pasting operator
 to replace a token embedded within a string (for example,
 THIS_IS_A_size_TOKEN, where size could be replaced with either large
 or small); the token to be replaced must be surrounded by token
 pasting operators (##). This is necessary only when the token to be
 replaced is completely embedded in another string (see Example 2).
 Normally, the space character is used as one of the token markers,
 while the (##) marks the other end. Only in this specific case (an
 embedded token) is more than one token pasting operator needed.

 For more information, please see the ANSI Draft Proposal for the C
 programming language (Document Number X3J11/88-159, 7 December 1988),
 Page 93, or the "Microsoft C Language Reference" manual for Version
 5.10, Page 197.

 /*
     PASTE.C: Demonstrates the use of the token pasting operator.
 */
 /*
     Example 1 definition.
     This definition will replace the token "a" from the beginning
     of the string and "b" from the tail of the string.
 */

 #define GLUE(a,b) a##b

 /*
    These are the defines for Example 2.
    Calling print with either LARGE or SMALL will then change
    the PRINT macro to call the proper PRINT_..._SIZE macro.
 */
 #define PRINT_LARGE_SIZE(val) printf("The large size is %d\n",val)
 #define PRINT_SMALL_SIZE(val) printf("The small size is %d\n",val)
 #define PRINT(size,val) PRINT_##size##_SIZE(val)

 void main ( void )

 {
     char *varsrc = "Hello!" ;
     char *vardest = "      " ;

 /*
     Example #1: Tokens at beginning and end of string
 */

     strcpy(GLUE(var,dest),GLUE(var,src)) ;
     printf("%s\n", GLUE(var,dest)) ;

 /*
     Example #2: Token embedded in string
 */

     PRINT(LARGE, 2) ; /* Calls the printf() for large sizes. */
     PRINT(SMALL, 1) ; /* Calls the printf() for small sizes. */
 }

 The following is the corresponding .i (preprocessed file). This file
 can be generated by using -P option at compile time (cl -P paste.c).

 void main ( void )

 {
     char *varsrc = "Hello!" ;
     char *vardest = "      " ;

     strcpy(vardest,varsrc) ;
     printf("%s\n", vardest) ;

     printf("The large size is %d\n",2) ;
     printf("The small size is %d\n",1) ;
 }


 522. Clarification of the /H Identifier Length Option

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC docerr
 Last Modified: 15-MAR-1990    ArticleIdent: Q51724

 The /H option is used to set the maximum length of identifiers in
 Microsoft C Version 5.10. Using /H can only decrease the maximum
 allowable length of identifiers, not increase it. An identifier
 declared with the CDECL type has an underscore (_) appended to the
 front at compile time. This character is part of the identifier and
 takes a significant location. Therefore, the maximum length of an
 identifier declared with the standard C declaration syntax is 32
 characters (the compiler limit on Page 280 of the "Microsoft C User's
 Guide" for Version 5.10 specifies 31 characters, which does not
 include the underscore).

 The following example shows how using /H can actually introduce errors
 if identifier lengths are limited to much:

 /* When compiled with /H5, the following code will produce
 the error 'L2025: _func : symbol defined more than once'. */

 void func1(void);
 void func2(void);

 void main(void)
 {
      func1();
 }

 void func1(void)
 {
 }

 void func2(void)
 {
 }

 You must also be careful when using the /H option because of
 predefined compiler identifiers. If the maximum identifier length is
 too small, certain predefined identifiers will be unresolved as well
 as certain library function calls. For example, if the printf function
 is used and the option /H5 is specified at compile time, the symbol
 _prin will be created in order to reference printf, and this will not
 be found in the library.


 523. Manual Correction for MASM Returning Single or Double to BASIC

 Product Version(s): 5.00   | 5.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr B_BasicCom H_MASM B_QuickBas
 Last Modified: 15-MAR-1990    ArticleIdent: Q51728

 The following information is relevant to BASIC programmers who want
 their BASIC programs to correctly invoke assembly language functions
 that return single- or double-precision floating-point values.

 The following two corrections apply to Page 78 of the "Microsoft
 Mixed-Language Programming Guide," which comes with Microsoft C
 Compiler Version 5.00 and with Microsoft Macro Assembler (MASM)
 Version 5.00 (but does not come with BASIC):

 1. In Section 6.1.6, in the second paragraph, the phrase "BASIC or"
    should be deleted.

 2. In the third paragraph, change the phrase "FORTRAN or Pascal"
    to "BASIC, FORTRAN, or Pascal".

 This documentation error was corrected in the "Microsoft
 Mixed-Language Programming Guide" supplied with Versions 5.10 of
 Microsoft C and Microsoft Macro Assembler.

 The first sentence in the second paragraph in Section 6.1.6 on Page 78
 should thus read as follows:

    When the return value is larger than 4 bytes, a procedure called
    by C must allocate space for the return value and then place its
    address in DX:AX.

 The first sentence in the third paragraph in Section 6.1.6 on Page 78
 should thus read as follows:

    If your assembly procedure is called by BASIC, FORTRAN, or Pascal,
    then it must use a special convention in order to return
    floating-point values, records and arrays, and values larger than
    4 bytes.

 For a complete guide for passing parameters and invoking functions
 between BASIC and assembly language, search in the Microsoft Knowledge
 Base for the following word: BAS2MASM.


 524. Clock Function Sets errno

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 16-JAN-1990    ArticleIdent: Q51735

 Question:

 Why does the clock function set errno?

 Response:

 The clock function uses intdos() to read the system date and time.
 When intdos() calls the date/time interrupt, the carry flag is set
 upon return. The intdos() function interprets the carry flag as an
 error and sets errno to the value in AL. In the case of a request for
 the system date, AL (and therefore, errno) contains the day of the
 week.


 525. Spawned Process Runs Out of Environment Space

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 20-DEC-1989    ArticleIdent: Q51742

 Using spawn to create a child process, then attempting to increase the
 environment space of the child (by adding a new environment variable
 or expanding an existing environment variable) results in an "Out of
 Environment Space" error.

 This problem does NOT happen under OS/2.

 The following program(s) illustrates this behavior:

 /*-----------------------------------------------------------------*/
 /*-----------------------------------------------------------------*/
 parent.c  This will call the child process (child) with the spawnlp
           function.
 /*-----------------------------------------------------------------*/

 #include <stdio.h>
 #include <process.h>

 void main (void);

 void main (void)
 {
     printf ("In the parent process\n");

     spawnlp (P_WAIT, "child.exe", "child", NULL);

     printf ("\nAnd back to the parent process.\n");
 }

 /*-----------------------------------------------------------------*/
 child.c Called by parent.c, uses the system function to call a batch
         file (BATCH.BAT) to attempt to set a new environment variable.

 /*-----------------------------------------------------------------*/
 #include <stdio.h>
 #include <process.h>
 #include <conio.h>
 #include <errno.h>

 void main (void);

 void main (void)
 {
     printf ("At child process...\n");
     system ("batch.bat");
     getch ();
 }

 /*-----------------------------------------------------------------*/
 BATCH.BAT  The batch file, which is called by the child process
             (CHILD.EXE). It just shows the environment variables,
             attempts to set another environment variable, then shows
             the environment variables one more time.
 /*-----------------------------------------------------------------*/
 set
 set blah=thisisatestonlyatestsoitdoesnotreallymatter
 set
 /*----------------------------------------------------------------------*/

 Parent will spawn child, which in turn spawns (through system)
 BATCH.BAT. The idea is to show that when BATCH.BAT is called, an "Out
 of Environment Space" error will be given. Yet, if BATCH.BAT is run
 from DOS, no such error is issued.

 To work around this problem, set up a dummy environment variable that
 is large enough to hold the new environment variable you plan to use
 in the spawned process. When the child process is called, you can then
 set the dummy variable to null (with a "set dummy="), then you can set
 your processes environment variable. Please note that this will change
 the dummy environment variable for the child only, not the parent
 process.

 Under DOS, the child will get only enough space to hold the current
 environment variables, while under OS/2, the segment that holds the
 environment can usually be expanded.


 526. spawn Ignores arg0 with DOS 3.00 and Later

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-JAN-1990    ArticleIdent: Q51768

 Question:

 Why is arg0 ignored when I use a spawn command under DOS?

 Response:

 Under DOS Versions 3.00 and later, the first argument (arg0) is used
 to hold the path and name of the program. The third parameter in a
 spawn command is arg0. Regardless of what you specify arg0 to be, DOS
 passes the path and name of the program to the child function. Under
 DOS 2.x, arg0 is not defined.

 Under OS/2, this is not the case; arg0 is passed as specified with the
 spawn command.


 527. Casting Large Double to Float Gives Compile or Run-Time Error

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 10-JAN-1990    ArticleIdent: Q52103

 Casts of double numbers (greater than 3.4E+38) to float numbers can
 cause serious problems at compile time or at run time. Although this
 is expected behavior, it is inconsistent with typical overflow casting
 in that no errors or warnings are produced by the compiler when
 nonfloat overflow casts are made.

 In addition, overflowing a float by casting it to a double constant
 may cause the compiler to generate several lines of random characters.

 Microsoft has confirmed this random character generation to be a
 problem with C Version 5.10. We are researching this problem and will
 post new information as it becomes available.

 If a constant that is greater than 3.4E+38 (the maximum float) is cast
 to a float, the compiler will fail with the following error:

    fatal error C1045: floating point overflow

 The following code sample demonstrates the compile error:

      /* This code when compiled will produce compiler error code
         C1045. */

      void main(void)
      {
           float f;

           f = (float)6e39;
           /* All numbers up to 3.4e38 work fine */
      }

 If a double return value (greater than 3.4E+38) is cast to a float,
 the following run-time error message is displayed:

    run-time error M6104: MATH
    -floating-point error: overflow

 This following code sample demonstrates the run-time error:

      /* This code will compile fine but produces a run-time error
         M6104. */

      #include <stdlib.h>

      void main(void)
      {
          float f;

          f = (float)atof("6e39");
          /* Once again, all numbers up to 3.4e38 work fine */
      }

 On the other hand, the following integer cast overflow demonstrates
 that on a nonfloating point cast overflow, no errors are produced:

      /* The following code produces no compiler errors, warnings
         (even at warning level 3), or run-time errors. */

      #include <stdio.h>

      void main(void)
      {
          int i;

          i = (int)70000;
          /* The signed integer i is overflowed in this case and will
             probably produce unintended results. */
      }

 There is no workaround regarding the casting of double constants to
 floats at compile time other than eliminating the offending cast from
 the code. On the other hand, the problem with the floating point
 overflow error at run time can be caught by using the signal()
 function to trap floating point exceptions. However, both problems can
 be avoided if you ensure that a value greater than 3.4E+38 (maximum
 float value as determined by the IEEE standard for 4 byte floating
 point numbers) is never assigned to a float.


 528. Calling a User-Written Function from an ISR

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1990    ArticleIdent: Q52122

 It is possible to call a user-written function from an Interrupt
 Service Routine (ISR). However, there a few caveats, as shown below:

 1. Do not make any calls to stack checking routines.

 2. Do not assume DS=SS.

 There are other considerations that must be taken into account, such
 as which stack a program is running on, availability of space on the
 stack, etc. Because of these restrictions, there is a limit as to
 which C run-time functions can be used.

 Recommended reading for ISR programming is the "Microsoft Systems
 Journal," September 1988, Volume 3, Number 5. This issue of the MS
 Systems Journal contains an article for writing TSR (terminate and
 stay resident) programs with Microsoft C and covers such issues as
 stack considerations and program size. Also, see the Microsoft "MS-DOS
 Encyclopedia," Article 11, for more information.

 The following code provides a demonstration of an ISR calling a
 user-written function. The code revectors the keyboard interrupt (INT
 9H) and then waits for a hotkey to be pressed. If the hotkey is
 pressed, a message is displayed. Because of the above restrictions,
 the printf() family cannot be used. Therefore, a user-written
 function must be called to write the string.

 Note: The sample program does not go TSR because this would complicate
 the code. If the you want to modify it for TSR usage, please read the
 above articles.

 Sample Code
 -----------

 /* Compile with /Gs /Au */

 #include <dos.h>
 #include <bios.h>

 union REGS inregs, outregs;

 void (interrupt far *oldint9)();

 /* HOTKEY is CTRL+W */

 #define HOTKEY_CODE 0x11
 #define HOTKEY_STAT 0x4
 #define KEYPORT 0x60

 #define DOS_INT 0x21
 #define KEYSVC_INT 0x9
 #define DOS_PRINTSTRING 0x9

 void dos_puts( char *msg);
 void interrupt far newint9(void);

 void dos_puts( char *msg )
 {

    (void) _bios_keybrd( _KEYBRD_READ );

    inregs.h.ah = DOS_PRINTSTRING; /* DOS INT 21 Function 9h is    */
                                   /*    Display String            */

    inregs.x.dx = (int)msg; /* inregs.x.dx gets the segment        */
                            /* value of string to be output to crt */

    intdos( &inregs, &outregs );   /* INT 21 call to output string */
 }

 void interrupt far newint9(void)
 {
    static unsigned char keycode;
    static char active = 0;

    if (active)
       _chain_intr(oldint9);

    keycode = inp(KEYPORT);        /* Check for key at keyboard    */

    if (keycode != HOTKEY_CODE )   /* If key isn't HOTKEY,         */
       _chain_intr(oldint9);       /* pass to old handler          */

    if ( _bios_keybrd(_KEYBRD_SHIFTSTATUS) & HOTKEY_STAT )
    {
       active = 1;
       (*oldint9)();
       dos_puts("HOTKEY was pressed\r\n$");
       active = 0;
    }
    else
       _chain_intr(oldint9);
 }

 void main(void)
 {
    long x;
                                   /* Save old keyboard ISR */
    oldint9 = _dos_getvect( KEYSVC_INT );
                                   /* Set new keyboard ISR */
    _dos_setvect( KEYSVC_INT, newint9 );
                                   /* Loop awhile to let program run */
    for(x=0L; x <= 200000L; x++)
                                   /* Restore old ISR and exit */
       _dos_setvect( KEYSVC_INT, oldint9 );
 }


 529. C 5.1 Run-Time Reference Example for atan2() Is Missing ")"

 Product Version(s): 5.10    | 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-JAN-1990    ArticleIdent: Q57233

 On Page 123 in the "Microsoft C 5.1 Optimizing Compiler Run-Time
 Library Reference," there is a right parenthesis missing in the last
 line of the example program for the atan() and atan2() functions. The
 line should read as follows:

    printf("%.7f\n",atan2(-1.0,1.0));


 530. Workaround for Converting a Float/Double to a String

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 15-JAN-1990    ArticleIdent: Q57244

 Question:

 The gcvt() function returns an exponential number in the string even
 if the number fits in the specified precision when the number is of
 the form 0.0x, where x is any digit(s). Because of this behaviour with
 the gcvt() function, I am unable to convert my floating point number
 to a string in the format that I want. Is there another function I can
 use to convert a floating point number to a string?

 Response:

 Another function that converts a floating point number to a string is
 fcvt(). Unfortunately, it does not do all the conversion for you
 because it leaves out both the decimal point and the sign of the
 number.

 You can also use the sprintf() or printf() functions with the "%lf"
 format specifier to obtain the correct results. However, if you do not
 want to use any printf() constructs, supporting code is needed to
 completely convert the floating point number to a string. The
 following program shows one possible way this can be done, and the
 printf() statements can be replaced by puts() statements:

 Sample Program
 --------------

 #include <stdio.h>
 #include <stdlib.h>
 #include <malloc.h>
 #include <string.h>

 #define PRECISION   8

 char *double_to_char (double) ;

 char *temp2 ;

 void main (void)
 {
         temp2 = (char *) malloc (100) ;
         if (temp2 == NULL)
                 printf ("Hey, it didn't work (the malloc for temp)\n") ;

         temp2 = double_to_char ((double) 0.0004567891) ;
         printf ("temp = %s\n", temp2) ;
         temp2 = gcvt ((double) 0.0004567891, PRECISION, temp2) ;
         printf ("temp = %s\n", temp2) ;

         temp2 = double_to_char ((double) 123.564) ;
         printf ("temp = %s\n", temp2) ;
         temp2 = double_to_char ((double) -43.7864383846738) ;
         printf ("temp = %s", temp2) ;
 }

 /*  Translates a double to an ASCIIZ string
 */

 char *double_to_char (double number)
 {
         char *buffer,
                  *temp ;

         int  decimal_spot,
                  sign,
                  count,
                  current_location = 0 ;

         buffer = (char *) malloc (PRECISION + 3) ;
         temp   = (char *) malloc (PRECISION + 1) ;
         if (buffer == NULL || temp == NULL)
         {
                 printf ("Memory allocating attempt has failed in"
                         "'double_to_char'\n") ;
                 exit (-1) ;
         }

         temp = fcvt (number, PRECISION, &decimal_spot, &sign) ;

 /*      Force the number to be precise to only PRECISION digits, notice
                 that no rounding is done here...
 */
         temp [PRECISION] = '\0' ;

 /*      Is this a negative number ?, if so add a negative sign.
 */
         if (sign)
                 buffer [current_location++] = '-' ;

 /*      Now we need to put the decimal point in the correct place,
                 followed by the rest of the digits.
 */
         if (decimal_spot > 0)
         {
                 strncpy (&buffer [current_location], temp, decimal_spot) ;
                 buffer [decimal_spot + current_location] = '.' ;
                 strcpy (&buffer [decimal_spot + current_location + 1],
                                 &temp [decimal_spot]) ;
         }
         else
         {
                 buffer [current_location] = '.' ;
                 for (count = current_location;
                      count < abs (decimal_spot);
                      count++)
                         buffer [count + 1] = '0' ;
                 strcpy (&buffer [count + 1], temp) ;
         }

         return (buffer) ;
 }


 531. Intel Phone Number for Information About EMS Specifications

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-JAN-1990    ArticleIdent: Q57480

 Question:

 Can I access any memory beyond the base 640K on my machine within DOS?

 Response:

 If you have expanded memory and you have an EMS (Expanded Memory
 Specification) driver that conforms to LIM (Lotus/Intel/Microsoft)
 specifications, you can access memory beyond the base 640K available
 on your machine. For information about accessing this memory, contact
 Intel at (800) 538-3373 or (503) 629-7362.

 Intel will send you EMS specifications and documentation discussing
 writing code that uses EMS specifications, including a reprint of the
 March 1987 Microsoft Systems Journal article, "Expanded Memory:
 Writing Programs That Break the 640K Barrier."


 532. C Can Recognize up to 31 Characters of Any Name

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  9-JAN-1990    ArticleIdent: Q57481

 On Page 83, Section 6.3, Number 3, in the mixed-language guide of
 "Microsoft C 5.1 Optimizing Compiler CodeView and Utilities, Microsoft
 Editor, Mixed-Language Programming Guide," the following is
 incorrectly stated:

    C recognizes only the first eight characters of any name, so
    do not make names shared with C longer than eight characters.

 This statement is not true. C can recognize up to 31 characters.


 533. Displaying Only the Subdirectories with _A_SUBDIR

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1990    ArticleIdent: Q57549

 Question:

 I am using _dos_findfirst and _dos_findnext and using the _A_SUBDIR
 file attribute to find only the subdirectories. But I am getting not
 only the subdirectories, but also the filenames. Is there any way to
 have _dos_findfirst and _dos_findnext return just the subdirectories?

 Response:

 You can use _dos_findfirst and _dos_findnext, and by using _A_SUBDIR
 you can find just the subdirectories. Since the _A_SUBDIR attribute
 returns information about normal files as well as files with the
 subdirectory attribute, you must check each file to determine whether
 or not it is an actual subdirectory or a normal file. The following
 program demonstrates how to display just the subdirectories:

 Code Example
 ------------

 #include <stdio.h>
 #include <dos.h>
 #include <direct.h>

 void display_directory ( struct find_t *find );       /* Prototypes */

 void main( void )
 {
    struct find_t find;
    char buffer[67];

    getcwd (buffer, 66);
    printf ("Current Working Directory: %s\n", buffer);

  /* Find first matching file, then find additional matches. */
    if ( !_dos_findfirst( "*.*", _A_SUBDIR, &find ))
         display_directory ( &find );
    while( !_dos_findnext ( &find ))
         display_directory ( &find );
 }

 /* Displays Subdirectories in Current Directory */

 void display_directory ( struct find_t *pfind )
 {
    /* Determines whether the file is a subdirectory */
     if( pfind->attrib & _A_SUBDIR )
        printf ( "<DIR> %-8s\n", pfind->name );
 }


 534. Float Data Type May Cause Problems in TSR Applications

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 26-FEB-1990    ArticleIdent: Q57586

 The following TSR (terminate and stay resident) interrupt handler does
 not execute properly when invoked. The floating point values produced
 are invalid. If you change the data type "float" to "double", the
 problem disappears.

 Code Example
 ------------

 #include <stdio.h>
 #include <conio.h>
 #include <math.h>
 #include <dos.h>

 void foo (void);
 void interrupt far myint (void);
 void main (void);

 /* Change the next line of code to "double a = 10.0"
    and the problem will go away. */
 float a = (float) 10.0;

 void foo (void)
    {
    cprintf("The sqrt of %lf is %lf.\n\r",(double) a,sqrt((double) a));
    }

 void interrupt far myint (void)
    {
    foo();
    }

 void main (void)
    {
    foo();
    _dos_setvect (0x65, myint);
    _dos_keep (0, 2000);
    }

 The above program is a TSR interrupt handler for INT 65h, which prints
 out the values 10.0 and sqrt(10.0) to the console when invoked. To see
 the problem with the above program, follow these steps:

 1. Compile with the large memory model (/AL), and run.

 2. Invoke interrupt 65h through the DOS DEBUG.EXE utility, as follows:

    a. debug  Press ENTER.

    b. a      Press ENTER.

    c. int 65 Press ENTER.

    d. ret    Press ENTER.

    e. Press ENTER.

    f. g      Press ENTER.

    g. q      Press ENTER.

 The problem disappears if you change the variable "a" from type
 "float" to type "double".


 535. Exemod Shows Min Alloc Greater Than Max Alloc with Link /CP:1

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | cvpack
 Last Modified: 15-JAN-1990    ArticleIdent: Q57607

 Problem:

 Looking at the header of a .EXE file, compiled with C Version 5.10
 with the following

    cl foo.c

 and linked with

    link /CP:1 /E foo;

 EXEMOD shows that the value of the minimum allocation(para) is higher
 than the value for maximum allocation(para).

 The description of EXEMOD implies that this is not possible (Page 323
 of the Microsoft "CodeView and Utilities, Microsoft Editor,
 Mixed-Language Programming Guide" manual, under the description of
 /MAX).

 Response:

 Under normal circumstances, the minimum allocation size cannot be
 larger than the maximum allocation size. However, on Page 324 of the
 Microsoft "CodeView and Utilities, Microsoft Editor, Mixed-Language
 Programming Guide" manual, it states the following:

    If either the /MIN or the /STACK option is used, the value is
    CORRECTED as necessary to accommodate unpacking of the modified
    stack. The /MAX option operates as it would for unpacked files.

 In other words, the minimum allocation value listed in a packed file
 is corrected to allow for the unpacked stack space. Since the maximum
 allocated value does not change for packed files, this COULD result in
 the minimum value being much larger than the maximum value. Note that
 this is the same whether the file is packed using the /E switch with
 LINK, or separately with EXEPACK.


 536. Example of Older FORTRAN Main to Newer C Procedure Call

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | H_FORTRAN 4.00
 Last Modified: 21-JAN-1990    ArticleIdent: Q57652

 When you link a mixed-language program, you must specify the newer
 version of the run-time library before the earlier version library on
 the link line, even if the earlier version of the library belongs to
 the main procedure in a mixed-language call.

 The following code is an example of a mixed-language program that uses
 a FORTRAN main program to call a C procedure to handle the graphics
 for the program. The code is intended to demonstrate correct compile
 and link switches when a FORTRAN routine is compiled with an earlier
 version of the FORTRAN package, which calls a C routine compiled with
 a newer version of the C package.

 The code begins execution in the FORTRAN main, then calls the C
 routine to handle elementary graphics routines. Notice the order of
 libraries specified on the link line.

 C*****************  FORMOD.FOR *****************
 C  FORMOD.FOR - FORTRAN 4.0 module to be used with CGRAPH

        INTERFACE TO SUBROUTINE CGRAPH[C, ALIAS:'_cgraph']
        END

        PROGRAM FORMOD
        CALL CGRAPH
        END

 /******************  CGRAPH.C *****************    */
 /* CGRAPH.C - C Graphics module. Used with FORMOD. */

 #include <stdio.h>
 #include <graph.h>
 #include <conio.h>

 void cgraph(void)
 {
     int i;

     i = _setvideomode(_MRES16COLOR);
     printf("return = %d", i); /* check for failed return */
     getch();
     _setvideomode(_DEFAULTMODE);
 }

 # ****************** FORMOD.MAK ***********************

 formod.obj: formod.for
         fl /Od /Zi /c /AL formod.for

 cgraph.obj: cgraph.c
         cl /Od /Zi /W3 /c /AL cgraph.c

 formod.exe: cgraph.obj formod.obj
         link /CO /NOE /NOD
         formod cgraph,,,llibcer.lib+llibfore.lib+graphics.lib;

 Note: The C graphics calls will fail if the earlier libraries (in this
 case, the FORTRAN libraries) are specified first on the link line.
 This is expected, as you always want newer definitions of the repeated
 code linked into your EXE file.

 For more information about FORTRAN and C mixed-language programming,
 see the "Mixed-Language Programming Guide" in your compiler
 documentation.


 537. Converting PL/M-386 Code to MSC

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-FEB-1990    ArticleIdent: Q57748

 Microsoft does not make any PL/M conversion programs or utilities, nor
 do we know of any products for converting PL/M to C or MASM code that
 are explicitly compatible with Windows development. There are,
 however, several third-party vendor products (seen on a December 1988
 bulletin board).

 Microsoft has not tested these products, and therefore, we make no
 guarantees about them. You may want to contact the respective vendors
 for more information.

    Product: PL/M to C
    Korzeniewski: Frank Korzeniewski Consulting
    1564-A Fitzgeral Dr. #137
    Pinole, CA  94564
    (415) 799-1819

    Product: name not listed
    Lexeme Co.
    Richard Cox
    4 Station Square #250
    Commerce Court
    Pittsburg, PA  15219-1119
    (412) 281-5454

 Another less convenient possibility is to use CodeView (CV) to view
 the assembly code from the PL/M .EXE files. CV may be able to detect
 PUBLIC symbols, such as _main in Microsoft C or Pascal, which would
 allow you to skip start-up code and perhaps to keep track of where you
 are in your code. This will not result in complete or correct
 assembler, but it may ease the conversion process.

 You can use PRINT SCREEN to print the assembly code in 17 line blocks.
 Or you can invoke CodeView in sequential mode (/t), redirect to a
 file, and unassemble (U). For details, query on the following words:

    disassemble and codeview and listing


 538. Return Value for getch() on Extended Characters

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 22-JAN-1990    ArticleIdent: Q57888

 When reading extended characters, you must make two calls to getch()
 because the first call returns a value indicating that the key is an
 extended character. The second call returns the actual key code. This
 is how extended keys are detected.

 When you are reading an extended character, the first return value
 will be either 0xE0 or 0x00, depending on which extended key is
 pressed.

 Sample Program
 --------------

 #include <stdio.h>
 #include <conio.h>
 void main(void)
 {
     int ch, scan;

     do {
         ch = getch();    /* 1st getch() gets ASCII code */
         printf("Character is %d\n", ch);
         if (ch == 0x00 || 0XE0)  { /* if extended key */
             scan = getch();  /* 2nd getch() gets "scan code" */
             printf("\tExtended character:  scan is %d\n", scan);
         }
     }  while (ch != 27);    /* exit loop on ESC */
 }

 For a discussion of keystrokes and scan codes, refer to "The New Peter
 Norton Programmer's Guide to the IBM PC & PS/2," Pages 128 to 130.


 539. File Buffering Can Hide Out-of-Disk-Space Condition

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 22-JAN-1990    ArticleIdent: Q57889

 If disk space is exceeded, file buffering fails when buffering is done
 by the stream I/O functions. For example, if a file buffer for a
 stream is set to 10K by setvbuf() but only 2K disk space is available,
 all data written to the buffer above 2K will be lost. This problem can
 occur even when setvbuf() and fwrite() return successful return codes.

 In the case where there is less space on the disk than there is in the
 stream buffer, all stream I/O functions will seem to work properly
 until the stream buffer is filled [for example, fwrite() returns the
 number of bytes written as if it were successful]. However, the status
 of these functions is valid only for the data going to the buffer and
 is not reflected in the file that is written to the disk.

 The problem is due to the existence of both the C run-time buffers and
 the DOS buffers. Only when the DOS buffers try to write to disk does
 it become evident that the disk is full. Then, the next return value
 from fwrite() will indicate failure.

 The following is the series of events that leads to the loss of data
 with buffered stream I/O functions:

 1. The stream is opened with fopen().

 2. Buffering is set on the stream, either 512 bytes default or the number
    of bytes selected by the user with setvbuf().

 3. There is less disk space than the size of the buffer set by Step 2.

 4. Bytes are written to the file [for example, fwrite()], with
    successful return codes.

 5. The buffer is filled and then the stream I/O function attempts to
    write all data to DOS.

 6. The bytes that can fit on the disk are written and all remaining
    data that was in the buffer is lost.

 7. Successive calls to write data to the file fail.

 The following are possible workarounds:

 1. Turn buffering off by setting the file buffer to NULL, using
    setvbuf().

 2. Use nonbuffered I/O functions, such as open(), read(), and write().

 3. Check the result of closing the stream with fclose(), which flushes
    all buffers associated with the given stream prior to closing.

 4. Set buffering to the same size as the records that are being
    written. The third workaround will force fwrite() to return a
    "failure" return code at a point where the program can easily
    recover because the program knows exactly which records were
    successfully written to disk and which one was not.


 540. "UNKNOWN WARNING" May Result from Bad Error Message File

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  8-MAR-1990    ArticleIdent: Q57942

 If a number of compiler warning messages contain the description
 "UNKNOWN WARNING", the cause may be the use of an incorrect or
 corrupted error message file. The compiler generates the correct error
 number, but since the messages are retrieved from a separate file, the
 compiler displays "UNKNOWN WARNING" when it cannot find a match.

 The error message files for C 5.10 should contain messages for all
 errors and warnings generated. If you look up the number of a compiler
 error in the documentation and find a normally documented error, then
 you should be suspicious of your .ERR error message files.

 The simplest check is to reinstall the error message files from the
 original C 5.10 disks and then recompile to see if the error messages
 appear correctly. The .ERR files to recopy are CL.ERR and C23.ERR from
 the Setup disk and C1.ERR from the disk labeled Compiler Disk 1.


 541. Err Msg: C1064 Too Many _text Segments

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q58522

 Question:

 When I compile my program, I get a fatal error message "C1064 : too
 many _text segments". What is wrong?

 Response:

 This error is caused by using the alloc_text pragma to define more
 than 10 distinct _text segments in a single "compilation unit". The
 following code reproduces the error message:

 Sample Code
 -----------

 /*******************************/
 /* Define _text segments here. */
 /*******************************/

 #pragma alloc_text(foo_1,foofunct_1)
 #pragma alloc_text(foo_2,foofunct_2)
     .
     .
     .
 #pragma alloc_text(foo_11,foofunct_11)

 /*******************************/
 /* Define Prototypes           */
 /*******************************/

 void main(void);
 void foofunct_1(void);
 void foofunct_2(void);
     .
     .
     .
 void foofunct_11(void);

 /********************/
 /* Define functions */
 /********************/

 void main(void)
 {
    printf("Here we go. Eleven alloc_text pragmas: \n");
 }

 void foofunct_1(void)
 {
 }
 void foofunct_2(void)
 {
 }
     .
     .
     .
 void foofunct_11(void)
 {
 }

 See the "Microsoft C Optimizing Compiler: User's Guide" Version 5.1
 manual. The alloc_test pragma is detailed on Page 159. The error
 message (C1064) is documented in the "Microsoft C for MS-DOS and OS/2
 Operating Systems: Version 5.1 Update" on Page 59.


 542. Escape Character Erases First Characters in gets() String

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_quickasm 1.00 1.01 2.00 2.01
 Last Modified: 26-JAN-1990    ArticleIdent: Q57948

 If you enter the escape character (ASCII 1Bh) from the keyboard
 (console) into a string that gets(), cgets(), or fgets() is reading,
 all of the string previously read in is erased. The string pointer is
 reset so that characters following the escape character are read into
 the beginning of the string. This is consistent with the action done
 by the operating system (OS) to parse the input-line.

 However, if the escape character is input from a file by redirection,
 the entire string including the escape character will be read into the
 string.

 Code Example
 ------------

 #include <conio.h>
 #include <stdio.h>

 char buf[22];
 char *result;

 void main(void)
 {
      int i;
      buf[0] = 20;

      printf("Enter your text: \n");
      result = gets(buf);

      printf ( "Resulting String: %s\n", result );
      for( i = 0; i < 20; i ++ )
      {
           printf("Buf[%2d] = %c (char)\n", i, buf[i]);
      }
 }

 Enter the following string as a test:

    abcdef<esc>ghijk

 Note that the resulting string is output as:

    ghijk

 Now, using a text editor that will accept an escape character embedded
 in a string, create a data file with the same string. If the above
 program is run with input redirected from the data file, for example

    program <test.dat

 the resulting string is output as follows:

    abcdef<esc>ghijk

 This behavior occurs in the entire gets() family of routines,
 including gets(), cgets(), and fgets(). If the input is coming from
 the console, the run time will use the standard MS-DOS OS/2 keyboard
 read routines. On the other hand, if the input is coming from a file
 (through redirection) there is no editing performed by the OS and the
 file is read in literally.


 543. Use of the Stringizing Operator (#) in Macros

 Product Version(s): 3.x 4.x 5.00 5.10 | 5.10
 Operating System:   MS-DOS            | OS/2
 Flags: ENDUSER | s_quickc s_quickasm 1.x 2.00 2.01
 Last Modified:  7-MAR-1990    ArticleIdent: Q57949

 When you are writing a preprocessor macro that takes an argument that
 must appear in quotation marks, you can use the # sign to expand the
 argument. One implementation of this preprocessor directive is the use
 of printf() in the macro. The following code demonstrates an example:

 Code Example
 ------------

 #define PR(fmt,value) printf("value = %" #fmt "\n", (value))

 #include <stdio.h>

 void main(void)
 {
    float afl;

    afl = 3.14f;
    PR(5.2f, afl);
 }

 The sample code outputs the following string:

    value =  3.14

 The # sign in front of the fmt variable allows the macro to be
 expanded out with quotation marks. Note that the preprocessor
 concatenates consecutive pairs of double quotation marks so that the
 following string

    "value = %""5.2f""\n"

 is translated into the following:

    "value = %5.2f\n"


 544. Why External References Are Created When They're Not Needed

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q57961

 Problem:

 In the following example, Microsoft C compiler versions 5.00 and 5.10
 generate an extern reference to printf(); therefore, the function is
 included at link time. This apparently is a bug since the compiler
 correctly ignores generating any code for the "if" statement.

 The following is code example:

 #define VERBOSE 0

 int  function(void)
 {
   if (VERBOSE) printf("hello world\n");

   return 1;
 }

 Response:

 The way it works now is by design. The extern reference is generated
 in the first pass of the compiler and the "if" code is removed in pass
 two. Furthermore, according to ANSI specifications (Section 3.7,
 "External Definitions" in December 7, 1988 draft), the extern is
 required.

 If your purpose is to provide conditional code for debugging reasons,
 the preprocessor is much better suited to the task.

 The above code fragment should be changed to the following:

 #define VERBOSE 0

 int  function(void)
 {
 #if (VERBOSE)
   printf("hello world\n");
 #endif

   return 1;
 }


 545. Unresolved Externals from GRAPHICS.LIB

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 26-JAN-1990    ArticleIdent: Q57971

 When linking a program with a version of GRAPHICS.LIB newer than the
 one supplied with your compiler, the following unresolved externals
 will occur:

    LINK : error L2029: Unresolved externals:

    __aDBdoswp in file(s):
     d:\lib\GRAPHICS.LIB(..\gr\qcswap.asm)
    ___aDBswpchk in file(s):
     d:\lib\GRAPHICS.LIB(..\gr\qcswap.asm)
    ___aDBswpflg in file(s):
     d:\lib\GRAPHICS.LIB(..\gr\qcswap.asm)

    There were 3 errors detected

 Code Example
 ------------

 #include <stdio.h>
 #include <graph.h>

 void main(void)
 {
     _clearscreen ( _GCLEARSCREEN );
     _settextcolor ( 1L );
     _outtext ("Hello");
     getch();
 }

 Following are the steps to re-create the unresolved externals:

 1. Compile the program using Microsoft C 5.10 compiler and link the
    object file with GRAPHICS.LIB from either FORTRAN 5.00, QuickC
    2.00, or QuickC 2.01.

 2. Compile the program using Microsoft QuickC 2.00 or 2.01 and link
    the object file with GRAPHICS.LIB from FORTRAN 5.00.

 To determine which GRAPHICS.LIB came with which package, check the
 size of the GRAPHICS.LIB file (shown below):

    C 5.10                       - 59357 bytes   3-07-88   5:10a

    QuickC 2.00                  - 75337 bytes  12-13-88  10:19a

    QuickC w/QuickAssembler 2.01 - 75871 bytes   3-08-89  11:17a

    FORTRAN 5.00                 - 76467 bytes   3-24-89   8:56p

 It is recommended that you use the version of GRAPHICS.LIB that comes
 with the compiler to avoid any problems.


 546. C2144 May Be Caused by Executable Code Between Declarations

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 12-FEB-1990    ArticleIdent: Q58559

 Compiler Error C2144 is defined as follows:

    syntax error : missing 'token' before type 'type'

 You may receive this error message if your program places executable
 code before a data declaration, a practice which was acceptable in
 Kernighan and Ritchie C, but has since been outlawed in later versions
 of the ANSI drafts.

 This error message will normally occur if a required closing curly
 brace (}), right parenthesis [)], or semicolon (;) is missing.

 The following code demonstrates this error message:

 /* Program : foo.c */

 #include <stdio.h>

 void main(void)
 {
         int i;
         printf("Beetlejuice\n");
         int j;
 }

 Compiling this code with Microsoft C Version 3.00, 4.00, 5.00, or
 5.10, or QuickC Version 1.00, 1.01, 2.00, or 2.01 will return the
 following error message:

    foo.c
    foo.c(7) : error C2144: syntax error : missing ';' before
            type 'int'

 Placing all data declarations before all executable code corrects the
 programming error.


 547. Changing a Drive's Volume Label

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm h_masm
 Last Modified: 14-MAR-1990    ArticleIdent: Q58650

 Changing a drive's volume label involves the use of FCB (File Control
 Block) file processing, and therefore, is not supplied with the C
 run-time libraries. However, one of the ways to do this is through DOS
 int 21h calls for FCB file manipulation.

 Below is an assembly routine written with Microsoft MASM Version 5.10
 to change a drive's volume name. To do this, it first sets up an
 extended FCB to allow for manipulating files with attributes. Offset 6
 of the FCB is set to 8 (_A_VOLID defined in dos.h) to specify a
 volume. The old volume is searched for with "*.*" as a pattern and
 deleted, then the volume is re-created with the new volume label
 passed by the C caller. The function returns the error code supplied
 from the DOS API that creates the volume label.

 Use the following:

  rc = NewVol( iDrive, szName ); // iDrive = Drive number ( 1, 2, ... )
                                // szName = Up to 11 chars. DOS filename
                                // rc = Return Code from function.

 The new volume label must be passed with 11 characters for the name.
 Anything less MUST be padded with spaces.

 Sample Code
 -----------

 ;   unsigned NewVol( int, char * ) will delete a disk volume and
 ;                                  create one with the new name.
 ;
 ; Assemble with /Dmodel={SMALL MEDIUM COMPACT LARGE}
 ;               /Dlang={C FORTRAN BASIC PASCAL}

 %.MODEL model,lang

 .DATA
 maxlen  EQU     11                 ;Maximum name length
 datasz  EQU      2                 ;Size of Data Pointers
 ;   Setup an extended FCB
 fcb     DB      255, 0, 0, 0, 0, 0, 8, 1
         DB      37 DUP (?)
 default DB      '*       *  '      ;Equivalent to "*.*"

 .CODE
 NewVol  PROC USES si di es, Drive:WORD, VolName:WORD
         mov     bx,Drive           ;Get drive number ( 1 byte )
         mov     fcb+7,bl           ;...and store in FCB offset 7
         mov     ax,ds
         mov     es,ax
         cld                        ;Upward move
         mov     cx,maxlen          ;Size of move
         mov     si,OFFSET default  ;Source string to
         mov     di,OFFSET fcb+8    ;...filename offset in 8 FCB
         rep     movsb              ;Move maxlen bytes of vol name
         mov     dx,OFFSET fcb      ;Delete volume off drive
         mov     ah,13H
         int     21H
         mov     cx,maxlen
         mov     si,VolName         ;New name passed by C caller
         mov     di,OFFSET fcb+8
         rep     movsb              ;Copy 11 chars for new label
         mov     dx,OFFSET fcb      ;Create the new volume
         mov     ah,16H
         int     21H
         mov     dx,OFFSET fcb      ;Close the file
         mov     ah,10H
         int     21H
         mov     ah,0
         ret
 NewVol  ENDP
         END


 548. Redirecting stdout to and from a File Using C

 Product Version(s): 5.00 5.10  | 5.10
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 26-FEB-1990    ArticleIdent: Q58667

 Question:

 How do I redirect stdout to a file from a C program, then get the
 original stdout back at a later time in the same program?

 Response:

 The C function typically used to redirect stdout or stdin is
 freopen(). To redirect stdout to a file called FOO.TXT, use the
 following call:

    freopen( "foo.txt", "w", stdout );

 This statement causes all subsequent output, which is typically
 directed towards stdout, to go to the file FOO.TXT.

 To get stdout back to the keyboard (the default stdout), use the
 following call:

    freopen( "CON", "w", stdout );

 In both of these cases, check the return value of freopen() to make
 sure that the redirection actually took place.

 Below is a short program to demonstrate the redirection of stdout:

 #include <stdio.h>
 #include <stdlib.h>

 void main(void)
 {
    FILE *stream ;

    if((stream = freopen("foo.txt", "w", stdout)) == NULL)
       exit(-1);

    printf("this is stdout output\n");

    stream = freopen("CON", "w", stdout);

    printf("And now back to the console once again\n");
 }

 This program assumes that stdout is to be redirected toward the
 console at the end of the program.


 549. Using _dos_findfirst() Function to Retrieve Disk Volume

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc 2.00 s_quickasm 2.01
 Last Modified: 26-FEB-1990    ArticleIdent: Q58800

 Question:

 I am using the _dos_findfirst() function to find my disk volume. I use
 the _A_VOLID attribute to get the disk volume and it works correctly,
 except when I get a volume name greater than eight characters. Then, I
 get a period embedded in the middle of my string. For example, if my
 volume name is "VOLUMENAME", _dos_findfirst returns "VOLUMENA.ME". Why
 does the period get embedded in the string?

 Response:

 Volume labels are a specific type of directory entry specified by
 setting bit 3 in the attribute field to 1 or 0x08. They are a special
 type of file that can only be in the root directory. The maximum
 number of characters a volume label can have is 11 characters (8
 characters for the filename followed by a three-character extension).

 The C run-time function _dos_findfirst() will return the volume label
 in a file format since DOS stores the volume label in the file format.


 550. Cannot Allocate More Than 64K with Calloc()

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified:  8-MAR-1990    ArticleIdent: Q58933

 Although calloc() takes two unsigned integers as parameters, it does
 not allocate more than 64K. Calloc() determines the size you are
 attempting to allocate by multiplying the two arguments. If the size
 is greater than 64K, it will return NULL.

 The confusion typically arises because, with malloc(), it is
 impossible to ask for more than 64K due to the size of the argument
 malloc() takes. Malloc() takes an unsigned int as an argument;
 therefore, the largest number you can pass it cannot be greater than
 64K. This is not the case with calloc() -- so one might make the
 assumption that you COULD allocate more than 64K with calloc(). This
 is simply not the case.


 551. If .DLL Is Linked with CRTLIB, Then .EXE Must Be Linked, Too

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  6-MAR-1990    ArticleIdent: Q58961

 When you write a program that uses a DLL that has been linked with
 CRTLIB.DLL, then the program itself must also link with CRTLIB.DLL.
 The diagram and text in Section 5.2 of MTDYNA.DOC explain this close
 relationship in detail.

 Also in MTDYNA.DOC, the table in Section 6 is very useful for
 identifying which components to use for which type of output file
 (.EXE or .DLL). The following is a diagram of the library
 relationships in the table:

                +---------+       |                    +---------+
            /   | xLIBCyP |       |                /   | LLIBCDLL|
        single  +---------+       |            single  +---------+
 +-----+/  thread                 |     +-----+/  thread
 | EXE |                          |     | DLL |
 +-\---+\                         |     +-----+\
   multiple                       |           multiple
     thread     +---------+       |             thread +---------+
      \      \  | LLIBCMT |       |                \   | CRTLIB  |
       \ (or)   +---------+       |                    +---------+
        \ ________________________________________________/

 As long as the .EXE is independent of any DLLs, it links with either
 xLIBCyP.LIB or LLIBCMT.LIB, depending on whether the .EXE is single or
 multithreaded. When the .EXE uses a DLL, the .EXE links with either
 xLIBCyP.LIB or CRTLIB.LIB, depending on whether the DLL is single or
 multithreaded.

 Additional .OBJs and .LIBs are linked for multithreaded .EXEs and for
 single and multithreaded DLLs. You can find complete detailed
 information about compiling and linking multithreaded programs and
 dynamic link libraries in MTDYNA.DOC, which is provided on the C 5.10
 disks.

 For further information, query on the following words:

    CRTLIB and DLL


 552. Pointer Arithmetic Wraps Around Segment Ends

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-MAR-1990    ArticleIdent: Q58987

 When you increment or decrement a pointer beyond a segment boundary,
 the offset of the pointer will wrap around the end. For example, if
 the pointer is sitting at FFFF and you increment it by 1 (one), the
 resulting value of the offset is 0000. This wraparound behavior is
 expected behavior in all memory models except huge. The example below
 demonstrates the "hidden" wraparound.

 The C language permits writing beyond array boundaries and heap
 allocations. Consequently, C compilers do not generate warning or
 error messages if an index or pointer goes out of bounds. It is up to
 the programmer to monitor indices and pointers.

 If you have an array that is larger than 64K, use the huge keyword or
 compile in the huge memory model. Pointer arithmetic for huge data is
 performed on the full 32 bits of segment and offset address. For
 complete information on huge model programming, refer to Chapter 6 in
 the "Microsoft C Optimizing Compiler User's Guide."

 Sample Code:

 /* wrap.c */
 #include <stdio.h>
 #include <dos.h>
 #include <malloc.h>

 void main (void)
 {
  char *ptr;

  ptr = (char*) malloc (100);
  printf ("\nSegment is %u, offset is %u\n", FP_SEG(ptr), FP_OFF(ptr));

  FP_OFF(ptr) = 0x0000;
  printf ("\nSegment is %u, offset is %u\n", FP_SEG(ptr), FP_OFF(ptr));
  ptr--;
  printf ("\nSegment is %u, offset is %u\n", FP_SEG(ptr), FP_OFF(ptr));

  FP_OFF(ptr) = 0xFFFF;
  printf ("\nSegment is %u, offset is %u\n", FP_SEG(ptr), FP_OFF(ptr));
  ptr++;
  printf ("\nSegment is %u, offset is %u\n", FP_SEG(ptr), FP_OFF(ptr));
 }


 553. Buffer Size for fcvt, ecvt Is 349 Bytes

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 15-MAR-1990    ArticleIdent: Q59070

 Question:

 The run-time references to the ecvt and fcvt routines say that they
 use a single, statically allocated buffer while converting floating
 point numbers to character strings. How large is this buffer?

 Response:

 The buffer is currently defined as 349 bytes. However, the largest
 double-precision variable that can be used is 309 bytes, with 40 bytes
 for padding.

 Note: This size may change in future releases of Microsoft's C
 compilers, so you should not rely on the consistency of this size.



 554. Changing a Compaq's CPU Speed

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 15-MAR-1990    ArticleIdent: Q59071

 There are no C run-time functions that change the CPU speed, but there
 is an interrupt that will change the speed of the CPU. This interrupt,
 shown below, works only on Compaq computers.

 INT 16h:

      AH = F0h
      AL = speed
           00h  equivalent to 6 MHz
           01h  equivalent to 8 MHz
           02h  full 16 MHz
           03h  toggles between 8 MHz -- equivalent and speed set by
                system board switch (AUTO or HIGH)
           08h  full 16 MHz except 8 MHz during floppy disk access
           09h  specify speed directly
                CX = speed value, 1 (slowest) to 50 (full), 3 ~= 8088

 To read the current CPU speed, set AH = F1h and call interrupt 16h.

 INT 16h:
      AH = F1h
 RETURN:
      AL = speed code (see function F0h for speed code)
           if AL = 09h, CX = speed code


 555. Determining Size of Memory Block Referenced by a Pointer

 Product Version(s): 5.00   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 15-MAR-1990    ArticleIdent: Q59087

 Question:

 Is there a function in the Microsoft C run-time library that returns
 the amount of memory that has been allocated to a pointer by malloc()?
 If not, is there a way I can write my own?

 Response:

 There is no C run-time library function that explicitly returns the
 amount of memory that has been allocated to a pointer by malloc().
 However, it is possible to retrieve this information indirectly
 through the Microsoft C run-time library function _heapwalk(). The
 _heapwalk() function returns a heap information structure of the
 following form:

    struct _heapinfo {
        int far * _pentry;
        size_t _size;
        int _useflag;
    } _HEAPINFO;

 The information returned in this structure can be accessed directly or
 used in writing a function that gives the size information you want.
 The following is sample code:

 #include <stddef.h>
 #include <malloc.h>

 size_t msize(void * pointer, int * error)
 {
    struct _heapinfo info; /* Heap info structure */
    int   heap_status;     /* Heap status */
    size_t  ret_val;       /* msize() return value */

    info._pentry = NULL;   /* Initialize heap info structure */

    do {
       heap_status = _heapwalk(&info); /* Step through heap until */
    } while ((pointer != info._pentry) /* desired entry is found  */
      && (heap_status == _HEAPOK));   /* or a heap error occurs. */

    if(heap_status == _HEAPOK)
       if(info._useflag != _FREEENTRY)
          ret_val = info._size;          /* no errors */
       else {
          ret_val = -1;                  /* entry has been freed */
          *error = _FREEENTRY;
       }
    else {
       ret_val = -1;     /* a heap error occurred */
       *error = heap_status;
    }
    return(ret_val);
 }

 Note: The msize() function takes as a parameter a pointer pointing to
 the base memory that was allocated. For msize() to work correctly,
 this pointer MUST point to the base of the allocated block, and not
 anywhere within that block.

 The msize() function returns the size of the allocated block or -1 if
 an error occurs. If -1 is returned, an error code is returned through
 the error parameter. The error parameter will be one of the following
 manifest constants:

    _FREENTRY      _HEAPEMPTY      _HEAPBADPTR
    _HEAPBADBEGIN  _HEAPBADNODE    _HEAPEND

 These error codes are actually generated by the Microsoft run-time
 library function _heapwalk(). Refer to your Microsoft C Compiler's
 documentation on _heapwalk() for more information on the meaning of
 these error codes.

 Following is a sample program that uses of the msize() function to
 find the amount of memory allocated to a pointer. This function is
 designed to work in any memory model:

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

 size_t msize(void *, int *);

 void main (void)
 {
    char * p;
    int    error;
    size_t size;

    p = (char *)malloc(sizeof(char) * 11)
    if(p = NULL) {
       printf("Memory allocation error\n");
       return;
    }

    size = msize(p,&error);
    if(size == -1)
       printf("An msize error has occurred\n");
    else
       printf("Size = %u\n", size);
 }

 Note: The malloc() function allocates 11 bytes of memory for use by
 the pointer p. Surprisingly, msize() returns 12 as the size of the
 allocated block. Actually, this is an expected result. Malloc() always
 allocates even-byte amounts as a result of PC architecture.
 Consequently, msize()'s return value always is an even amount.


 556. How to Do a Print Screen within a Program

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  7-MAR-1990    ArticleIdent: Q59380

 The code below demonstrates how to do a print screen from within a
 program under MS-DOS. This is done by executing INT 5 within a
 program.

 The interrupt service directs all its output to the default printer.
 The print-screen service prints text or graphics. In graphics mode,
 GRAPHICS.COM must be loaded before invoking the print-screen service.

 INT 5 does not return any values but the status code is available at
 memory location 0050:0000. The values are as follows:

    00   no error occurred
    01   indicates that a print-screen operation is in progress
    FF   the previous print screen was not successful.

 Code Example
 ------------

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

   void main (void)
   {
      int  *result;
      struct REGS inregs, outregs;

   /* inregs and outregs are never used but necessary
      for the int86 function.
   */

      puts("This is a test of prtscr() function.");
      int86(0x5, &inregs, &outregs);

      *result = (int *) 0x00500000;
      switch( *result )
      {
         case 0:
           puts("No error occurred.");
           break;
         case 1;
           puts("Print Screen in progress....");
           break;
         case 0xFF;
           puts("ERROR occurred during print screen");
           break;
      }
   }


 557. Cannot Open Compiler Intermediate File

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q59479

 In DOS mode, the error number for the "cannot open compiler
 intermediate file" message is C1042; in OS/2, the error number is
 C1043. This is caused by an incorrect setting of the TMP environment
 variable, when a semicolon ends the path. For example:

    TMP=C:\TMP;

 This causes the compiler to return the following error message:

    fatal error C1042: cannot open compiler intermediate file -- DOS

 or

    fatal error C1043: cannot open compiler intermediate file -- OS/2

 The correct way to set up the TMP environment variable is as follows:

    >SET TMP=C:\TMP<RETURN>

 It is important that the environment string does not end with a
 semicolon because the compiler appends the intermediate filename to
 the TMP path. By removing the semicolon from the path, the compiler
 can create the file correctly.

 Since there are other Microsoft products that utilize the TMP
 environment variable, it is safe to remove the semicolon from the end
 of the TMP environment variable path.

 This is true only for the TMP variable because other environment
 variables are used only for a search path.


 558. L2022, L2029 on PM Functions Not Prototyped As EXPENTRY

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | o_os2sdk
 Last Modified: 15-MAR-1990    ArticleIdent: Q59489

 Problem:

 I receive the following error messages when I link my PM (Presentation
 Manager) program:

    LINK : error L2022: ClientWndProc (alias ClientWndProc) :
           export undefined

    LINK : error L2029 : 'ClientWndProc' : unresolved external

 Response:

 Most frequently, this problem is caused by having an /NOI linker
 option, which forces the linker to distinguish between uppercase and
 lowercase. For more information, search the knowledge base using the
 following query:

    L2022 and L2029 and /noi

 These linker error messages may also occur if you forget to prototype
 your functions with the EXPENTRY keyword. The EXPENTRY keyword is
 defined in OS2DEF.H as follows:

    #define EXPENTRY far pascal

 The "pascal" keyword instructs the compiler to use left-to-right
 calling sequences for the function it modifies. The keyword also
 causes the conversion of the function's name to uppercase letters.

 Not using the EXPENTRY keyword means that your function names are not
 converted to uppercase, so even though you declare a .DEF file, which
 includes the following line

    EXPORTS        ClientWndProc

 the linker cannot resolve definitions for the function because it does
 not see ClientWndProc and CLIENTWNDPROC as being equal.


 559. A2071 and A2006 with Assembly Code from a C Program

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_masm s_quickc s_quickasm fixlist6.00
 Last Modified: 15-APR-1990    ArticleIdent: Q59608

 When using the /Fa switch (generate assembly language listing) and the
 /AL switch (large memory model) with C 5.10, the compiler will
 generate some slightly incorrect assembly code in the .ASM file. When
 this assembly code is run through MASM, MASM will give the following
 errors:

    A2071:  Forward needs override or FAR
    A2006:  Phase error between passes

 Specifically, these errors occur in a module that has a function
 calling another function within the same module. In this case, it is
 possible to make a NEAR call to the specified function. Because the
 function being called is a FAR function (in large memory model), CS
 must be pushed onto the stack to correct problems that arise.

 The assembly code produced by C 5.10 does not specify that the call to
 the function is NEAR, although it still pushes CS onto the stack prior
 to calling the function. Because the current memory model is large,
 and the type of call is not specified, a FAR call is assumed.

 When the function returns (with a RET), both CS and IP are popped off
 of the stack, which the call automatically put onto the stack. You are
 left with an extra CS still on the stack.

 To work around this problem, it is important to force a NEAR call to
 the function.

 The following is an example of the C code used to produce the
 assembly code:

 #include <stdio.h>

 void main (void);
 int  r1   (void);

 void main (void)
 {
    printf ("Foo\n");
    r1 ();
    printf ("Bar\n");
 }

 int r1 (void)
 {
    return (1);
 }

 The following is a piece of the assembly code, the important piece in
 this case:
         .
         .
         .
    push  cs
    call  _r1
    mov   WORD PTR [bp-2], ax  ; rc
         .
         .
         .
 Because these procedures are both declared as FAR, it is assumed that
 this is a FAR call. Since that is the case, it is not necessary to
 push CS.

 To correct the problem, you can change the call to the following:
         .
         .
         .
    push  cs
    call  NEAR PTR _r1
    mov   WORD PTR [bp-2], ax  ; rc
         .
         .
         .
 In this case, you are forcing the assembler to notice that only the
 offset is necessary on the stack. When the RET is encountered, both
 words (offset and segment) will be popped off of the stack.

 It is necessary to make these changes for each call to a function that
 can be made with a near call. Calls that are made to functions in
 another module are FAR by default because they are external, so they
 aren't a problem.

 If the .ASM code is assembled with Quick Assembler, the same errors
 will result if the two-pass option is turned on. With only one pass,
 the phase error is not generated. Either way, the same correction
 applies in both cases.


 560. How to Find the Load Size Required for a Program

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified:  9-APR-1990    ArticleIdent: Q59768

 The final allocated segment within a program is stored in the second
 word of its Program Segment Prefix (PSP). To find the size of the
 program in paragraphs, subtract the actual segment of the PSP from
 this segment number. This is useful in a number of applications
 including finding the amount of memory neccessary to store a TSR
 (terminate and stay) program.

 In Microsoft C, the segment of the PSP is stored in the global
 variable _psp. This makes program load size easily accessible within C
 programs as demonstrated below. For more information on the PSP, see
 the "MS-DOS Encyclopedia," Pages 108-111.

 Sample Code
 -----------

 #include<dos.h>

 extern unsigned _psp;       /* segment of PSP                */
 unsigned size;              /* size of program in paragraphs */
 unsigned far *psp_pointer;  /* pointer to beginning of PSP   */

          /* psp_pointer[1] will contain the final allocated  */
          /* segment of the program stored in the second word */
          /* of the Program Segment Prefix.                   */

 void main(void)
 {
      FPSEG(psp_pointer)=_psp;
      FPOFF(psp_pointer)=0;

      size=_psp_pointer[1]-_psp;
 }


 561. Determining If Your TSR Has Already Been Installed

 Product Version(s): 4.00 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm appnote
 Last Modified: 23-MAR-1990    ArticleIdent: Q59884

 When writing a TSR (terminate-and-stay-resident), it is possible to
 utilize the multiplex interrupt (2fh) to determine whether your TSR
 has already been loaded into memory. Set up an Interrupt Service
 Routine (ISR) for this interrupt, which will compare the AH register
 with a predefined TSR number (ID#) and change the AL register to a
 nonzero value if the two are equal.

 When using the interrupt keyword in Microsoft C, registers are pushed
 onto the stack before each function call. To access these register
 values from within an ISR, just define the ISR function as accepting
 these registers as parameters.

 Once this is set up, the installation part of the TSR can make a call
 to the multiplex interrupt with the AH register set to the ID# of the
 TSR, and the AL register set to 00h. If the handler is currently
 installed, it will pick up these values in the AX register and then
 change the AL register to 01h and return this "installed" signal to
 the calling program. If the ID# in the AL register is not that of the
 TSR, the TSR can simply chain the interrupt back to its original
 vector.

 In summary, to have your TSR check to see if it is already installed,
 do the following:

 1. Make an int86 call with the following:

       inregs.h.ah=id#(0xc0-0xff)
       inregs.h.al=0x00

 2. If outregs.h.al != 0x00, program is in memory, don't re-install.

 3. Else, revector INT2fh to your own ISR. This ISR should do the
    following:

    a. Take as parameters the registers pushed on the stack by the
       interrupt keyword (see REGPAK below).

    b. Check the AH register, hibyte of the AX register, with a TSR
       ID#(0xc0-0xff).

    c. If AH=TSR ID#, change al to 0x01.

    d. Else, chain to the old INT2fh vector.

 4. Terminate and stay resident.

 The following is a simple example of an ISR that would accomplish Step
 3 (above) nicely with a TSR ID# of 0xc9. For more information about
 the multiplex interrupt and its function, please refer to "The New
 Peter Norton Programmer's Guide to The IBM PC & PS/2," Page 303-306.
 For an example of a TSR, see the application note "TSR Example
 Dirzap.C," which is available from Microsoft Product Support Services
 by calling (206) 454-2030.

 Sample Program
 --------------

 void (interrupt far *original_int2fh)(); /*set to original*/
                                          /* int2fh handler*/

 #define HIBYTE(x) (((unsigned) (x) >> 8) & 0xff)

 #define REGPAK unsigned es, unsigned ds, unsigned di, \
                unsigned si, unsigned bp, unsigned sp, \
                unsigned bx, unsigned dx, unsigned cx, \
                unsigned ax, unsigned ip, unsigned cs, \
                unsigned flags

 void interrupt far new_int2fh(REGPAK)
 {
      if (HIBYTE(ax)==0xc9) /* check TSR ID# */
           ax=0xc901;       /* set AL to 01  */
      else
           _chain_intr(original_int2fh);
 }


 562. Read() Run-Time Function Example Is Incorrect

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-JUL-1990    ArticleIdent: Q59885

 On Page 481 of the "Microsoft C Optimizing Compiler: Run-Time Library
 Reference," Version 5.1 manual, the sample program for read() is
 incorrect. The conditional statement for the function read() should
 check for the value 65535 (0xFFFF or -1 for a signed int), instead of
 less than or equal to 0 (zero). Since bytesread is declared as an
 unsigned int, the value 0xFFFF is stored as 65535.

 Sample Code
 -----------

 #include <fcntl.h>            /* Needed only for O_RDWR definition */
 #include <io.h>
 #include <stdio.h>

 char buffer[60000];

 void main (void)
 {
   int fh;
   unsigned int nbytes = 60000, bytesread;

   /* Open file for input: */
   if ((fh = open ("data", O_RDONLY)) == -1)
   {
         perror ("open failed on input file");
         exit(1);
   }

   /* Read in input: */

   bytesread = read (fh, buffer, nbytes);
   if ((bytesread == 0) || (bytesread == 65535))
     perror ("Problem reading file");
   else
     printf ("Read %u bytes from file\n", bytesread);
 }


 563. How to Write Directly to Video Memory Under OS/2

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 23-MAR-1990    ArticleIdent: Q59837

 Question:

 I am porting an application from DOS to OS/2 that writes directly to
 screen memory. If I run it from OS/2, it gives me a protection
 violation whenever I attempt to write directly to screen memory. How
 is this done under OS/2?

 Response:

 Under OS/2, you can use the VioGetPhysBuf API call to obtain a 16-bit
 segment selector to the physical screen buffer. You can then use the
 MAKEP macro to obtain a 32-bit far pointer to screen memory.

 It is important to note that your program MUST be the current
 foreground session when writing to the screen buffer obtained by
 VioGetPhysBuf. If you switch the program to the background, OS/2
 temporarily invalidates the selectors to protect the integrity of the
 display. Any attempt to write to these selectors when the process is
 not in the foreground results in a general protection violation. You
 can use the VioScrLock API to ensure that your process will not be
 swapped to the background while writing to the video buffer.

 The following program demonstrates how to write directly to the
 monochrome screen buffer under OS/2.

 Sample Code
 -----------

 /*
  * MONO.C
  *
  * Writes directly to the monochrome screen buffer.
  *
  * Uses VioScrLock and VioScrUnlock to ensure that the program doesn't
  * get swapped to the background while writing to the video buffer.
  *
  * This program basically clears the monochrome screen buffer.
  *
  */

 #define INCL_VIO
 #define INCL_DOSPROCESS

 #define MONOBUF     (char far *) 0xB0000L  /* Address of mono screen
                                            /* buffer */
 #define BYTE_SIZE   4000                   /* 80x25 * 2 */

 #include <os2.h>
 #include <stdio.h>
 #include <conio.h>

 void main (void)
 {
     VIOPHYSBUF viopbBuf;
     PCH pchScreen;
     USHORT usStatus;
     int i;

     viopbBuf.pBuf = MONOBUF;
     viopbBuf.cb = BYTE_SIZE;

     /* Lock the video buffer so bad things don't happen. */
     VioScrLock(LOCKIO_NOWAIT, (PBYTE) &usStatus, 0);

     if (usStatus != LOCK_SUCCESS) {
         printf ("ERROR: Somebody else has the video buffer.\n");
         DosExit (EXIT_PROCESS, usStatus);
     }

     /* Grab the video buffer. */
     usStatus = VioGetPhysBuf(&viopbBuf, 0);
     if (usStatus) {
         printf ("VioGetPhysBuf failed returncode %d.\n",usStatus);
         DosExit (EXIT_PROCESS, usStatus);
     }

     /* Make a 32 bit pointer from a segment selector. */
     pchScreen = MAKEP(viopbBuf.asel[0], 0);

     /* Loop through memory writing spaces. Jump over attribute byte.*/
     for (i=0; i < BYTE_SIZE; i+=2)
         pchScreen[i] = ' ';

     /* We're done, so we can unlock the video buffer. */
     VioScrUnLock(0);
 }


 564. Floating-Point Differences Between the 8086 and MC68000

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm h_masm endian
 Last Modified: 15-JAN-1991    ArticleIdent: Q60037

 Question:

 I am writing a file that will be exchanged between an MC68000 machine
 and an 8086 machine. I want to know how the byte ordering of the IEEE
 (Institute of Electrical and Electronic Engineers) floating-point
 format must be manipulated. In other words, how should the bits or
 bytes be reordered?

 Response:

 The byte ordering of floating point numbers in the architecture of the
 MC68000 is opposite that of the 8086; that is, the bytes are reversed.
 Microsoft C Version 5.10 conforms to the IEEE standard. The 8086
 stores floating-point numbers low-order byte to high-order byte (known
 as "little end in"). The MC68000 stores floating-point numbers
 high-order byte to low-order byte (known as "big end in"). Except for
 the bytes being reversed, the internal representation of the float is
 the same.

 For example, given the following floating-point number in the
 following 4-byte real data type

    5.27E-3

 the representation of that number in IEEE format would be

    3B AC AF F7

 which is equivalent in binary to the following:

    0011 1011 1010 1100 1010 1111 1111 0111

 However, an Intel machine stores this number with the bytes reversed,
 as follows:

    F7 AF AC 3B

 On the other hand, in MC68000 format, the bytes are not reversed.
 Internally the MC68000 would represent the above number as

    3B AC AF F7

 which is the same as the IEEE representation; therefore, no "manual"
 byte reversal needs to be effected.

 To summarize the internal interpretation of the above number, the
 following information is valid for both IEEE and MC68000 formats:

 The mantissa is bits 0-22, which in this case equals 2928631. The
 mantissa is assumed to be prefixed with an implied "1."; therefore,
 the full mantissa is 1.2928631. Bits 23-30 represent the exponent.
 This exponent must be adjusted by a factor of 127 (80 hex; the "bias"
 adjustment, which must be subtracted from the bitwise representation
 of the exponent). Bit 31 is 0, which implies that the exponent is
 positive. Therefore, the exponent as represented here is 119.
 Performing the following bias subtraction:

    119-127 = -8

 While the base in the original number 5.27E-3 is 10, the base of the
 internal representation is 2. Therefore, the above calculation yields
 the final result of

    1.2928631 X 2E-8

 which is the original number (allowing for some floating point
 inaccuracies).


 565. Error in memchr() Definition

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  3-APR-1990    ArticleIdent: Q60045

 The following text shown on Page 418 of the "Microsoft C Optimizing
 Compiler: Run-Time Library Reference" for Version 5.1 manual,
 regarding the definition of the memchr() function, contains a
 misleading statement that could be confusing for some customers:

      void *memchr(buf,c,count);
      void *buf;                      Pointer to buffer
      int c;                  |-----> Character to copy
      size_t count;           |       Number characters
                              |

 Instead of "Character to copy," the definition of int c should read
 "Character to search for." Memchr() searches for, but does not copy, a
 character in a string.


 566. fscanf() Fails to Read Consecutive Lines

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 19-APR-1990    ArticleIdent: Q60336

 If you try to read lines of text using fscanf() from a file opened in
 text mode, and define [^\n] as the delimiter, you will find that your
 program will read only the first line of the text file.

 Sample Code
 -----------

 FILE *fin;
 char Line[80];

 while ( ( fscanf(fin,"%[^\n]",line) ) !=EOF  )
 {
    printf("Line = %s \n",line);
 }

 At first glance, the sample code appears to read and print lines from
 a text file until the end of the file is reached. However, this is not
 the case.

 The fscanf() function reads up to but not including the delimiting
 character. Therefore, the file stream is stopped at the first "\n" in
 the file. Subsequent fscanf() calls fail because the file is still at
 the first delimiting character and fscanf() will not move past it.

 To move the file stream beyond the delimiting character, the following
 are two workarounds:

 1. Place a fgetc() after the fscanf() to position the file pointer
    past the "\n".

 2. Change the fscanf() call to the following:

       fscanf(fin, "%[^\n]%*c", line)

    This automatically reads the next character.

 The corrected code is as follows:

 FILE *fin;
 char Line[80];

 while ( ( fscanf(fin,"%[^\n]",line) ) !=EOF  )
 {
    fgetc(fin);       // Reads in "\n" character and moves file
                      // stream past delimiting character
    printf("Line = %s \n",line);
 }


 567. C Compiler and Linker Send Errors to Stdout Not Stderr

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_util s_pascal h_fortran h_masm docsup docerr
 Last Modified: 19-APR-1990    ArticleIdent: Q60750

 Current versions of the C compiler and linker send error messages to
 stdout instead of stderr. Use of the ERROUT utility shipped with
 Microsoft C Version 5.10 does not redirect these error messages to a
 file as is suggested in the documentation.

 The following example from the Microsoft C Version 5.10 "CodeView and
 Utilities Software Development Tools for the MS-DOS Operating System"
 manual, Page 329, is misleading:

    ERROUT /f C_ERRORS.DOC CL /AL /Zi /Od demo.c

 In the above example, the only thing printed in C_ERRORS.DOC is the C
 compiler copyright and version message. Neither the compiler or the
 linker errors appear there. This is not an error in the ERROUT
 utility, nor is it an error in C Version 5.10; it is just a change in
 the way error messages are output from the newer compilers.

 This new method of sending error output to stdout allows our products
 to function more easily with third-party editors that check only
 stdout for compiler and linker messages.

 Note: The ERROUT utility is designed for use only with executable
 programs and batch files. Attempting to use it on DOS commands, such
 as DIR, usually only results in the failure of the command.


 568. Bad Conditional Jump Generated in Inline Assembly

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q69011

 Under the following conditions, C 6.00 and C 6.00a will generate bad
 code for conditional jumps in inline assembly blocks. If, prior to the
 conditional jump, an align or even directive is used that causes NOP
 instructions to be inserted into the code, the conditional jump
 address will be off by the number of NOPs inserted into the code. This
 will happen only when using the /Od switch for disabling optimizations
 on the compile. Optimizations should not have an affect similar to
 this on inline assembly.

 Using /Os, /Ot, or /Ox will resolve the problem. Removing any align or
 even directives will also eliminate the source of the problem.
 Finally, using the /qc option will also generate correct code;
 however, the /qc option does not generate the NOP instructions for the
 align and even directives as it should.

 Microsoft has confirmed this to be a problem in C version 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 void main (void)
 {
    _asm
    {
       even
       push  ds
       even
       jb    foo
 foo:  pop   ds
    }
 }


 569. Why locking() May Allow Only Twenty Regions to Be Locked

 Product Version(s): 4.x 5.x 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 30-JAN-1991    ArticleIdent: Q67485

 The DOS SHARE.EXE command installs file sharing and locking capability
 within the DOS environment. If SHARE is executed without any
 parameters, the default number of simultaneous file locks is 20.
 Subsequently, the C locking() function will allow only twenty regions
 to be locked at the same time. To change from the default, SHARE
 should be installed with the following parameter (where n is the
 number of simultaneous regions that can be locked):

    SHARE /L:n


 570. C 5.00/5.10 Give "Constant Too Large" with Decimal Initializer

 Product Version(s): 3.00 4.00 5.00 5.10 | 5.10
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q11876

 Problem:

 When I attempt to use the most negative long integer, my results
 depend on whether I used decimal or hexadecimal to enter the value.
 The results also seem to vary between C version 5.00 and the newer
 compilers.

 For example, the following program produces the compiler warning
 "constant too big" when compiled with C 5.00:

 long d1, d2;

 void main(void)
 {
     long  d1 = -2147483648L;
     long  d2 =  0x80000000;
     printf("d1 = %ld", d1);
     printf("d2 = %ld", d2);
 }

 The compiler assigns the value -2147483647 to d1, although it assigns
 -2147483648 to d2. The internal representation of d1 seems incorrect.

 Response:

 In C versions 5.00 and earlier, the decimal constant -2147483648L is
 treated semantically as a unary minus sign applied to a positive
 constant, 2147483648L. The positive constant is outside the valid
 range for constants, and therefore, is reduced to the maximum positive
 long integer; thus, the message "constant too large" is issued.

 On the other hand, the hexadecimal constant 0x80000000 is treated
 semantically as a series of bits. It has few enough bits to fit into a
 long integer, so no message is issued. Had the constant contained too
 many bits to fit into a long integer, it too would have been reduced
 to 2^31 - 1.

 C version 5.10 does not complete compilation in this situation and
 halts with the error, "C2177: constant too large." This ensures that
 you will not be using an unexpected value.

 Beginning with C version 6.00, long constants can be initialized to
 decimal values larger than MAX_LONG (as per the ANSI draft standard),
 so this is no longer a problem at compilation time.


 571. fread() May Cause Protection Violation Under OS/2

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 buglist 6.00a
 Last Modified: 11-FEB-1991    ArticleIdent: Q69136

 Under certain circumstances, fread() may issue a general protection
 violation (GP fault) under OS/2 when compiled in large model with C
 versions 6.00 and 6.00a.

 The sample code below allocates a 64K segment, filling it by doing 128
 fread()'s that request 512 bytes per call. In tracing through the
 code, it appears that as fread() is preparing to continue the read, it
 calculates the address of the first unused byte. Finding it to be
 beyond the end of the segment, it adds 0x20 to the segment value and
 places the result in the ES register, resulting in a general
 protection violation.

 Sample Code
 -----------

 /* Compile with -AL
  *
  */

 #define BUFS_PER_BLOCK   128      /* Number of word buffers per block. */
 #define WORD_BUFFER_SIZE 512

 #include <stdio.h>
 #include <os2.h>

 void main( void)
 {
    SEL  usSel;                    /* Selector for allocated memory. */
    FILE *fp;
    CHAR *ptCurrentBufferAddress;  /* Address of current word buffer. */
    INT   i;

    DosAllocSeg(WORD_BUFFER_SIZE * BUFS_PER_BLOCK, &usSel, SEG_GETTABLE);
    if ((fp = fopen("c:\\os2\\pmfile.exe", "r+b")) == NULL)
       printf("FOPEN FAILED\n");
    else
       printf("FOPEN SUCCEEDED\n");
    ptCurrentBufferAddress = MAKEP(usSel, 0);
    for (i = 0 ; ; i++)
       {
       fread(ptCurrentBufferAddress, WORD_BUFFER_SIZE, 1, fp);
       if (i == BUFS_PER_BLOCK - 1)
          break;
       ptCurrentBufferAddress += WORD_BUFFER_SIZE;
       }
 }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 572. Use of OFFSET and SEG on Local Variables in Inline Assembly

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q69012

 Inline assembly allows you to use the SEG and OFFSET operators to get
 the segment and offset address of variables. However, if you use the
 SEG directive on a local variable, you will get the following error
 message in C versions 6.00 and 6.00a or QuickC versions 2.50 and 2.51:

    error C2415: improper operand type

 You will not get this error with QuickC versions 2.00 and 2.01, and
 incorrect code will be generated. In all versions, using the OFFSET
 directive on a local variable will not directly give you a near
 pointer to the variable.

 It is important to remember that a local variable is placed on the
 stack at run time. Therefore, the compiler cannot determine its
 address at compile time. The value returned by OFFSET applied to a
 local variable actually is that variable's position on the stack
 relative to the BP register. Thus, adding the BP register to the
 OFFSET value will create a near pointer into the stack segment.

 Because the local variable is on the stack, the segment value of a
 local variable is simply the stack segment (SS) register. The
 following two sample programs demonstrate the incorrect and correct
 method to access a local variable address:

 Sample Code
 -----------

 // These programs show how you might try to load an address
 // of a local variable into the dx, ax register combination.

 // This is the wrong way to get a local variable address.

 void main(void)
 {
    int foo;
    _asm
    {
       mov ax, OFFSET foo
       mov dx, SEG foo
    }
 }

 // This is the right way to get a local variable address.

 void main (void)
 {
    int foo;
    _asm
    {
       mov ax, OFFSET foo
       add ax, bp
       mov dx, ss
    }
 }


 573. How Structures Are Packed with /Zp

 Product Version(s):
 Operating System:   6.00 6.00a | 6.00 6.00a
 Flags: MS-DOS     | OS/2
 Last Modified: 30-JAN-1991    ArticleIdent: Q67735
 ENDUSER | docerr s_quickc

 The C compiler contains a command-line option as well as a pragma to
 pack structures, /Zp and pack, respectively. Packing a structure means
 to align an element of a structure on a 1-, 2-, or 4-byte boundary.
 Packing can be used for indexing purposes, as well as to decrease
 processor access times. If /Zp or the pragma is not used, the default
 structure packing value is 2.

 The amount of padding used before a particular structure field is
 determined by the field size and packing value. The packing value may
 change the offset of particular members of the structure.

 All offsets of structure members are relative to 0 (zero). Each member
 size is compared to the packing value (also called the alignment
 value). The element is then aligned on a boundary of the smallest of
 the field size and packing value.

 Finally, the structure itself may be padded to allow for arrays of
 structures to be aligned properly. The rule is simple. All structures
 are padded to a multiple of the pack size except one case. If a
 structure is packed on 4 byte boundaries but doesn't contain any
 elements larger than 2 bytes, it is padded to a multiple of 2.

 Below is an example of a structure that was packed with 1-byte packing
 [/Zp1 or #pragma pack (1)]. The structure is shown first, followed by
 a summary of what happens to the structure in memory, and finally the
 generated assembly listing is shown.

 Structure
 ---------

 struct
 {
    char a;
    int b;
    char c;
 } dummy;

 Packed Structure (/Zp1)
 -----------------------

 struct
 {
    char a;
    int b;
    char c;
 }

 Assembly Code Generated in Small Model
 --------------------------------------

 _BSS SEGMENT WORD PUBLIC 'BSS'
 _BSS ENDS
 .
 .
 .
 _BSS SEGMENT
 COMM NEAR _dummy:BYTE:4
 _BSS ENDS

 Notice that the size in the assembly listing shows 4 bytes. Because
 the structure is exactly 4-bytes in size, there is no need for padding
 at the end.

 The following is an example with 2-byte packing [/Zp2 or #pragma
 pack(2)]:

 Structure
 ---------

 struct
 {
    char a;
    int b;
    char c;
 } dummy;

 Packed Structure (/Zp2)
 -----------------------

 struct
 {
    char a;
    (Filler character here)
    int b;
    char c;
    (Filler character here)
 }

 Assembly Code Generated in Small Model
 --------------------------------------

 _BSS SEGMENT WORD PUBLIC 'BSS'
 _BSS ENDS
 .
 .
 .
 _BSS SEGMENT
 COMM NEAR _dummy:BYTE:6
 _BSS ENDS

 In this case, notice that the int is padded to start on a 2-byte
 boundary and the actual structure was padded to be a multiple of 2.
 Therefore, the length is 6 bytes.

 The following is an example of a structure packed with /Zp4:

 Structure
 ---------

 struct
 {
    char a;
    int  b;
    long c;
    char d;
 } dummy;

 Packed Structure (/Zp4)
 -----------------------

 struct
 {
    char a;
    (1 padding character here)
    int  b;
    long c;
    char d;
    (3 filler characters here)
 }

 Assembly Code Generated in Small Model
 --------------------------------------

 _BSS SEGMENT WORD PUBLIC 'BSS'
 _BSS ENDS
 .
 .
 .
 _BSS SEGMENT
 COMM NEAR _dummy:BYTE:12
 _BSS ENDS

 This is a little more complex. The first padding occurs with the
 integer. Because the field size for an integer is 2 and the alignment
 value is 4, the integer will be aligned on a 2-byte boundary (field
 size is smaller). The long integer needs to be on a 4-byte alignment.
 However, because it is already on a 4-byte boundary, no padding
 characters are needed. Finally, because we have a long in this
 structure, the entire structure is padded to be a multiple of 4.


 574. How to Modify the Environment for a Spawned Process

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q11997

 Question:

 I use the spawnl() function to allow the user to run other programs
 without exiting mine. Is there a way to change the operating system
 command prompt to remind the user to type EXIT to return to my
 program?

 Response:

 Since PROMPT is a DOS and OS/2 environment variable, you just need to
 set your own value for PROMPT in the spawned processes environment. C
 allows you to specify the environment to be handed to a child process
 in one of the following two ways:

 1. Use one of the spawn*e() functions. See the C run-time library
    reference or online help supplied with your compiler for specific
    details about the spawn() family of functions.

 2. Use the putenv() function to modify the program's own local copy of
    the environment, then use one of the spawn() functions other than
    spawn*e(). Details on the putenv() function may also be found in the
    C run-time library reference or online help.

 In general, a process may only alter the environment to be handed to a
 child process. The C run-time library functions give the illusion of
 being able to alter the environment space but this is accomplished by
 making a copy of the environment strings during start up and,
 thereafter, only altering this copy.


 575. How to Change Attributes of Subdirectories in a C Program

 Product Version(s): 3.x 4.x 5.x 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                 | OS/2
 Flags: ENDUSER |
 Last Modified: 25-FEB-1991    ArticleIdent: Q69216

 The C run-time functions _dos_setfileattr() and _dos_getfileattr(), or
 the OS/2 API calls DosSetFileMode() and DosQFileMode(), respectively,
 allow you to set and check the attributes of files. When using the
 same functions on subdirectories, the operating system does not allow
 attributes to be set, and no error codes are returned. However,
 because a subdirectory is a special instance of a file, the system can
 be fooled into thinking that a subdirectory is a file, which will
 allow you to set the attributes of a subdirectory.

 Below is a listing of available attribute settings:

    C Run-Time   OS/2            Description                  Value
    ----------   ----            -----------                  -----

    _A_NORMAL    FILE_NORMAL     A file with no attributes    0x00
    _A_RDONLY    FILE_READONLY   A read-only file             0x01
    _A_HIDDEN    FILE_HIDDEN     A hidden file                0x02
    _A_SYSTEM    FILE_SYSTEM     A system file                0x04
    _A_VOLID     *               Volume label (special case)  0x08
    _A_SUBDIR    FILE_DIRECTORY  Subdirectory (special case)  0x10
    _A_ARCH      FILE_ARCHIVED   An archived file             0x20

  * A drive's volume label is another special-case file; there is only
    one per (logical) drive, and it is only in the root directory.
    Under OS/2, volume labels can be changed with DosSetFSInfo. Under
    DOS, there are no C run-time functions to change drive volumes. For
    more information, query on the following words:

       volume and attribute and 5.10

 From the list above, the only attributes that can be dynamically set
 are FILE_READONLY, FILE_HIDDEN, and FILE_SYSTEM (all files,
 subdirectories, and volumes entail FILE_NORMAL), and this process
 cannot be done on a directory entry that is flagged as a subdirectory
 or volume label. To change the attributes of a subdirectory, the
 attribute flag _A_SUBDIR (or FILE_DIRECTORY) should not be included.
 The code below demonstrates how to do this using either C run-time
 calls (DOS only) or OS/2 API functions (DOS and OS/2 if bound).

 Sample Code
 -----------

 #define INCL_DOSFILEMGR
 #include <os2.h>

 #include <dos.h>
 #include <stdlib.h>

 unsigned attr, newattr;

 void main(void)
 {
    if (DOS_MODE == _osmode)
       {
       // First get the current attribute of subdirectory '\foo'
       // If successful, 'attr' will contain at least the
       // _A_SUBDIR bit mask

       _dos_getfileattr( "\\foo", &attr );

       // Mask in new attributes and remove _A_SUBDIR from the old
       // attribute

       newattr = (attr | _A_HIDDEN | _A_SYSTEM | _A_RDONLY)
                   & ~_A_SUBDIR;

       // Set new attribute for 'foo'

       _dos_setfileattr( "\\foo", newattr );
       }
    else     // Here is the same using OS/2 APIs
       {
       DosQFileMode( "\\foo", &attr, 0L );

       newattr = (attr | FILE_HIDDEN | FILE_SYSTEM | FILE_READONLY)
                   & ~FILE_DIRECTORY;

       DosSetFileMode( "\\foo", newattr, 0L );
       }
 }


 576. Getting to the Mouse from a Real-Mode C Program

 Product Version(s): 3.00 4.00 5.00 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q12012

 Question:

 I am trying to access the mouse from a C program. Do you have an
 example to help get me started?

 Response:

 Below is a program example to test mouse usage from a C program. The
 mouse driver must be installed first. This type of information is
 described in the "Mouse Programming Interface" chapter of the
 "Microsoft Mouse Programmer's Reference" available from Microsoft
 Press.

 Sample Code
 -----------

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

 int m1=0,m2=0,m3=0,m4=0;
 union REGS Mouse_regs;

 void mouse(void)
 {
     Mouse_regs.x.ax=m1;
     Mouse_regs.x.bx=m2;
     Mouse_regs.x.cx=m3;
     Mouse_regs.x.dx=m4;
     int86(0x33,&Mouse_regs,&Mouse_regs);
     m1=Mouse_regs.x.ax;
     m2=Mouse_regs.x.bx;
     m3=Mouse_regs.x.cx;
     m4=Mouse_regs.x.dx;
 }

 void main(void)
 {
     /* Turn on the mouse */
     m1 = 1;           /* SHOW MOUSE Opcode -- See reference */
     m2 = m3 = m4 = 0; /* Additional parameters (init=0) */
     mouse();          /* Make it happen */

     for (;;)          /* loop until both buttons are down */
        {
         m1=3;         /* Get mouse status */
         m2=m3=m4=0;
         mouse();

         if (m2 & 1)
            printf("Left button down\n");
         if (m2 & 2)
            printf("Right button down\n");
         if (m2 & 1 && m2 & 2)
            {
             printf("BOTH!\n");
             exit(0);
            }
        }
 }


 577. Retrieving a Disk's Volume Serial Number from C

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 25-FEB-1991    ArticleIdent: Q69223

 Beginning with MS-DOS 4.00, a semi-random 32-bit binary identification
 number (ID) is assigned to each disk that DOS formats. The volume
 serial number (or ID) is stored at offset 27H to 2AH in the boot
 sector of each disk. The following program illustrates how to retrieve
 this information:

 /***************************************************************/
 /*                                                             */
 /* This program reads the volume serial number (or ID) from    */
 /* the boot sector of a specified disk. The DOS interrupt 25   */
 /* Absolute Disk Read is used to read in the boot sector.      */
 /*                                                             */
 /* Note: The volume ID is only implemented from MS-DOS 4.00    */
 /*       and later.                                            */
 /*                                                             */
 /* The output consists of the OEM name and version of the      */
 /* disk-formatting program (stored at offset 03H to 0AH in the */
 /* boot sector), the disk volume label, and the disk-volume    */
 /* serial number.                                              */
 /*                                                             */
 /***************************************************************/

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <dos.h>
 #include <conio.h>

 char bootsector[1024];
 char volume[12];
 char ver[9];
 char block[10];

 void main(void)
 {
    int ax, _far *p, drive;
    struct find_t fileinfo;
    char filename[13], _far *foo, _far *q;
    union REGS inregs, outregs;
    struct SREGS segregs;

    printf("Enter drive number (0=A,1=B,2=C, ...): ");
    drive=getche() - '0';

    /**************************************/
    /* Parameter block for int 25H        */
    /* Bytes    Description               */
    /* -------  -----------               */
    /* 00H-03H  32-bit sector number      */
    /* 04H-05H  Number of sectors to read */
    /* 06H-07H  Offset of buffer          */
    /* 08H-09H  Segment of buffer         */
    /**************************************/

    block[0]=block[1]=block[2]=block[3]=0;
    block[4]=1;
    block[5]=0;

    foo=bootsector;

    p=(int *)&block[6];
    *p=FP_OFF(foo);

    p=(int *)&block[8];
    *p=FP_SEG(foo);

    q=block;
    inregs.h.al=(char) drive;
    inregs.x.cx=-1;
    inregs.x.bx=FP_OFF(q);
    segregs.ds=FP_SEG(q);
    ax=int86x(0x25, &inregs, &outregs, &segregs);

    /*** Error routine ***/

    if(outregs.x.cflag)
    {
       printf("\n\nerror on int 25\n");
       printf("this is AX:%04X",ax);
       exit(-1);
    }

    /*** Output ***/

    printf("\n\nDrive %c\n-------\n\n", drive +'A');

    strncpy(ver, &bootsector[3], 8);
    printf("OEM name and version: %s\n", ver);

    /* Use _dos_findfirst for the volume label */

    filename[0]=(char) (drive + 'A');
    filename[1]='\0';
    strcat(filename, ":\\*.*");
    if(!_dos_findfirst(filename, _A_VOLID, &fileinfo))
    printf("Volume name         : %s\n",fileinfo.name);

    /* Before printing serial number, check if version >= 4.x */

    if((ver[6]=='.')&&(ver[5]>='4')&&(ver[5]<='9'))
       printf("Serial number       : %02X%02X-%02X%02X\n\n",
                               (unsigned char) bootsector[0x2a],
                               (unsigned char) bootsector[0x29],
                               (unsigned char) bootsector[0x28],
                               (unsigned char) bootsector[0x27]);
 }


 578. Comments in .COD Listing Are Wrong When Using _fastcall

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a fastcall
 Last Modified: 30-JAN-1991    ArticleIdent: Q67513

 When using the code below with the _fastcall keyword, and compiling
 with the /Fc option for a code listing, the listing generates correct
 code but incorrectly comments the values that are being pushed.

 Using the /Gs (recommended for using _fastcall) and /Fc compile-line
 options will generate a code listing that produces wrong comments for
 the following statements:

    mov ch, byte ptr top
    mov cl, byte ptr left
    mov dh, byte ptr bot

 The code listing below shows the incorrect comments that are
 generated:

 ;|***                   mov al, byte ptr lines
 ; Line 13
         *** 000018   8a 46 06   mov     al,BYTE PTR [bp+6] ;lines
 ;|***                   mov bh, byte ptr attr
 ; Line 14
         *** 00001b   8a 7e fe   mov     bh,BYTE PTR [bp-2] ;attr
 ;|***                   mov ch, byte ptr top
 ; Line 15
         *** 00001e   8a 6e fe   mov     ch,BYTE PTR [bp-8]
 ;|***                   mov cl, byte ptr left
 ; Line 16
         *** 000021   8a 4e fa   mov     cl,BYTE PTR [bp-6] ;top
 ;|***                   mov dh, byte ptr bot
 ; Line 17
         *** 000024   8a 76 fc   mov     dh,BYTE PTR [bp-4] ;left
 ;|***                   mov dl, byte ptr right
 ; Line 18
         *** 000027   8a 56 08   mov     dl,BYTE PTR [bp+8] ;right

 Notice that the comments after the ch, cl, dh mov statements are not
 the same variable names that were actually moved into these registers.
 For instance, the statement

     mov ch, byte ptr top

 has no comment after it stating what variable was used. However, the
 statement

     mov cl, byte ptr left

 has a comment of ";top" stating that top was moved in. Obviously,
 "top" was moved into the ch register in the previous statement.

 Note: The generated code in this listing, as well as in the OBJ, is
 correct.

 Sample Code
 -----------

 static void _fastcall scr_scroll
           (int top, int left, int bot, int right, int lines, int dir)
 {
         char attr = 7;

         _asm
                 {
                         mov ah, byte ptr dir
                         or  ah, ah
                         mov ah, 7
                         jnz around
                         dec ah
                 around:
                         mov al, byte ptr lines
                         mov bh, byte ptr attr
                         mov ch, byte ptr top
                         mov cl, byte ptr left
                         mov dh, byte ptr bot
                         mov dl, byte ptr right
                         int 0x10
                 }
 }

 void main(void)
 {
         int t=0,l=0,b=0,r=0,li=0,d=0;
         scr_scroll(t,l,b,r,li,d);
 }

 Microsoft has confirmed this to be a problem in the C version 6.00a.
 We are researching this problem and will post new information here as
 it becomes available.


 579. Directly Accessing Video Memory from a C Program

 Product Version(s): 3.00 4.00 5.00 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q12010

 Question:

 How can we access the video memory bytes located in segment B800
 offset 0? We want to move blocks of bytes directly to the graphic
 system memory in a C program.

 Response:

 When programs access special memory directly, they become less
 portable, and may not run as expected on other or future machines.
 Given this warning, the sample code below is a function that directly
 accesses video memory.

 Sample Code
 -----------

 /* Video.c -- Function to place a character and its standard
               attribute into the desired video memory page.

       Note: This function assumes that the display is set to
            Color or Monochrome, 80 column, text mode.
 */

 #include <dos.h>

 #define MAKELONG(a, b)  ((long)(((unsigned)a) \
                        | ((unsigned long)((unsigned)b)) << 16))
 #define COLORTEXT_BUFFER   0XB800

 void video(int pageno, int row, int col, char *ch, char attrib)
 /* pageno : page number to load character into (0 to 3) */
 /* row    : row of location 0 to 24                     */
 /* col    : column of location 0 to 79                  */
 /* ch     : character to be placed there                */
 /* attrib : standard character attribute                */
 {
     unsigned int offset; /* Offset from the segment address of
                             the desired video page */
     char far *y;         /* Long Pointer to the position in memory
                             where we will put the character and
                             it's attribute (next byte) */

 /* Calc the in-page offset w/page number offset and segment address */
     offset = (unsigned int) ((row * 160 )+(col*2)+(pageno*4096));

 /* Set the character. */
     y = (char far *)MAKELONG( offset, COLORTEXT_BUFFER);
     *y = *ch;

 /*  Set the attribute byte. See a DOS programmers reference for
     more information on video attributes. */
     offset++;
     y = (char far *)MAKELONG( offset, COLORTEXT_BUFFER);
     *y = attrib;
 }


 580. C1001: Internal Compiler Error: regMD.c, Lines 3881 and 3837

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69224

 The C version 6.00a compiler produces the following internal compiler
 error when the sample program below is compiled with the intrinsic
 optimization (/Oi):

    file.c(7) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.110', line 3881)
                Contact Microsoft Product Support Services

 With C version 6.00, the error is the same, except it is line 3837.

 Using the function version of strlen() eliminates the problem.

 Microsoft has confirmed this to be a problem in the C compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.

 Sample Code
 -----------

 #include <stdio.h>

 void main(void)
 {
    char * string;
    int j;

    j = 8 * strlen(string);
 }


 581. Questions and Answers About the Use of malloc() and _fmalloc()

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q12159

 Question:

 I am designing a product using the medium model, but need some dynamic
 memory larger than the default segment for temporary storage and
 semi-permanent main data structures. Things seem to be working
 properly, but I have the following questions:

 1. Can malloc() and _fmalloc() be used together without restriction,
    for example, using malloc() for the temporary data and _fmalloc()
    for the semi-permanent data?

 2. Are there ever any user-visible delays for garbage collection
    (compression of string space)?

 3. Are there fragmentation risks? In experimenting with _fmalloc(), it
    appears that contiguous blocks freed at different times are
    automatically consolidated, which should reduce the fragmentation
    risk.

 4. Does _fmalloc() ensure that any single assignment is within one
    data segment (so assembly move/access routines need not deal with
    segment boundaries)?

 Response:

 1. Yes, malloc() and _fmalloc() may be used together. They both track
    their memory allocation separately and, in fact, you must use two
    different functions to free the allocated data: free() and _ffree()
    respectively.

 2. The malloc() functions do not perform any form of garbage
    collection. You allocate the space and you decide when it is to be
    freed up for later usage. Therefore, there will be no visible or
    unexpected time delays during execution.

 3. The _fmalloc() function will consolidate adjacent free blocks. This
    reduces the risk of fragmentation problems.

 4. The _fmalloc() function will not allocate across segment
    boundaries. Only halloc() (the huge-model memory allocation
    routine) can perform this function. Therefore you are assured that
    no one allocation will cross a segment boundary (because it cannot
    allocate larger then 64K).


 582. Use Timer Interrupt to Maintain Time Independent of CPU Speed

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q12131

 Question:

 Is there a way to set up a function that will pause for n units of
 time without being altered on a faster or slower machine (for example,
 from a PC to an AT).

 Response:

 Set up a routine to handle the timer tick interrupt. This will be the
 same on all machines (about 18.2 times per second with interrupts
 enabled). The timer tick is interrupt 1C and can be modified for
 access by your own routine.


 583. _bheapseg: Return Value Documented Incorrectly

 Product Version(s): 6.00 6.00a  | 6.00 6.00a
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-FEB-1991    ArticleIdent: Q69237

 The return value for the _bheapseg function is documented incorrectly
 on page 147 of the "Microsoft C Reference," in the online help for C
 6.00, and in the online help for QuickC versions 2.50 and 2.51.

 On page 147 of the "Microsoft C Reference," the line that reads

    Returns     The selector for the newly allocated segment
                if successful; -1 if not.

 should read as follows:

    Returns     The selector for the newly allocated segment
                if successful; 0 (_NULLSEG) if not.

 The online help mentions the correct return value for the _bheapseg
 function in the "Summary" section, except that it specifies NULLSEG
 instead of _NULLSEG. The paragraph in the "Description" section titled
 "Return Value" incorrectly documents the return value as -1.


 584. Call ROM BIOS Routines to Check the Printer Status

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q12110

 Question:

 We are sending text to the printer using fopen("prn","w"). Many of our
 clients get the following message:

    Writing error on device PRN -- abort, retry, ignore.

 How can we check the printer status so that we can avoid this?

 Response:

 Although there is no portable method for checking printer status in C,
 you can get printer status information via the ROM BIOS. You can
 obtain status information by calling _bios_printer(), which is an
 interface to INT 17H, function 2. You can also call BIOS interrupt
 functions through the int86() functions. See the online help or the
 run-time library reference for your version of the compiler for more
 information about these functions.

 You may want to handle the error by revectoring the critical error
 handler interrupt (24H), which will allow you to intercept the "abort,
 retry" message before the user receives it. You then can decide
 whether to substitute your own message, such as "Printer off line: set
 printer on line and press Y to continue."

 More information on the ROM BIOS routines and interrupt handlers can
 be found in the following two books from Microsoft Press:

 1. "The Peter Norton Programmer's Guide to the IBM PC" (r)

 2. "Advanced MS-DOS" by Ray Duncan


 585. C1001: Internal Compiler Error: exphelp.c, Line 617

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69289

 The Microsoft C Compiler versions 6.00 and 6.00a produce the following
 internal compiler error when the sample program below is compiled with
 default optimization and large memory model (/AL):

    mem2.c(4) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)exphelp.c:1.117', line 617)
                Contact Microsoft Product Support Services

 The above error occurs only when using any one of the optimizations
 /Oi, /Oa, /Oc, /On, /Op, /Or, /Os, /Ot, /Ow, /Oz, or using default
 optimizations. Furthermore, the source must be compiled in compact,
 large, or huge memory models.

 To work around the problem, compile without using default
 optimizations or any of the above mentioned options. You may elect to
 disable optimizations for the function that is producing the error. Do
 this by using the "optimize" pragma. Another valid workaround is to
 compile using the /qc (Quick Compile) option, which also does not
 produce the error.

 Sample Code
 -----------

 /* Compile with /AL */

 void func(int *memoryPtr,unsigned long pageLow)
 {
     if ((*memoryPtr)>0)
       pageLow=(unsigned long)memoryPtr>>28;
 }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 586. Bad Code Generated for Function Returning _self Based Pointer

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 30-JAN-1991    ArticleIdent: Q67612

 The C versions 6.00 and 6.00a compilers will generate incorrect code
 for a function that returns a pointer based on self. The code
 generated for the return statement introduces an extra level of
 indirection.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 The following program fragment demonstrates this problem. Compile the
 code with the /Fc option to generate an assembly listing, and observe
 the code in the resulting .COD file for the return statement in the
 function test().

 struct foo {
             int  _based((_segment) _self) *pbs;
            } far *pfoo;

 int far *test(void)
 {
    return(pfoo->pbs);
 }


 587. Use the signal() Function to Trap Floating-Point Exceptions

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q12127

 Question:

 Is there a way that I can trap all possible floating point exceptions
 in a C program?

 Response:

 The C signal() function allows the capture of floating-point
 exceptions.

 For more information on the signal() function, see the run-time
 library reference or the online help that accompanies your compiler.


 588. Promotion of char to int May Add Two Hex Digits in printf()

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | s_quickc hexidecimal conversion
 Last Modified: 25-FEB-1991    ArticleIdent: Q69344

 When trying to display a signed char in two-digit hexadecimal format, as
 follows

    char hex_byte = 0x80;
    printf( "The Hex value is %X", hex_byte);

 four digits will be displayed if the char has a value of 0x80 to 0xFF
 because of promotion of the char to a signed int. The %x and %X
 specifiers designate an unsigned hex integer, but because leading 0's
 (zeros) are dropped, values in the range of 0 to 127 produce the
 desired two digits. See the sample code below.

 To preserve the two-digit display for all possible values, just
 typecast the char to an unsigned char in the printf() argument list,
 as shown below:

    printf( "The Hex value is %X", (unsigned char)hex_byte);

 Another way to achieve this, if sign is of no consequence, is to
 declare the variables as unsigned char.

 For ANSI compliance, the compiler promotes all char arguments to
 signed int. If the type is signed char, then the value will be
 sign-extended. Thus, the int will be negative if the left-most bit of
 the char was set, resulting in a different value for the int. When an
 unsigned char is promoted, a 0 (zero) is placed in the high byte so
 that the value is retained.

 This promotion may also cause problems with comparisons of signed and
 unsigned chars. This situation, unlike the printf() situation, will
 produce a C4018 (signed/unsigned mismatch) warning at warning level 3
 and above, beginning with C version 6.00.

 This behavior is also observed in QuickC versions 2.00 and 2.50 and
 QuickC with QuickAssembler versions 2.01 and 2.51.

 Sample Code
 -----------

 #include <stdio.h>

 void main( void)
 {
    char goo = 127;
    char foo = 128;

    printf( "goo = %X\n",   goo); /* yields "7F" */
    printf( "foo = %X\n",   foo); /* yields "FF80" */

    /* correct way to represent the char as two hex digits "80" */
    printf( "foo = %X\n",   (unsigned char)foo);
 }


 589. File Component Constants Increased Beginning with C 6.00

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 25-FEB-1991    ArticleIdent: Q69349

 The following manifest constants (found in STDLIB.H) were changed
 beginning with C version 6.00:

    _MAX_PATH       260     /* max. length of full pathname */
    _MAX_DRIVE      3       /* max. length of drive component */
    _MAX_DIR        256     /* max. length of path component */
    _MAX_FNAME      256     /* max. length of filename component */
    _MAX_EXT        256     /* max. length of extension component */

 Prior to C 6.00, these constants were defined as follows:

    _MAX_PATH       144
    _MAX_DRIVE      3
    _MAX_DIR        130
    _MAX_FNAME      9
    _MAX_EXT        5

 These changes may cause unexpected results if filenames longer than
 eight characters are entered for use under DOS. The sample code below
 demonstrates the differences.

 The changes in the constants were made to allow for longer filenames
 and extensions in future operating systems, as well as the current
 implementation of the High Performance File System (HPFS) introduced
 in OS/2 version 1.20. The potential for problems is greatest when
 buffers are used that are not as big as the new constant values. This
 generally occurs when porting code from a previous version of the
 compiler to C version 6.00 or later.

 There are several ways to protect against problems that may occur in
 your code because of this change:

 1. Always declare filename buffers with the actual constants, for
    example:

       char file_name[_MAX_FNAME];

 2. Provide error checking before file operations are performed, such
    as:

       #define DOS_FILE_NAME_LENGTH 8

       if ( strlen(file_name) > DOS_FILE_NAME_LENGTH )
            printf("File name too long, try again");

 3. In extreme cases, you can change the constants in STDLIB.H back to
    the previous values, but this will also require the purchase of the
    Microsoft C run-time library source code so that you may rebuild
    the affected modules in the run-time library. The one advantage of
    this method is that it saves the memory used by buffers declared
    with the larger values (840 bytes).

 The sample program below prompts for a filename to be input. If the
 input file specification is

    C:\PATHPATHPATH\NAMENAMENAME.EXTEXT

 then the output with C version 5.10 will be

     Old path was : C:\PATHPATHPATH\NAMENAMENAME.EXTEXT
     Drive is     : C:
     Dir is       : \PATHPATHPATH\
     Fname is     : NAMENAME
     Extension is : .EXT
     New path is  : C:\PATHPATHPATH\NAMENAME.EXT

 while, with C version 6.00, the ouput will be:

     Old path was : C:\PATHPATHPATH\NAMENAMENAME.EXTEXT
     Drive is     : C:
     Dir is       : \PATHPATHPATH\
     Fname is     : NAMENAMENAME
     Extension is : .EXTEXT
     New path is  : C:\PATHPATHPATH\NAMENAMENAME.EXTEXT

 Notice that in C 5.10, the name is truncated to eight characters and
 the extension is truncated to three characters (plus the period),
 while in C 6.00 the name and extension are left unchanged.

 Note that these same new larger constants are present in QuickC
 beginning with versions 2.50 and 2.51 because these packages share
 the same include files as C 6.00.

 Sample Code
 -----------

 /* Compile options needed: none
 */
 #include <stdio.h>
 #include <stdlib.h>

 void main( void)
 {
    char oldpath[_MAX_PATH];
    char newpath[_MAX_PATH];
    char   drive[_MAX_DRIVE];
    char     dir[_MAX_DIR];
    char   fname[_MAX_FNAME];
    char     ext[_MAX_EXT];

    printf( "Enter a file name: " );
    gets( oldpath );

    _splitpath( oldpath, drive, dir, fname, ext );
    _makepath( newpath, drive, dir, fname, ext );

    printf( "Old path was : %s\n", oldpath);
    printf( "Drive is     : %s\n", drive);
    printf( "Dir is       : %s\n", dir);
    printf( "Fname is     : %s\n", fname);
    printf( "Extension is : %s\n", ext);
    printf( "New path is  : %s\n", newpath);
 }


 590. CHRTDEMO Example Gives C2059 Error with ANSI Compatibility Set

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc chartdemo pgchart
 Last Modified: 25-FEB-1991    ArticleIdent: Q69350

 If the C version 6.00 sample Presentation Graphics program CHRTDEMO.C
 is compiled with the ANSI compatibility switch (/Za), the following
 compiler error will be produced:

    chrtdemo.h(140) : error C2059: syntax error : '*'

 This is correct behavior due to the use of the Microsoft extension
 "far" found on line 140 of CHRTDEMO.H; /Za disables extensions
 specific to Microsoft C.

 The supplied CHRTDEMO.MAK makefile is set up to use the default
 setting of /Ze (Microsoft C extensions enabled). The C2059 error will
 only occur if this option is changed to /Za (ANSI compatibility --
 Microsoft C extensions disabled). This change could be made either
 inside the Programmer's WorkBench from the C Compiler Options dialog
 box or by actually modifying the makefile to include /Za in the
 compiler flags macro.

 According to the ANSI specification, all keywords that are extensions
 to the language must begin with a leading underscore. Beginning with C
 version 6.00, the Microsoft supplied header files contain this change
 to all keywords, such as _far, _pascal, etc., but the previous
 versions of these keywords without the leading underscores are
 retained for backwards compatibility.

 Most of the sample programs were modified to include the new keywords,
 but the line in CHRTDEMO.H was not changed to include _far, instead of
 far, thus resulting in the C2059 error with /Za. If you modify the far
 keyword on line 140 of CHRTDEMO.H so that it includes a leading
 underscore, this will eliminate the C2059 error even when /Za is
 specified.

 The QuickC compiler shares the same ANSI compatibility mode as the
 optimizing compiler, as well as a similar chart example program. Thus,
 the same C2059 error may be encountered with /Za in QuickC versions
 2.00, 2.01, 2.50, and 2.51.


 591. Dividing Negative Integers May Give Positive Results

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 30-JAN-1991    ArticleIdent: Q67740

 In some situations, dividing a negative integer by a positive integer
 may give positive results. For example, when the following code is
 compiled with the /Od option, both printf() statements will generate
 positive answers.

 Code Example
 ------------

 void foo(void)
 {
     int num1 = -32768,
         num2 = -32751;

     printf(" %d ",  num1 / 16);
     printf(" %d ", (num2 & 0xfff0) / 16);
 }

 When these calculations are performed, the sign bit is lost. The
 output is incorrect for the first printf() statement when -32768 is
 being divided by a power of 2 (for example, 4,8,16,32,64,...16384).

 Workarounds for the first printf() statement are:

 1. Compile without the /Od option.

 2. Compile with the /qc option.

 With the second printf(), the value (num2 & 0xfff0) must be typecast
 to an integer or separated into another statement. For example,

    printf(" %d ", (int)(num2 & 0xfff0) / 16);

 -or-

    num3 = num2 & 0xfff0;
    printf(" %d ", num3 / 16);

 Microsoft has confirmed this to be a problem in the C versions 5.10,
 6.00, and 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 592. C1001: Internal Compiler Error: grammar.c, Line 140

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q67781

 The C version 6.00a compiler produces the following internal compiler
 error when the sample program below is compiled the /Ox or /Oe
 optimizations:

    foo.c(9):fatal error C1001:Internal Compiler Error
        (compiler file '../grammar.c', line 140)
        Contact Microsoft Product Support Services

 The following are valid workarounds for this problem:

 1. Compile with any optimization not containing /Oe.

 2. Disable the "e" optimization using the optimize pragma.

 Sample Code
 -----------

 1  typedef struct utype { char bitmap[10]; } Utype;
 2  extern Utype utypes[];
 3
 4  void InitializeBitmaps(void)
 5  {
 6     int cnt,cnt2;
 7     for(cnt=0;cnt<13;cnt++)
 8       for(cnt2=0;cnt2<10;cnt2++)
 9          utypes[cnt].bitmap[cnt2]=(char)~utypes[cnt].bitmap[cnt2];
 10 }

 Microsoft has confirmed this to be a problem in Microsoft C version
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 593. C1001: Internal Compiler Error: regMD.c, Lines 3101 and 3074

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69413

 The Microsoft C Compiler versions 6.00 and 6.00a produce the following
 internal compiler errors when the sample program below is compiled
 with default optimization:

 With C 6.00a
 ------------

    file.c(5) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.110', line 3101)
                Contact Microsoft Product Support Services

 With C 6.00
 -----------

    file.c(5) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.100', line 3074)
                Contact Microsoft Product Support Services

 These errors will occur under any memory model when using any one of
 the following optimizations (although the errors may not occur when
 some of these options are combined):

    /Oa, /Oc, /Od, /Oi, /On, /Op, /Or, /Os, /Ot, /Ow, or /Oz

 There are several possible ways to work around these errors:

 1. Do not use any of the above options and do not use the default
    optimization for the module where the error occurs.

 2. Add /Oe or /Og; one of these combined with other optimizations
    may eliminate the problem.

 3. Selectively disable optimizations for the particular function that
    is producing the error through use of the optimize pragma.

 4. Rewrite the statement to use an if-else construct instead of the
    ternary operator.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 /* Compile options needed: none
 */

 void func(unsigned char uch1, unsigned char uch2)
 {
     uch2 = uch1 ? (unsigned char)'0' : (unsigned char)(uch1 % 24);
 }


 594. Old Compiler Pass May Cause C1007: Unrecognized Flag -Bm in P2

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified: 25-FEB-1991    ArticleIdent: Q69474

 If you receive the following error when compiling a program with C
 version 6.00 or 6.00a

    fatal error C1007: unrecognized flag '-Bm' in 'p2'

 it may be the result of inadvertently invoking pass 2 (C2.EXE) of an
 earlier version of the compiler, such as C version 5.10. Beginning
 with C version 6.00, the option -Bm is a valid flag for pass 2 of the
 compiler. This was not a valid option in earlier compiler versions.

 When looking for an executable file, the operating system will first
 search your current directory, and then search all the directories
 listed in your path. You should make sure that the C 6.00 compiler is
 listed first on your path, before any other versions of the compiler.
 This is especially true when running on a network because network
 search paths sometimes obscure exactly what directories are being
 searched for files.

 If you would like to double-check which drive and directory are being
 used when compiling, invoke the compiler with the /d option. This
 option displays the information that is being passed to each phase of
 the compiler, including the name and directory of the compiler file in
 use.


 595. _getpixel() Return Value is Not Changed by _setbkcolor() Call

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q67759

 In the sample program below, _getpixel() will return a 0 (zero).
 Setting _setbkcolor() to any other color has no effect on the return
 value from _getpixel().

 The _getpixel() function is documented as returning a color index for
 a specific pixel. In the example program, there are no colors on the
 screen except the background color (color index 0). When the call to
 _setbkcolor() is made, the color mapped to index 0 is changed;
 however, the color index for the pixel is not changed. Therefore,
 _getpixel() still returns 0. This same behavior is exhibited when
 using the _remappallette() function on index 0 and the
 _remapallpallette() function.

 To change the color index at a particular point on the screen, first
 call the _setcolor() function with the desired color index, then use
 one of the graphics drawing functions, for example, _floodfill(),
 _setpixel(), etc.

 Sample Code
 -----------

 // Note: C 5.10 doesn't support _MAXRESMODE

 #include<graph.h>
 #include<stdio.h>
 void main(void)
 {
    short xvar=100,yvar=100,result1=0,result2=0;
    _setvideomode(_MAXRESMODE);
    result1=_getpixel(xvar,yvar);
    _setbkcolor(_BLUE);
    result2=_getpixel(xvar,yvar);
    _setvideomode(_DEFAULTMODE);
    printf("Before _setbkcolor - %d\n",result1);
    printf("After _setbkcolor  - %d\n",result2);
 }


 596. stdout/stderr Are Buffered When Stack Is Moved Out of DGROUP

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69476

 By following the instructions in the C 6.00 STARTUP.DOC file, you can
 recompile/reassemble the C start-up code and modify existing libraries
 so that the stack will be moved out of DGROUP for programs linked with
 these modified libraries. When using the DOS version of these modified
 libraries, stdout and stderr are unexpectedly buffered. The sample
 code and sample output below illustrate this problem.

 The OS/2 versions of the modified libraries perform as expected;
 however, to achieve the correct behavior with the DOS versions of the
 modified libraries, you must add the following line to your code:

    setvbuf(stdout, NULL, _IONBF, 0);

 This line sets buffering for streams to none.

 Information about the predefined stream pointers can be observed by
 compiling the start-up code with CodeView information and placing a
 watch on the _iob2 array. Information about stdout is in _iob2[1].
 After executing the start-up code, the buffer size on stdout is still
 0 (zero); however, once a function call is made to printf(), the
 buffer size for _iob2[1] is changed to 512 (0x200) bytes. This change
 does not occur when the stack is left in DGROUP.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 /* Compile options needed: /c /ALw /Zi /Od
       Link options needed: /CO /NOD (plus you must specify the
                            modified DOS C run-time library)
 */

 #include <stdio.h>

 int number;

 void main(void)
 {
     /* Uncomment the following line to obtain the desired results */
     /* setvbuf(stdout, NULL, _IONBF, 0); */

     printf("\nEnter a number: ");
     scanf("%d", &number);
     printf("\nThe number is %1d\n", number);
 }

 Program Output
 --------------

 22                   /* user enters a number (without prompt) */

 Enter a number:      /* printf() output is buffered, so output does */
 The number is 22     /* not appear until exit code flushes buffers  */


 597. _bios_disk() May Require 3 Tries for Drive to Get Up to Speed

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-FEB-1991    ArticleIdent: Q69504

 The _bios_disk() routine in the C run-time library uses BIOS interrupt
 0x13 to provide several disk-access functions. The ROM BIOS does not
 automatically wait for the drive to come up to speed before attempting
 to read the sector, verify the sector, or write to the sector. In the
 book "IBM ROM BIOS" by Ray Duncan, the recommendation given in each
 case is to reset the floppy disk system and try the operation three
 times before assuming an error has occurred.

 The following sample program from the C 6.00 online help makes three
 attempts to read the disk before giving up. A printf() statement is
 added to show which read attempt is successful.

 Sample Code
 -----------

 /* Compile options needed: none
 */

 #include <stdio.h>
 #include <conio.h>
 #include <bios.h>
 #include <dos.h>
 #include <stdlib.h>

 char _far diskbuf[512];

 void main( int argc, char *argv[] )
 {
    int count;
    unsigned status = 0, i;
    struct diskinfo_t di;
    struct diskfree_t df;
    unsigned char _far *p, linebuf[17];

    if( argc != 5 )
    {
       printf("  SYNTAX: DISK <driveletter> <head> <track> <sector>");
       exit( 1 );
    }

    if( (di.drive = toupper( argv[1][0] ) - 'A' ) > 1 )
    {
       printf( "Must be floppy drive" );
       exit( 1 );
    }

    di.head   = atoi( argv[2] );
    di.track   = atoi( argv[3] );
    di.sector   = atoi( argv[4] );
    di.nsectors = 1;
    di.buffer   = diskbuf;

    // Get information about disk size.

    if( _dos_getdiskfree( di.drive + 1, &df ) )
       exit( 1 );

    // Try reading disk three times before giving up.

    for( count = 1; count <= 3; count++ )
    {
       status = _bios_disk( _DISK_READ, &di ) >> 8;
       if( !status )
          break;
    }

    // Display one sector.
    if( status )
       printf( "Error: 0x%.2x\n", status );
    else
    {
       for(p=diskbuf, i=0; p < (diskbuf+df.bytes_per_sector); p++)
       {
          linebuf[i++] = (*p > 32) ? *p : '.';
          printf( "%.2x ", *p );
          if( i == 16 )
          {
             linebuf[i] = '\0';
             printf( " %16s\n", linebuf );
             i = 0;
          }
       }
    }

    // Which attempt was successful?

    printf( "\nThat was try #%d.\n", count );

    exit( 1 );
 }


 598. C Compiler May Give Wrong Line Number for a C2125 Error

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69538

 The C compiler will correctly produce a "C2125: allocation exceeds
 64K" error for an array larger than 64K that is not declared as huge
 or compiled for the huge memory model. However, the line number that
 the compiler displays for the error is incorrect. The sample program
 below demonstrates this problem.

 The following error message shows the incorrect line number generated
 when the sample code below is compiled with C version 5.10, 6.00, or
 6.00a:

    file.c(7) : error C2125: 'array' : allocation exceeds 64K

 The error is actually generated because of the array declaration on
 line 4, but the compiler always lists the line with the opening brace
 for the main() function as the location of the error (line 7 in this
 case).

 When the quick compile (/qc) option is specified under C 6.00 or
 6.00a, the correct line number (line 4) is generated in the error
 message:

    test.c(4) : error C2125: 'array' : allocation exceeds 64K

 Note that if you are compiling inside the Programmer's WorkBench
 (PWB), the incorrect line number in the error message will cause PWB
 to take you to an incorrect line in the source code when the compiler
 errors are displayed.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.

 Sample Code
 -----------

 /* Compile options needed: none
 */

 char array[100000];  /* Error should be generated for this line (4) */

 void main(void)
 {                    /* Error message refers to this line (7) */
 }


 599. _cexit() Does Not Close Files Correctly

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc buglist6.00 buglist6.00a
 Last Modified: 25-FEB-1991    ArticleIdent: Q69539

 As stated in the online help, the _cexit() function performs clean-up
 operations and returns without terminating the process. The _cexit()
 function first calls the functions registered by the atexit() and
 onexit() routines, and then it should flush all I/O buffers and close
 all open files before returning.

 The _cexit() function works as described except that it does not close
 all the open files. The sample code below demonstrates this problem.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 *\

 #include<stdio.h>
 #include<stdlib.h>
 #include<process.h>

 void foo(void);

 void main(void)
 {
     FILE *outfile;
     int   retval;

     atexit(foo);    /* set up function to invoke on exit */

     if ( (outfile = fopen("TEST.TXT", "w")) == NULL )
         {
         printf("Could not open test file TEST.TXT");
         exit(-1);
         }

     retval = fprintf(outfile, "This is line 1.\n");
     if ( retval >= 0 )
         printf("\nFirst line written successfully to file.\n");
     else
         printf("\nFile write failed on first attempt!\n");

     _cexit();   /* Call _cexit() -- files should all be closed */

     retval = fprintf(outfile, "This line should not be written!\n");
     if ( retval >= 0 )
         printf("Error - Write to file succeeded for file that should"
                " have been closed!\n");
     else
         printf("File write failed on second attempt as expected!\n");

     fclose(outfile);
 }

 void foo(void)
 {
     printf("\nThis is the exit function code.\n\n");
 }


 600. Local Variable Allocation Is Limited to 32K

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                    | OS/2
 Flags: ENDUSER | s_quickc stack
 Last Modified: 15-JAN-1991    ArticleIdent: Q19785

 The total amount of space that can be allocated for variables local to
 a function is 32K. Trying to allocate more than this will result in
 the following compiler error:

    fatal error C1126: automatic allocation exceeds 32K


 601. GRAPHICS.LIB Cannot Be Used with Tiny Model

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified:  6-FEB-1991    ArticleIdent: Q67761

 Programs written in the tiny model cannot use the graphics library
 supplied with Microsoft C versions 6.00 and 6.00a. The graphics
 routines are meant to be model-independent, so they are labeled as far
 procedures. The linker does not allow far references in a tiny model
 program and does not resolve the references to the graphics routines.

 The sample source code below demonstrates this problem. The program
 should be compiled with:

    cl /AT foo.c graphics.lib

 For more information on building .COM files, query on the article
 titled "Use of _far Keyword in Tiny Programs."

 Sample Code
 -----------

 #include <graph.h>

 void main(void);

 void main()
 {
    _setvideomode(_DEFAULTMODE);
 }


 602. C1001: Internal Compiler Error: regMD.c, Line 1017

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 28-DEC-1990    ArticleIdent: Q67778

 When compiling with /Oe optimization under the compact or large memory
 models, the code below generates the following internal compiler error
 with Microsoft C version 6.00a:

    fatal error c1001: Internal Compiler Error
         (compiler file '@(#)regMD.c:1.110',line 1017)
         Contact Microsoft Product Support Services

 Sample Code
 -----------

     char hex_digits[]={"f"};

     int x(char *resultp, int item)
     {
         char *s;
         int hundreds;

         s=resultp;
         hundreds=100;
         if(hundreds)
           *s++='0';
         *s++=' ';
         *s++=hex_digits[item/16];
         *s++=hex_digits[item%16];
     }

 The following are valid workarounds for the problem:

 1. Compile without the /Oe optimization.

 2. Use the #pragma optimize switch in the code to turn off the
    offending optimizations for the particular function.

 3. Compile under the small or medium memory models.


 603. Jumping into the Middle of a For Loop Is Not Recommended

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q19972

 Question:

 Under what conditions can a program perform a jump (via goto) into the
 middle of a for loop?

 Response:

 The only restriction on the goto statement is that the goto statement
 and its corresponding label be located in the same function. However,
 because different compilers optimize for loops differently, using a
 goto to jump into the middle of a for loop is not considered safe or
 portable.

 Also, if you are jumping into an inner loop that uses auto variables,
 an additional problem may occur because different compilers allocate
 space for auto variables in loops in different ways.

 Essentially, it is risky and not advisable for a program to jump into
 the middle of a for loop.


 604. No More Than 255 Modules May Be Placed in Overlays

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |  s_quickc s_link
 Last Modified: 15-JAN-1991    ArticleIdent: Q22286

 Question:

 The "too many overlays" error message indicates that my program
 defines more than 63 overlays. Is there also a limitation on the
 number of total modules that can be in overlays?

 I have a large C program that contains more than 255 modules in a
 total of 12 overlays. I receive no error messages, however, my link
 map indicates that all modules after the 255th are placed in the root
 instead of the overlays I specified.

 Response:

 There is a limit of 255 code segments that can be overlayed. Segments
 beyond this limit are put in the root.


 605. The Most Common C Programming Errors

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q22321

 The following is a list of the most common C programming errors. Any
 of these items could cause unpredictable results, such as trashed data
 or a system hang.

  1. Using auto variables that have not been initialized.

  2. Leaving out the closing comment delimiter.

  3. Over-indexing an array.

  4. Leaving out a semicolon (;) or brace ({}).

  5. Using uninitialized pointers.

  6. Using break with an IF block, since break does not exit out of IF
     blocks. It only breaks you out of WHILE, FOR, or SWITCH loops.

  7. Comparing a char variable against EOF, as in the following
     example:

        char c;
        while ((c=getchar()) != EOF)
            {
            }

     If c is a char, you cannot test c against EOF because a -1 cannot
     fit into a character, so c must be an int.

  8. Using a forward slash instead of a backslash (for example, /n
     instead of \n).

  9. Using = instead of == in a comparison.

 10. Overwriting the null terminator (the last byte) in a string by
     indexing 1 byte too far.

 11. Placing a semicolon improperly, as in the following example:

        void foo(int a,char b);   /* semicolon does not belong here */
        {  }

 12. Forgetting that scanf() expects addresses.

 13. Using the wrong return value for a function. For example, a
     function that returns a real, but is not declared, will return an
     int by default.

 14. Using expressions with side effects. For example, a[i] = i++; is
     ambiguous.

 15. Forgetting that static variables inside functions are initialized
     only once.

 16. Unintentionally omitting a break from a case label in a switch
     statement, and therefore, falling through to the next case.


 606. Internal Representation for NAN or INF Is Coprocessor Specific

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | 8087 80x87 80287 80387
 Last Modified: 15-JAN-1991    ArticleIdent: Q22320

 The internal representation for a NAN (Not A Number) or INF (Infinity)
 is coprocessor dependent. To obtain this information, we recommend
 that you consult the "Numeric Supplement" in the "Intel iAPX
 Programmer's Reference Manual" for the specific coprocessor chip.


 607. "Invalid Object Module" Usually Caused by Old Version of LINK

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  4-DEC-1990    ArticleIdent: Q22331

 In many cases, an "invalid object module" error message from the
 linker indicates that an incorrect version of LINK is being utilized.
 Most DOS systems contain a DOS directory listed near the beginning of
 the PATH. Because DOS ships with a version of LINK, this version is
 often picked up instead of the correct version.

 To indicate if the wrong linker is the source of an "invalid object
 module" error, perform the following steps:

 1. Change into the language product directory where the version of
    LINK.EXE that came with the compiler you are currently using
    resides.

 2. Type "link" at the DOS prompt.

 3. The copyright banner for LINK will appear. Note the version number
    of LINK that is indicated. (This is the correct version of LINK
    that you should be using.)

 4. Press CTRL+C to exit out of LINK.

 5. Switch to the work directory where you normally compile and link
    your program.

 6. Perform steps 2 through 4 again.

 If the version of LINK that comes up in your work directory is
 different than the correct version you first noted in the language
 directory, then you have another version of LINK in a directory in
 your PATH that comes before the directory with the correct version.

 If you do find that you are picking up another LINK.EXE on your
 system, you will need to determine where it resides. Most likely, it
 is a DOS linker that came with the operating system because these are
 older versions of LINK that are not well-matched to the newer language
 products. Be aware, however, that it also could be the linker from
 another Microsoft language product. In either case, you should do one
 of the following to correct this problem:

 1. Locate the old linker and rename it to something resembling LINK.OLD.
    It is rare that you would need the DOS linker for anything, but this
    method assures that it will still be available.

 2. Change your path so that your PATH environment variable points
    first to the directory containing the correct version of LINK.EXE.
    This solution is less preferable than the one above because it does
    nothing to ensure that the problem will not appear again if you make
    some changes to your system.

 It is not uncommon to have a number of linkers in directories that are
 specified in the PATH. Therefore, it is highly recommended that you
 repeat the version number test from within your work directory once
 you have implemented one of these solutions.


 608. C1001: Internal Compiler Error: regMD.c, Lines 3047 and 3020

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q67779

 The sample code below produces the following internal compiler errors
 when compiled under different versions of the C compiler. The problem
 occurs when compiled with the /Og and /Oe optimizations under the
 compact and large memory models.

 Under C 6.00a
 -------------

    file.c(11) : fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)regMD.c:1.110', line 3047)
                       Contact Microsoft Product Support Services

 Under C 6.00
 ------------

    file.c(11) : fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)regMD.c:1.110', line 3020)
                       Contact Microsoft Product Support Services

 The following are valid workarounds for the problem:

 1. Compile without the /Oe or /Og optimizations.

 2. Use the #pragma optimize switch in the code to turn off the
    offending optimizations for the particular function.

 3. Compile under the small or medium memory models.

 Sample Code
 -----------

 #include<string.h>

 void foo (void)
 {
     char *o, *wp, *cp;
     int c,t;

     for (;;)
     {
         wp++;
         t = wp - cp;
         if (c) t=0;
         if (t) strncpy (&o[c], cp, t );
         c = t;
         cp = wp;
     }
 }


 609. /MT Cannot Be Mixed with /FPa As Shown on Page 370 of APT

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  6-FEB-1991    ArticleIdent: Q67782

 Page 370 of the "Advanced Programming Techniques" manual shipped with
 Microsoft C version 6.00 incorrectly gives an example of combining the
 command-line switches /MT and /FPa. This procedure does not work and
 will cause the compiler to generate the following error message:

    Command Line Error D2016: '-MT' and '-FPa' are incompatible

 To use the alternate math libraries, you must either create a single
 threaded .EXE or a multithreaded DLL. The libraries to create a
 multithreaded .EXE are not available.


 610. C1001: Internal Compiler Error: regMD.c, Lines 4634 and 4688

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q67783

 When compiled with /Oe and /MD, the sample code generates an internal
 compiler error for Microsoft C Compiler versions 6.00 and C 6.00a. The
 errors are different for each version.

 Under C 6.00
 ------------

    fatal error c1001: Internal Compiler Error
    (compiler file '@(#)regMD.c:1.110',line 4634)

 Under C 6.00a
 -------------

    fatal error c1001: Internal Compiler Error
    (compiler file '@(#)regMD.c:1.110',line 4688)

 Sample Code
 -----------

 char wi_lines(char);

 int w_hline(char *pnt)
 {
    int x;
    for (x=0;x<=10;x++)
    pnt[x]=wi_lines(pnt[x]);
 }


 611. C 6.00/6.00a May Incorrectly Generate C4009 Warning with /Zg

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q67784

 When compiling with the "/Zg" option in C version 6.00 or 6.00a, a
 C4009 (string too big, trailing characters truncated) warning error
 may be incorrectly flagged. In the sample code below, a local array of
 strings of total size greater than 2K will generate the warning. If
 the array is made global or the total size is less than 2K, the
 warning is not generated.

 Sample Code
 -----------

 void main(void) { }

 int test(void) {

 char * test_array[3][35] = {
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 "xxxxxxxxxxxxxxxxxxxx","yyyyyyyyyyyyyyyyyyy","zzzzzzzzzzzzzzzzzzzz"
 };

 }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 612. Bit Operations on Char May Produce Unexpected Results

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified:  6-FEB-1991    ArticleIdent: Q67785

 Bit manipulations on type char may produce different results depending
 on the compiler switches. The /J and /qc switches have different
 effects on the code below when using the Microsoft C versions 6.00 and
 6.00a compiler.

 Sample Code
 -----------

 #include <stdio.h>

 char unsigned ary[4] = {0xF6, 0xF7, 0xF8, 0xF9};

 void main(void)
 {
    unsigned long result1, result2;
    char *p;
    p = ary;
    result1 = *p | ( *(p+2) << 8);
    result1 += ( *(p+1) | ( *(p+3) << 8)) * 0x10000;
    result2 = (unsigned long)(( *(p+2) << 8) | *p) |
              (unsigned long)(( *(p+3) << 8) | *(p+1)) << 16;
    printf("result1 = %lX\n", result1);
    printf("result2 = %lX\n", result2);
 }

 When compiled with

    cl /qc /J foo.c

 the results are:

    result1 = F9F7F8F6
    result2 = F9F7F8F6

 When compiled with

    cl /J foo.c

 the results are:

    result1 = F9F6F8F6
    result2 = FFFFF8F6

 When compiled with

    cl /qc foo.c
 or
    cl foo.c

 the results are:

    result1 = FFF6FFF6
    result2 = FFFFFFF6

 The differences occur because of a problem in the Quick Compiler. When
 an integral promotion is required, the Quick Compiler incorrectly
 converts an unsigned char to an unsigned int. According to ANSI, if
 all the values of a char can be represented in an int, it is converted
 to an int; otherwise, it is converted to an unsigned int (see section
 3.2.1.1). This is also documented in the "Advanced Programming
 Techniques" manual on page 422.

 There are a number of ways to work around this problem depending on
 the desired results. If the intent was to generate results equal to
 F9F7F8F6 (as the Quick Compiler with /J did), declare "p" as a pointer
 to an unsigned char and modify the equations for "result1" and
 "result2" to use unsigned int casts where appropriate. For example:

    result1 = *p | ((unsigned int)*(p+2) << 8);
    result1 += ( *(p+1) | ( *(p+3) << 8)) * 0x10000;

 -or-

    result2 = ((unsigned long)(((unsigned int)*(p+2) << 8) | *p)|
              (unsigned long)(( *(p+3) << 8) | *(p+1)) << 16;

 If the results from the full optimizing compiler with /J are desired,
 again declare "p" as a pointer to unsigned char and replace the above
 mentioned casts with signed int. Finally, if the results without /J
 are desired, declare "p" as a pointer to a signed char.

 Microsoft has confirmed this to be a problem in the Microsoft C
 Compiler versions 6.00 and 6.00a. We are researching this problem and
 will post new information here as it becomes available.


 613. Code Generation Error with C 6.00 and Global Variables

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q67786

 The sample program below does not compile properly when using any
 optimizations other than /Od under C versions 6.00 and 6.00a. The code
 generated by the compiler incorrectly assumes that foo and bar are
 equal after the call to the function inc_foo. The compiler then
 accesses bar[1] by using the value of foo rather than the value of
 bar. This generates the wrong effect on the array being modified.

 There are several workarounds:

 1. Use the /Od option or the /qc option.

 2. Declare foo as a volatile pointer to a char.

 3. Change the code to assign buf to bar first.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 #include <stdio.h>
 char inc_foo (void);

 char * foo;
 char * bar;
 char * buf = "....................";

 main ()
 {
    foo= buf;
    bar= buf;
    bar[1]= inc_foo ();
    printf ("buf = %s\n", buf);
    printf ("foo = %d\nbar = %d\n", foo, bar);
 }

 char inc_foo ()
 {
    foo += 10;
    return (char) '[';
 }

 The correct output is:

 buf = .[..................
 foo = 76
 bar = 66

 The output generated is:

 buf = ...........[........
 foo = 76
 bar = 66


 614. %n Format Specifier May Be Ignored in C 6.00 sscanf()

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q67790

 If the "%n" format specifier is used within a sscanf() function and
 the format specifier before it causes the last character to be read
 from the string of data, the %n will be ignored and the sscanf()
 function will return without making the %n assignment. This is correct
 per ANSI specifications, since an input failure before the %n
 parameter is evaluated.

 The code below demonstrates the problem. Notice that the last
 parameter passed (d) does not get changed. The sscanf() statement
 finishes making assignments as soon as it reaches the end of the
 string.

 Sample Code
 -----------

 #include <stdio.h>

 void main(void)
 {
    int a,b,c,d;
    char buffer[50];
    a=b=c=d=0;

    sscanf("100Dummy2","%n%d%n%s%n",&a,&b,&c,buffer,&d);

    printf("%d  %d  %d\n",a,c,d);
 }

 Output
 ------

 0  3  0


 615. C and QuickC Compiler Options Should Be Placed Before .C File

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  4-DEC-1990    ArticleIdent: Q23739

 The C and QuickC compiler switches must be specified on the command-
 line, before any source files that the option is intended to apply to.
 In most cases, specifying options at the end of the command-line after
 a filename will NOT generate any warnings or errors -- the compiler
 will ignore the options because there are no following source files
 that the options apply to.

 In a few cases, a trailing option at the end of the command-line will
 generate an error if the option conflicts with a previously specified
 option.


 616. Effects of Min and Max Memory Allocation During C Program Load

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_link s_exemod s_exehdr
 Last Modified:  6-FEB-1991    ArticleIdent: Q24935

 Changing the minimum and maximum allocation values in an .EXE file
 will affect the way in which memory is allocated for a program.

 Memory is dynamically allocated for a program when it is loaded. DOS
 initially attempts to allocate FFFFH paragraphs memory. This will
 always fail, returning the size of the largest free block. If this
 block is smaller than the minimum allocation and the load size, a
 no-memory error will occur. If this block is larger than the sum of
 the maximum allocation and the load size, DOS will allocate the amount
 specified by the load size and the maximum allocation. Otherwise, the
 largest block of memory available is allocated.

 An example of when the maximum allocation should be changed would be a
 program, such as a menu driver, that spawns other programs. Since this
 program would stay resident in memory, the maximum allocation should
 be set to the minimum allocation to keep as much memory available as
 possible for the spawned programs.

 In small memory model, the C start-up code will return all memory
 allocated to it back to DOS, except for a 64K block reserved for the
 default data group. If only 4K of this 64K will be used by the menu
 program, the entire 64K should not be kept. There are several ways of
 changing the maximum allocation to 4K -- you can link with the /CP:1
 option or you can modify an existing .EXE file with the EXEHDR or
 EXEMOD utilities.


 617. fseek() Function Requires a long for the Offset into a File

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q23753

 Question:

 I am using fseek() to seek in a file, but it fails when I try to seek
 beyond 32K. Is this a limit of fseek()?

 Response:

 The offset parameter to fseek() takes a value of type long, so this
 problem is not likely to be the result of fseek() limits. On the other
 hand, this situation does occur if you are using variables of type int
 to calculate the offset. Because an int is limited to a maximum value
 of 32,767 (32K), values assigned to ints between 32K and 64K are
 treated as negative.

 An int will be automatically typecast to a long when passed to fseek()
 but when this occurs, it is sign-extended. Thus, an int value above
 32K that is represented as negative will be sign-extended to a
 negative long. This, in turn, specifies a negative offset into the
 file, which fails to produce the expected results.

 When using the fseek() routine, just be sure to use a long for
 specifying the offset into the file.


 618. Difference Between Minimum Load Size and Minimum Allocation

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_link s_exehdr s_exemod
 Last Modified:  6-FEB-1991    ArticleIdent: Q25024

 The following is a summation of the differences between the minimum
 load size and the minimum allocation size in a DOS executable (.EXE)
 file header:

 The minimum load size is the amount of memory needed for the load
 module, plus the minimum allocation value. This reflects the amount of
 memory necessary to load and run the program, assuming no dynamic
 allocation is necessary.

 The minimum allocation is the amount of memory needed above the actual
 load module. These values determine the highest memory location into
 which the program can be loaded. For example, if the minimum load size
 is 0, the program will be loaded at the highest possible location in
 memory.


 619. Sending 1Ah to a Printer Requires Setting "Raw" Mode

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-FEB-1991    ArticleIdent: Q23867

 Problem:

 I am trying to output a graphics file to a printer. I have opened the
 printer as a binary file, but the output stops every time I try to
 output hexadecimal character 1A. I assumed that anything could be
 output to a binary file.

 Response:

 If you open a device, such as PRN, as a binary file using fopen() or
 open(), the device will not translate carriage return/line feed
 combinations. However, DOS will continue to interpret CTRL+Z (1Ah) as
 an end-of-file character.

 You must use interrupt 21h function 44h to set the raw-mode bit for
 the device to disable checking for CTRL+Z characters. This way, all
 characters will be allowed to pass.

 The following example was taken from page 351 of "Advanced MS-DOS
 Programming," which gives an assembly language program example for
 setting raw mode.

 Sample Code
 -----------

 void setrawmode(void)
 {
    union REGS inregs, outregs;

    inregs.x.ax = 0x4400;
    inregs.x.bx = 0x04;         /* specify the printer */
    int86(0x21, &inregs, &outregs);

    outregs.h.dh = 0x00;
    outregs.h.dl = 0x20;        /* set raw mode bit */
    outregs.x.ax = 0x4401;
    int86(0x21, &outregs, &inregs);
 }


 620. How to Do "Peeks" and "Pokes" in a C Program

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q23868

 The sample code below contains two functions that simulate what are
 commonly known as "peek" and "poke" functions. The peek() function
 allows you to look at the contents of any memory location while the
 poke() function allows you to place a value into any memory location.

 Sample Code
 -----------

 /* The following function will stuff a value into any location in
    addressable memory. seg:ofs = val.
 */

 void poke(unsigned int seg, unsigned int ofs, char val)
 {
     unsigned char far *ptr;

     ptr = (unsigned char far *) (((long)seg<<16)|(long)ofs);
     *ptr = val;
 }

 /* The following function will return the contents of any location in
    addressable memory. return(seg:ofs).
 */

 unsigned char peek(unsigned int seg, unsigned int ofs)
 {
     unsigned char far *ptr;

     ptr = (unsigned char far *) (((long)seg<<16)|(long)ofs);
     return(*ptr);
 }


 621. malloc() and free() Do Not Return Memory to DOS

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q23869

 Problem:

 My large model program calls system() to do a directory, and then I
 malloc() a large amount of space. I can free() it all but I get a "Not
 enough memory" error when I try to call system() again. Apparently
 free() is not returning the memory to DOS.

 Response:

 When you malloc() a large amount of space (more than is available
 within the current heap), the malloc() function will execute a DOS
 call to get more memory in an attempt to expand the heap. If this is
 successful, DOS will allocate the desired memory to your program and
 malloc() will return successful. If you then free() this memory, it
 will be marked as free within your program's heap and will be
 available for use again by your program.

 However, DOS still sees this memory as being used by the program
 because it now resides within the program's heap. If you attempt a
 subsequent system() call, DOS may find it does not have enough free
 memory to load the code required to perform the system() function.

 An alternative is to use halloc() and hfree(), which will return the
 memory to DOS, rather than retaining it for use by the currently
 executing program.


 622. C 6.00a CD-ROM Setup Does Not Install RAMDRIVE or SMARTDRV

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q67847

 When Setup is run from the CD-ROM version of Microsoft C version
 6.00a, the following two files are not found along the specified path:

    \HD525\DISK7\RAMDRIVE.SYS
    \HD525\DISK7\SMARTDRV.SYS

 The two files are included in this path:

    \HD525\DISK6\RAMDRIVE.SYS
    \HD525\DISK6\SMARTDRV.SYS

 Since the files are not compressed, they can be copied to your hard
 drive.

 Microsoft has confirmed this to be a problem in the C version 6.00a
 CD-ROM Setup program. We are researching this problem and will post
 new information here as it becomes available.


 623. .EXE Header Must Be Marked for OS/2 Long Filename Support

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | s_exehdr
 Last Modified:  1-FEB-1991    ArticleIdent: Q67878

 Applications using long filenames and extended file attributes are
 supported under OS/2 versions 1.20 and later running the high
 performance file system (HPFS); however, a bit in the executable file
 must be set to tell OS/2 that the executable file supports long
 filenames.

 The following lists two possible methods to specify that the
 application supports long filenames:

 1. Modify the executable file using the EXEHDR utility:

       EXEHDR /NEWFILES test.exe

 2. Link with a module definition file containing the following line
    specifying the optional attribute <NEWFILES>:

       NAME [appname] [apptype] NEWFILES


 624. R6002 "Floating Point Not Loaded" May Result from printf() Use

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  4-DEC-1990    ArticleIdent: Q23873

 Question:

 I have a simple program that prints out some numbers. Every time I try
 to run the program, I get the error message "R6002: Floating point
 support not loaded." Why do I get this error when I don't have any
 floats in my program?

 Response:

 You most likely have a printf() statement in your program that
 contains a floating point format specifier, such as %f in the format
 string. At link time, the floating-point library modules will not be
 loaded unless floats are declared. This saves space by making the
 executable file smaller. However, in this case the program will
 encounter this floating-point format specifier at run time and will
 generate the above error because the floating-point handling routines
 are needed by the printf() call.

 To work around this problem, just declare and initialize a floating
 point variable in your program. This will force the floating point
 support to be linked into the .EXE file.


 625. Scanf() Format Specifications and Syntax

 Product Version(s): 6.00a 6.00 | 6.00a 6.00
 Operating System:   MS-DOS     |  OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 31-JAN-1991    ArticleIdent: Q67879

 The scanf() format specifiers allowed for strings are usually
 specified with the %s format. However, %s is a shortened version of
 what is actually being used. Because %s reads until the first white
 space, %[^\0x20\t\n] is equivalent. This reads as "read in the string
 until encountering a space (\0x20), a tab (\t), or a newline (\n)."

 The following are some examples of different uses for the string type:

    String          Usage
    ------          -----

    %[a-z]          Reads a string until it does not encounter a
                    letter in "abc...z".
    %[^a-z]         Reads a string until it encounters a letter
                    in "abc...z".
    %[]]            According to ANSI, this will read until it
                    does not encounter a "]".
    %[^]]           Reads a string until it encounters a "]".
    %*[^%]          Scans a string (does not buffer it) until it
                    reaches a "%".

    Note: The "*" tells the compiler to scan the string and not read it
    into the buffer.

    %[-af-k]        Reads a string until it does not encounter a
                    "-", "a", or "f-k" (fgh...k).
    %[]             Not legal -- unpredictable results.
    %[^]            Not legal -- unpredictable results.

    Note: Because scanf() receives a string as a parameter, this is not
    caught by the compiler as an error.

    %40c            Reads in 40 characters to the string.

    Note: A null character is not appended automatically in this case.
    Also, this does not automatically end scanf() execution after the
    40th character is read in. Because this is buffered input, a
    carriage return must be entered to cause the string scan to
    complete. If a carriage return is entered within the 40 character
    string, it will be displayed normally, but will continue to prompt
    for more input until all 40 characters have been read.

      %[^.-]          Reads a string until it encounters a "." or a
                      "-".


 626. Error C2213 Occurs When Base Is an Expression

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 16-JAN-1991    ArticleIdent: Q67882

 The following are new to C 6.00:

    _based
    _segment

 Variables of type _segment are defined to hold a memory segment
 address.

 With based variables, you name a base to specify where the data
 resides. The base can be of type _segment, or be a near or a far
 pointer. However, if the base is an expression, even of one of the
 types listed above, the following error is produced:

    error C2213: illegal argument to _based

 Microsoft has confirmed that this is a restriction, although it is not
 documented as such.

 The following examples illustrate the restriction:

 This declaration is valid:

    _segment foo;
    char _based( foo ) *cptr;

 The following declaration

    struct sample
    {
        _segment foo;
    }rec;
    char _based( rec.foo ) *cptr;

 produces the following error:

    error C2213: 'rec': illegal argument to _based
    error C2059: syntax error: '.'

 The following declaration

    _segment array[10];
    char _based( array[0] ) *cptr;

 produces the following error:

    error C2059: syntax error: '['


 627. C1001: Internal Compiler Error: mactab.c:1.70, Line 482

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68073

 The sample code below produces the following internal compiler error
 when compiled with both the /Ol and /Oe optimizations. This error
 occurs when compiled under the compact and large memory models of C
 6.00a and under all memory models except the huge model of C 6.00.

    test.c(9) : fatal error C1001: Internal Compiler Error
                   (compiler file '@(#)mactab.c:1.70', line 482)
                    Contact Microsoft Product Support Services

 Disabling either of the offending optimizations will correct this
 error.

 Microsoft has confirmed this to be a problem in Microsoft C version
 6.00 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.

 Sample Code
 -----------

 void goo(int);

 void foo(void)
 {
    int high, low=0, mid, len, * word;

    while (mid)
    {
       mid=low+high;
       len=word[mid+1]-word[mid];
       if(len) while(mid) goo(len);
       else low=5 ;
    }
 }


 628. Stringize Operator Fails to Insert Backslashes

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist 5.10 buglist6.00 buglist6.00a s_quickc
 Last Modified: 31-JAN-1991    ArticleIdent: Q68143

 The stringizing operator is used only with the arguments of macros. If
 a # precedes a formal parameter in the definition of a macro, the
 actual argument is enclosed in double quotation marks and treated as a
 string when the macro is expanded.

 If the argument contains characters that normally must be preceded by
 a backslash (\) when appearing in a string (such as " or \), the
 backslash should be automatically inserted. However, there are many
 cases where the preprocessor fails to do this.

 Below are some sample macros that use the stringize operator. They are
 followed by a line showing the incorrect preprocessor output
 (compiling with /P) and the output that was expected.

 Sample Code
 -----------

 Example 1:

     #define print_filename(x) printf(#x);

     main()
     {
      print_filename(d:\test\sscanf.c)
     }

 Preprocessor Output:

    printf("d:\test\sscanf.c");

 Expected Output:

    printf("d:\\test\\sscanf.c");

 Example 2:

     #define print_filename(x) printf(#x);

     main()
     {
        print_filename(This: \" prints an escaped double quote mark)
     }

 Preprocessor Output:

    printf("This: \\" prints an escaped double quote mark")

 Expected Output:

    printf("This: \\\" prints an escaped double quote mark")

 Example 3:

     #define print_stuff(x) printf(#x);

     main()
     {
        print_stuff(I am printing a quote: ")
     }

 Preprocessor Output:

    error C2001: newline in constant
    fatal error C1057: unexpected end-of-file in macro
                               expansion (missing ')'?)

 Expected Output:

    printf("I am printing a quote: \"");

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 629. Too Much Data or Mixing Memory Models Causes "Fixup Overflow"

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q23903

 Question:

 My large model program compiles fine, but I can't link. At that link
 time, I get an L2002 error, "Fixup Overflow." What does this error
 mean and how can I work around it?

 Response:

 This error occurs when a group is larger than 64K. The first suspect
 for such a problem is DGROUP, into which goes the stack, the near
 heap, and all near data. This can exceed 64K if you have a large
 amount of static or global data initialized by the compiler. This
 problem can be avoided by doing the following:

 1. Explicitly force certain items into segments of their own.

 2. Use the far keyword.

 3. Specify the /Gt compiler option. This places all such data items
    larger than a given size into their own segments.

 If you are trying to mix memory models by applying the near keyword to
 a function used by another module, the code for the function and the
 call will be placed in different segments. A fixup error will occur if
 the segment containing the near address comes before the segment using
 it, or if it is more than 64K away from the start of the segment.
 Removing the near keyword will correct the problem in this case.


 630. Creating Pointers to Specific Addresses in Memory

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q23977

 Accessing specific addresses in memory in Microsoft C can be easily
 accomplished by using the FP_SEG and FP_OFF macros or by creating a
 far pointer directly from a long.

 The FP_SEG and FP_OFF macros are defined in DOS.H, and can be used to
 set or get the segment and offset of a far pointer.

 The following example shows how FP_SEG and FP_OFF could be used to
 create a pointer for directly accessing video memory:

    char far *p;
    FP_SEG(p) = 0xb800;   /* point to segment of video memory */
    FP_OFF(p) = 0;        /* set offset to first screen position */

 See the C run-time library documentation or online help supplied with
 your compiler for more information on FP_SEG and FP_OFF.

 You can also access a specific address in memory by casting a long to
 a far pointer, as in the following example:

    p = (char far *) 0xb8000000L;   /* video memory again */

 When converting a pointer to or from a long, the upper 16 bits hold
 the segment and the lower 16 bits hold the offset.


 631. C1001: Internal Compiler Error: regMD.c, Line 725

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 11-JAN-1991    ArticleIdent: Q68144

 The sample code below produces the following internal compiler error
 when compiled with both global register allocation (/Oe) optimization
 and SS!=DS (/Au or /Aw) options:

    cl /c /Alfu /Oe t.c

    t.c(19) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)regMD.c:1.110', line 725)
                    Contact Microsoft Product Support Services

 The following are three valid workarounds:

 1. Compile without /Oe optimization.

 2. Use the optimize pragma to turn off /Oe optimization for the
    function in which the error is occurring. For example, uncomment lines
    2 and 21 below to eliminate the error.

 3. Compile with the /qc (Quick Compile) option.

 Sample Code
 -----------

 1:  void func1 (struct tag1 *);
 2:  void func2 (struct tag3 _near *hoo, int boo );
 3:
 4:  struct tag3{
 5:          struct tag2 {
 6:                  int Active_Task_Count, Fd;
 7:                  struct tag1 {
 8:                          int i;
 9:                  } moo;
 10:          } Task_Vars[3];
 11:  };
 12: // #pragma optimize("e", off)
 13:  void func3 (struct tag3 _near *hoo, int boo )
 14:  {
 15:     struct tag2 _near *Task_Ptr;
 16:
 17:          Task_Ptr = &hoo->Task_Vars[boo];
 18:          func1(&Task_Ptr->moo);
 19:          if(Task_Ptr->Fd) func2(hoo, boo);
 20:  }
 21: // #pragma optimize("e", on)

 Microsoft has confirmed this to be a problem in C version 6.00a. We
 are researching this problem and will post new information here as it
 becomes available.


 632. C1001: Internal Compiler Error: grammar.c, Line 164

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a fastcall
 Last Modified: 24-JAN-1991    ArticleIdent: Q68145

 The sample code below produces the following internal compiler error
 when compiled with default optimizations:

    cl /c /Gs t.c

    t.c(10) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)grammar.c:1.138', line 164)
                    Contact Microsoft Product Support Services

 The following is a list of possible workarounds:

 1. Turn off all optimizations (compile with /Od).

 2. Remove the _fastcall keyword from the function declaration.

 3. Reduce the complex expression by using temporary variables.

 4. Compile with the /qc (Quick Compile) option.

 Sample Code
 -----------

 1: #include<math.h>
 2:
 3: double _fastcall round(void)
 4: {
 5:     char *decimal;
 6:     double sign;
 7:     int right;
 8:
 9:     right=(int)(((int)(atof(decimal)+1.0))*1.0);
 10:    return (sign*(1.0+((double)right)));
 11:}

 Microsoft has confirmed this to be a problem in C version 6.00a. We
 are researching this problem and will post new information here as it
 becomes available.


 633. Signed Is Converted to unsigned in Comparison with unsigned

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  1-FEB-1991    ArticleIdent: Q68265

 The additional adherence to the ANSI standard beginning with C
 versions 6.00 and 6.00a and QuickC versions 2.50 and 2.51 will cause a
 negative signed integer to be converted to an unsigned integer in a
 comparison. This is the correct and intended behavior, although it may
 produce results that are unexpected. The sample code below
 demonstrates this behavior.

 This is new in C 6.00 and is documented in "Microsoft C Advanced
 Programming Techniques" on page 422, section B.1.2. The following
 program will produce warning C4018 "signed/unsigned mismatch" at
 warning level 3 or 4. Casting of the variables will preserve their
 relationship in the expression.

 Sample Code
 -----------

 #include <stdio.h>

 void main( void)
 {
    int a = -1;
    unsigned b = 1;

    if ( b < a )
       printf( "Signed was converted to unsigned\n");
    else
       printf( "Sign was preserved\n");
 }

 The output from the program above will be:

    Signed was converted to unsigned

 Either of the following methods may be used to achieve the expected
 behavior:

 1. If you are sure that b is less than 32768, change the if statement
    to:

       if ( (signed int) b <  a)

    Note: This will produce the most efficient code.

 2. Change the if statement to:

       if ( (long) b < (long) a)


 634. ftell() May Return an Invalid Value with a Text File

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | s_quickc buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 11-FEB-1991    ArticleIdent: Q68337

 When ftell() is used on a file opened in text mode that contains only
 line feeds (0x0A) with no carriage returns (0x0D), it may return an
 incorrect value on the first call, causing all subsequent return
 values to be wrong as well. Opening the file in binary mode will
 eliminate this problem.

 Sample Code
 -----------

 #include <stdio.h>

 void main( void)
 {
    FILE *ptr;
    char a[80];
    fpos_t offset;

    ptr = fopen( "foo", "r" );    /* foo contains 12 lines of 40 chars
                                    each with line feeds only */
    fgets( a, 79, ptr );          /* positions (or should position)
                                    the file pointer at an offset of 41 */
    offset = ftell( ptr );
    printf( "offset = %ld\n", offset );   /* prints out 30  */
    fclose( ptr );
 }


 635. Multithreaded fcvt() and ecvt() in C 6.00 May Cause GP Fault

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68382

 The multithreaded versions of the fcvt() and ecvt() functions that
 shipped with the Microsoft C version 6.00 compiler can cause a GP
 fault. This includes the versions in LLIBCMT.LIB, LLIBCDLL.LIB, and
 CDLLOBJS.LIB.

 Microsoft has confirmed this to be a problem in C version 6.00. This
 problem has been corrected in the C version 6.00a maintenance release.

 As a workaround, the gcvt() function can be used if the numbers are
 first coerced into the correct format. The gcvt() function will return
 fcvt() format if the number is greater than 0.1 and ecvt() format if
 the number is less than 0.1. In addition, sprintf() can be called with
 the %f or %e format specifier to return the required string.


 636. TZ and tzset Only Use Whole Hours: How to Work Around

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q68383

 Question:

 In looking through the documentation for the TZ environment variable
 and the tzset() function, it appears that only whole hours can be used
 for time-zone adjustments. I want to calculate the time in SriLanka,
 which is 330 minutes off of GMT. How should I do that?

 Response:

 It is true that the TZ environment variable allows only whole numbers.
 This may change in a future release of the run-time libraries when we
 support the POSIX implementation (which would allow for partial
 hours). In the meantime, the only workaround is to use a second
 environment variable (for example, TZ2) as an indicator so you can add
 the thirty minutes to the times returned by, and passed to, functions
 that return and use local times.


 637. First _pg_chartscatter() Call May Not Use Specified plotchar

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc buglist6.00 buglist6.00a pgchart
 Last Modified: 24-JAN-1991    ArticleIdent: Q68384

 When producing scatter charts with the Presentation Graphics function
 _pg_chartscatter(), the first scatter chart created in a program may
 be drawn with the default plotting character even if a different
 character was specified. This usually results from calling
 _pg_initchart() before setting the graphics video mode with
 _setvideomode().

 The problem stems from an initialization sequence for the palette that
 is used whenever a new video mode is set. If the call to _pg_initchart
 is made AFTER a call to _setvideomode(), then the palette should not
 be affected.

 The sample program below demonstrates this problem and the workaround.
 The program draws two scatter charts. For the first chart, the '$'
 character is specified for the plotting character. For the second
 chart, the '#' character is the plotting character. The second chart
 uses the '#' character as specified, but the first chart is drawn with
 the '*' character, which is the default plotting character.

 If the program is altered, so that the call to _pg_initchart is moved
 down a few lines to after the call to _setvideomode(), then the
 problem goes away and the first chart is drawn correctly with the '$'
 character.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.

 Sample Code
 -----------

 /* TEST.C
    Compile line: CL test.c graphics.lib pgchart.lib  */

 #include <conio.h>
 #include <graph.h>
 #include <string.h>
 #include <stdlib.h>
 #include <pgchart.h>

 float _far x[2][5] = { 23.0F, 42.0F, 59.0F, 72.0F, 96.0F };
 float _far y[2][5] = {  0.9F,  2.3F,  5.4F,  8.0F,  9.3F };

 void main(void)
 {
     chartenv env;
     palettetype pal;
     int i;

     /* Move the following line to after the call to _setvideomode() */
     _pg_initchart();
     if( !_setvideomode( _MAXRESMODE ) )
         exit( 1 );

     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.maintitle.title, "Scatter Test" );
     strcpy( env.xaxis.axistitle.title, "X Amount" );
     strcpy( env.yaxis.axistitle.title, "Y Amount" );

     strcpy( env.subtitle.title, "\"plotchar\" should be '$'" );
     _pg_getpalette(pal);
     for(i=0; i < _PG_PALETTELEN; i++)
         pal[i].plotchar = '$';
     _pg_setpalette(pal);
     _pg_chartscatter( &env, x[0], y[0], 5 );
     getch();
     _clearscreen( _GCLEARSCREEN );

     strcpy( env.subtitle.title, "\"plotchar\" should be '#'" );
     _pg_getpalette(pal);
     for(i=0; i < _PG_PALETTELEN; i++)
         pal[i].plotchar = '#';
     _pg_setpalette(pal);
     _pg_chartscatter( &env, x[0], y[0], 5 );
     getch();
     _clearscreen( _GCLEARSCREEN );

     _setvideomode( _DEFAULTMODE );
 }


 638. Compiler Lacks Warnings for Options Incompatible with /u

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68385

 The /u compiler option turns off the definition of all predefined
 identifiers. Therefore, other compiler options that implicitly define
 identifiers are incompatible with /u. Nevertheless, no warnings or
 errors are generated if an option incompatible with /u is specified.

 For example, the /MT option implicitly defines _MT, which is necessary
 for multithreaded programming. If both /u and /MT are specified, the
 /MT option is effectively ignored due to /u undefining _MT.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 639. sizeof(char Expression) Same as sizeof(int)

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-FEB-1991    ArticleIdent: Q68389

 Question:

 If I print out the sizeof a char, an int, and a long, I get 1, 2, and
 4 bytes, respectively. However, if I shift each type by 1 and print
 the sizeof each after the shift, I get 2, 2, and 4 bytes. Why does a
 shifted char return 2 bytes, whereas an unshifted char returns 1 byte?

 Response:

 This is ANSI-specified behavior. Below is section 3.3.7 from the ANSI
 specifications, which details the semantics of the shift operator:

    Semantics
       The integral promotions are performed on each of the operands.
       The type of the result is that of the promoted left operand. If
       the value of the right operand is negative or is greater than or
       equal to the width in bits of the promoted left operand, the
       behavior is undefined.

 This means that chars are promoted to integers by default. If you
 really want a char result, you must cast the final result.

 The ANSI-specified semantics of all operators specify promotion from
 char to int, so the size of any char expression will be the sizeof
 int. This was also the case for Kernighan and Ritchie (K & R) C.

 The sizes of the int and long expressions stay the same because no
 promotion takes place.

 Note that if int is the same size as long rather than short in this
 implementation, the sizeof both a short expression and a char
 expression will be 4, as will be the sizeof both an int and a long
 expression.

 Sample Code
 -----------

 #include <stdio.h>

 void main(void)
 {
    short si;
    long li;
    char sc;
    unsigned char uc;

    printf("Signed char width: %d\n",
            sizeof((char)(sc<<1));           // 1 byte

    printf("Signed char width: %d\n",
            sizeof(sc<<1));                 // 2 bytes

    printf("Unsigned char width: %d\n",
            sizeof((unsigned char)uc<<1));  // 1 byte

    printf("Unsigned char width: %d\n",
            sizeof(uc<<1));                 // 2 bytes

    printf("Short width: %d\n",
            sizeof(si<<1));                 // 2 bytes

    printf("Long width: %d\n",
            sizeof(li<<1));                 // 4 bytes
 }


 640. "C1063: Stack Overflow" Caused by Taking Address of Constant

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68390

 If the sample code below is compiled with any memory model or
 optimization level, the C version 6.00 and 6.00a compilers will
 generate the following fatal error message:

    file.c(3) : fatal error C1063: compiler limit : compiler stack
                overflow

 Changing the code from

    foo(&"ABC");

 to the following

    char *x = "ABC";

    ...

    foo(&x);

 will eliminate the error.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 void main(void)
 {
    foo(&"ABC");
 }


 641. C 6.00/6.00a Do Not Give Warning That /Gm Is Not Functioning

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a docerr
 Last Modified:  1-FEB-1991    ArticleIdent: Q68391

 The /Gm compiler option for moving strings to the const segment is not
 supported in C 6.00 or in C 6.00a. The compiler will permit /Gm to be
 specified on the command line, but no functionality is attached to the
 option.

 No warnings are displayed to inform you that /Gm is not performing any
 function, and strings are not moved to the const segment. In addition,
 the online help incorrectly lists /Gm as a valid option. However, the
 README.DOC correctly notes that the option has been removed.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 642. Re-entrant Function List for C 5.10 and 6.00

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 24-JAN-1991    ArticleIdent: Q68392

 This material is taken from page 369 of the version 6.00 "Microsoft C
 Advanced Programming Techniques" manual.

 The C run-time functions listed below are re-entrant and can be used
 in multithreaded OS/2 programs with the standard libraries.

 However, Microsoft recommends use of the multithreaded C run-time
 library LLIBCMT.LIB, which allows free use of C run-time library
 functions, instead of restricting yourself to the functions below.

    abs         memcpy          srcat         strnset
    atoi        memchr          strchr        strrchr
    atol        memcmp          strcmpi       strrev
    bsearch     memcpy          strcmpi       strset
    chdir       memicmp         strcpy        strstr
    getpid      memmove         stricmp       strupr
    halloc      memset          strlen        swab
    hfree       mkdir           strlwr        tolower
    itoa        movedata        strncat       toupper
    labs        putch           strncmp
    lfind       rmdir           strncpy
    lsearch     segread         strnicmp


 643. The Use of a CTRL+Z Is Limited in Text Files

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified: 23-JAN-1991    ArticleIdent: Q68423

 --------

 The use of a CTRL+Z (hex 1A, decimal 26) is limited in a file opened
 in text (translated) mode. If a file contains a CTRL+Z, there can be
 only one occurrence of it and it must be the last character in the
 file.

 No other instance of a CTRL+Z is allowed in text mode. By using
 multiple CTRL+Z's, or having characters after the CTRL+Z, you may
 cause fseek(), or run-time functions that call fseek(), to behave in
 an unexpected manner.

 -----------------

 By performing one of the following steps, these functions will perform
 as expected if you have multiple CTRL+Z's in the file.

 1. Open the file in binary (untranslated) mode.

 2. Convert your input file to meet the previously mentioned conditions
    of a text file.

 When opening a file in binary mode, you must remember that the file is
 untranslated. This means that on input, the carriage-return line-feed
 (CR-LF) combination is not translated into a single line-feed (LF)
 character, and on output, the (LF) character is not translated into a
 (CR-LF) combination.

 This may necessitate modifications to your I/O routines that deal with
 newlines (\n) and carriage returns (\r).

 Examples of Opening Binary Files
 ---------------------------------

    FILE * fileptr;
    fileptr = fopen( "filename.dat", "rb+");

 Opens a file called FILENAME.DAT for both reading and writing in
 binary mode. The letter "b" in the access mode designates opening for
 binary mode.

    int filehndl;
    filehndl = open( "filename.dat", O_CREAT | O_BINARY | O_RDWR,
                                     S_IWRITE | S_IREAD);

 Opens a file called FILENAME.DAT for both reading and writing in
 binary mode. The O_BINARY constant designates the file to be opened in
 binary mode.

 With both of the file-open commands, it should be noted that the text
 (translated) mode is the default mode. You may link with an object
 module called BINMODE.OBJ to change the default mode to binary. This
 file is located in your LIB subdirectory.

 This is expected behavior from the Microsoft C Compiler versions 6.00
 and 6.00a.


 644. C1001: Internal Compiler Error: regMD.c, Line 1017

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68445

 The sample code below will produce the following internal compiler
 error when compiled under C versions 6.00 or 6.00a with default
 optimizations in any memory model:

   test.c(24) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)regMD.c:1.110', line 1017)
                 Contact Microsoft Product Support Services

 The following are valid workarounds:

  - Compile with /Od.

  - Compile with /Ox.

  - Use the optimize pragma to turn off optimizations for the function
    in which the error occurs.

  - Compile with the /qc (Quick Compile) option.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 typedef struct
 {
   unsigned d : 8;
   unsigned m : 8;
 } SysDate;

 typedef struct
 {
   unsigned m : 8;
   unsigned h : 8;
   unsigned s : 8;
 } SysTime;

 extern SysDate fd(void);
 extern SysTime ft(void);

 long gotdostime()
 {
   SysDate dd = fd();
   SysTime tt = ft();
   unsigned d = dd.d | (dd.m << 5);
   unsigned t = tt.h | (tt.m << 5) | (tt.s >> 1);

   return((((long)d) << 16) | t);
 }


 645. "C2118: Negative Subscript" May Be Caused by int Expression

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  1-FEB-1991    ArticleIdent: Q68475

 The compiler error "C2118: negative subscript" may be caused by an
 integer expression in the subscript of an array. If the expression
 evaluates to greater than 32768, its value becomes negative, thus
 causing the aforementioned error.

 To work around this situation, add an uppercase (or lowercase) "L" to
 one of the terms of the expression. This will force the compiler to
 use long math to evaluate the expression.

 Sample Code
 -----------

    #include <stdio.h>
    char foo[1000 * 33];

 If the above two-line program is compiled, the following error is
 generated:

    file.c(2) : error C2118: negative subscript

 To eliminate the error, add "L" to one of the terms to indicate it is
 a long constant. For example,

    #include <stdio.h>
    char foo[1000L * 33];

 This is correct and expected behavior for the Microsoft C Compiler
 because the evaluation of integer expressions is done using integer
 math. In this case, integer math produces an incorrect result because
 the value of the expression is larger than an integer. By using a long
 integer as one of the operands, you can force the expression to be
 evaluated using long math, which does not overflow in this case.


 646. C1001: Internal Compiler Error: grammar.c, Line 140

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68496

 The C version 6.00a compiler produces the following internal compiler
 error when the sample program below is compiled with /AL and any of
 these optimizations: default, /Oa, /Oc, /Oi, /On, /Op, /Or, /Os, /Ot,
 /Ow, or /Oz:

    file.c(6) : fatal error C1001: Internal Compiler Error
                 (compiler file '../grammar.c', line 140)
                 Contact Microsoft Product Support Services

 The following are valid workarounds:

 1. Compile with one of the following optimizations:

       /Od, /Oe, /Og, /Ol and /Ox

 2. Use the optimize pragma to turn off optimizations for the function
    in which the error is occurring.

 3. Use the /qc (quick compile) compiler option.

 Sample Code
 -----------

 void select( int *x, int d, int *y, int *z)
 {
    int sx;

    if( x != z && sx < 0)
       x[0] = (-x[0]);      /* this line causes error */
 }

 Microsoft has confirmed this to be a problem in C version 6.00a. We
 are researching this problem and will post new information here as it
 becomes available.


 647. Bad Code Generated for "a+b == a" FP Comparison Expressions

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a conditional equals codegen
 Last Modified:  1-FEB-1991    ArticleIdent: Q68559

 The Microsoft C Compiler versions 6.00 and 6.00a will perform an
 incorrect optimization on expressions of the form "a+b == a" if a and
 b are floating-point variables (double or float type).

 Sample code with floating-point expressions of the form "a+b == a" was
 compiled with optimization disabled (/Od) and the first few lines of
 the resulting assembly listing follows:

 ; double a,b;
 ; if (a+b == a) ;
     *** 00000b  9b d9 ee                fldz
     *** 00000e  9b dc 16 00 00          fcom    QWORD PTR _b
     *** 000013  9b dd d8                fstp    ST(0)
     *** (lines deleted)

 ; if ((a+b) == a) ;
     *** 000025  9b dd 06 00 00          fld     QWORD PTR _b
     *** 00002a  9b dc 06 00 00          fadd    QWORD PTR _a
     *** 00002f  9b dc 16 00 00          fcom    QWORD PTR _a
     *** 000034  9b dd d8                fstp    ST(0)
     *** (lines deleted)

 Note that the first expression gets optimized to compare variable b to
 zero, rather than comparing a+b to a. In the second expression, a+b is
 correctly compared to a.

 The optimization performed in the above code is valid for integers but
 not for floating-point numbers, and will produce incorrect results in
 certain cases. One reason the expression (a+b == a) might be used is
 to detect when b is negligibly small in relation to a.
 The following are valid workarounds:

 1. Enclose the expression "a+b" in parenthesis.

 2. Make the variables a and b integers, if applicable.

 3. Use the quick compile (/qc) option on the compiler command line.

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 648. Integer Divide by 0 Only on 8088/86 Machine

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 24-JAN-1991    ArticleIdent: Q68599

 The code below produces an error on computers with Intel 8088/86
 processors, but runs correctly on later versions of the Intel
 processors, such as the 80286. When the program is run on an 8088/8086
 machine, the following error will occur:

    run-time error R6003
    - integer divide by 0

 The problem is caused by the difference between the IDIV instruction
 on the processors. The Intel programmer's reference manual for the
 8088/86 processor states the following:

    For word integer division, the maximum positive quotient is +32767
    and the minimum negative quotient is -32767. If the quotient is
    positive and exceeds the maximum, or is negative and is less than
    the minimum, the quotient and remainder are undefined, and a type 0
    interrupt is generated.

 A type 0 (zero) interrupt is an "Integer Divide By 0" error, which
 means that the lowest negative number that can be used on an 8088/86
 CPU machine for integer division is -32767. The developer should not
 allow an integer to become -32768. This limitation has changed with
 later versions of the Intel processors, which allow integer division
 with a quotient of -32768.

 Note: This is not a problem with the code generated by the compiler.
 Because the problem is exhibited at execution time, it is up to the
 programmer to ensure that an integer will not take on a value of
 -32768 before it is used as a quotient.

 Sample Code
 -----------

 #include <stdio.h>
 void main(void)
 {
   int numerator=-32768;
   int denominator=1;
   int result;
   result=numerator/denominator;
 }


 649. /Gm Option Can Be Emulated with a Preprocessor

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68626

 The /Gm switch from Microsoft C version 5.10 is not fully implemented
 in versions 6.00 and later. This switch is designed to take all string
 literals and move them into the _CONST segment, instead of keeping
 them in the _DATA segment. However, there is a way to emulate the /Gm
 switch, which involves the use of a preprocessor for pass 2 of the
 compiler.

 There is a text file on CompuServe (in the MSLANG forum, library 3)
 called C2PP.C. This is public domain source code for a preprocessor
 that alters the output file from pass 1 of the compiler. Instructions
 for use are included in the source code. The program reads the input
 file, alters it, and then calls pass 2 of the compiler.

 To use the program, add the following options to the beginning of
 your compile line:

    /B2 c2pp /Gm

 Even though the /Gm switch is not fully implemented in version 6.00,
 it does alter the pass 1 output file, and the preprocessor requires
 it.

 This program cannot be used with the /qc (Quick Compile) option.

 Warning: The format for the output file from pass 1 is not documented,
 and is subject to change at any time. This program has been tested
 with versions 6.00 and 6.00a. It is not guaranteed to work with any
 other versions. It is also not supported or maintained by Microsoft,
 only by the author, as listed below and in the comments in the source
 code.

 Many thanks to Paul van Keep (CIS ID:75170,1045) for the code that
 does the preprocessing.


 650. C1001: Internal Compiler Error: omfMD.c, Line 446

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68627

 The sample program below attempts to save data in the code segment
 using inline assembly, but produces the following internal compiler
 error when compiled with or without optimizations:

    foo.c(10) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)omfMD.c:1.26', line 446)
                 Contact Microsoft Product Support Services

 The sample code was designed to store the stack segment immediately
 after the jmp instruction. The code should compile without any errors;
 however, it is usually not good programming choice to write
 self-modifying code.

 The following are two workarounds:

 1. Compile with /qc (the Quick Compile) option.

 -or-

 2. Use the _based keyword to define a location within the code
    segment. The following sample illustrates this:

       int _based(_segname("_CODE")) savess;
       void foo(void)
       {
           _asm mov savess, SS
       }

 Sample Code
 -----------

  1. void foo(void)
  2. {
  3.    _asm
  4.    {
  5.       jmp label
  6.       nop
  7.       nop
  8.       nop
  9.    label:
 10.       mov CS:WORD PTR $-4, SS
 11.    }
 12. }


 651. Warning C4026 Not Generated by Microsoft C Compiler 6.00

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68690

 When a function is declared to take arguments but the function does
 not declare formal parameters, no warning is generated if the function
 is not called. The following code, when compiled with the /W4 switch,
 demonstrates this problem.

 Sample Code
 -----------

 void empty( int bar );

 void empty( void ){}

 void main( void ){}

 While Microsoft C versions 6.00 and 6.00a produce no errors in the
 above code, version 5.10 produces the following error:

    void.c(3) : warning C4026 : function was declared with formal
                                argument list

 Microsoft has confirmed this to be a problem in the C compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.


 652. Online Help Example of Rich Text Format (RTF) Is Incorrect

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 31-JAN-1991    ArticleIdent: Q68691

 The online help example for making help databases with Rich Text
 Format (RTF) files has several errors. Because of these errors, the
 Helpmake utility cannot encode the example.

 Example in Online Help
 ----------------------

  1. {rtf0
  2. >> open \par
  3. {\b Include:} <fcntl.h>, <io.h>, <sys\\types.h>, <sys\\stat.h>
  4.
  5. {\b Prototype:}   int open(char *path, int flag[, int mode]);\par
  6.     flag: O_APPEND O_BINARY O_CREAT O_EXCL O_RDONLY\par
  7.           O_RDWR   O_TEXT   O_TRUNC O_WRONLY\par
  8.           (can be joined by |)\par
  9.     mode: S_IWRITE  S_IREAD   S_IREAD | S_IWRITE\par
 10. \par
 11. {\b Returns:}   a handle if successful, or -1 if not.\par
 12.     errno:  EACCES, EEXIST, EMFILE, ENOENT\par
 13. \par
 14. {\b See also:}  {\u Example}{\v open.ex},\par
 15. {\u Template}{\v open.tp}, access, chmod, close,
 16. creat, dup, dup2, fopen, sopen, umask\par
 17. }

 1. Line 1 needs a backslash before "rtf". It should read:

       {\rtf0

 2. "\u" in line 14 and 15 is not RTF formatting code. "\ul" is the
    correct code. Line 14 should read:

       {\b See also:}  {\ul Example}{\v open.ex},\par

 3. "\par" is needed on the end of line 15 for the formatting to be
    consistent. Line 15 should read:

       {\ul Template}{\v open.tp}, access, chmod, close,\par

 Microsoft has confirmed this to be a problem in Microsoft C versions
 6.00 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 653. charttype Constants Are Documented with Wrong Names in C 6.00

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q68693

 When using the _pg_chart() function, the first parameter is a chart
 environment pointer, which defines the structure chartenv. Within this
 structure, the first element is a short called charttype. According to
 the C 6.00 online help and the documentation in PGCHART.H, there are
 five (5) predefined constants that can be used for the charttype:

    _PG_BAR     - Bar chart
    _PG_COLUMN  - Column chart
    _PG_LINE    - Line chart
    _PG_SCATTER - Scatter chart
    _PG_PIE     - Pie chart

 However, the actual constant names are defined to be _PG_BARCHART,
 _PG_COLUMNCHART, _PG_LINECHART, _PG_SCATTERCHART, and _PG_PIECHART.


 654. Generating Browse Information with GRDEMO and CHRTDEMO

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  5-FEB-1991    ArticleIdent: Q68739

 Two of the sample make files GRDEMO.MAK and CHRTDEMO.MAK, which are
 distributed with C versions 6.00 and 6.00a, do not contain the data
 needed to generate browse information. If you try to generate browse
 information in the Programmer's WorkBench (PWB) with either of these
 files by selecting the Browse Options function from the Options menu
 and activating Generate Browse Information and then recompiling, the
 Browse menu options will still not be available.

 This problem occurs because the information that would normally invoke
 PWBRMAKE to build the browser database is not included in these
 makefiles. To work around this problem:

 1. Use PWB to set your own program list with a new name.

 2. Enter the same filenames that are contained in the corresponding
    makefile that you are replacing.

 3. Perform a Rebuild All.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 655. PGCHART: How to Draw a Line Chart with Lines Only

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 29-JAN-1991    ArticleIdent: Q68745

 Using _pg_defaultchart, you can specify a line-chart type with
 _PG_LINECHART. The choices for the chart style are _PG_POINTANDLINE
 and _PG_POINTONLY. There is no manifest constant for "lines only," but
 a line chart with lines only can be made with a few modifications to
 the existing code, which produces a chart with points and lines.

 The following code, which defines the field in the palette to be
 modified, is taken from page 259 of the "Microsoft C Advanced
 Programming Techniques" manual that shipped with C version 6.00.

 /* Typedef for pattern bitmap */
 typedef unsigned char fillmap[8];

 /* Typedef for palette entry definition */
 typedef struct
 {
      unsigned short color;
      unsigned short style;
      fillmap fill;
      char plotchar;     /* by default, the plotted character is '*' */
 }paletteentry;

 /* Typedef for palette definition */
 typedef paletteentry palettetype[ _PG_PALETTELEN ];

 The following are the modifications to be made to the sample program
 SCATTER.C, on pages 256-258 of "Microsoft C Advanced Programming
 Techniques" (also on pages 280-281 of "C For Yourself," which was
 shipped with QuickC version 2.50). Note that the original program
 produces a scatter chart; a line chart requires different arguments in
 the call to _pg_defaultchart(), as shown below.

 Declare the following variable

    palettetype palette_struct;

 after the line

    _pg_initchart( );

 but before the line

    _pg_defaultchart( &env, _PG_LINECHART, _PG_POINTANDLINE);

 1. Get the array of current palette structures with the line:

       _pg_getpalette( palette_struct );

 2. Change the plotted character in the first palette to a blank, so
    that no points will appear on the graph (the line will be
    unbroken). For example:

       palette_struct[1].plotchar = ' ';

 3. Reset the palette with the line:

       _pg_setpalette( palette_struct );

 The following is the modified SCATTER.C program:

 Sample Code
 -----------

 #include <conio.h>
 #include <string.h>
 #include <graph.h>
 #include <pgchart.h>

 #define MONTHS  12

 typedef enum {FALSE, TRUE}  boolean;

 float far value[MONTHS] =
 {
         33.0,27.0,42.0,64.0,106.0,157.0,
        182.0,217.0,128.0,62.0,43.0,36.0
 };

 char far *category[MONTHS] =
 {
         "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jly", "Aug",
         "Sep", "Oct", "Nov", "Dec"
 };

 palettetype palette_struct;

 main( )
 {
         chartenv env;
         int mode = _VRES16COLOR;

         if( _setvideomode( _MAXRESMODE ) == 0 )
                 exit( 0 );
         _pg_initchart();

         _pg_getpalette( palette_struct );
         palette_struct[1].plotchar = ' ';
         _pg_setpalette( palette_struct );

         _pg_defaultchart( &env, _PG_LINECHART, _PG_POINTANDLINE );

         strcpy( env.maintitle.title, "Good Neighbor Grocery" );
         env.maintitle.titlecolor = 6;
         env.maintitle.justify = _PG_RIGHT;
         strcpy( env.subtitle.title, "Orange Juice vs Hot Chocolate" );
         env.subtitle.titlecolor = 6;
         env.subtitle.justify = _PG_RIGHT;
         strcpy( env.xaxis.axistitle.title, "Months" );
         strcpy( env.yaxis.axistitle.title, "Quantity" );
         env.chartwindow.border = FALSE;
         env.xaxis.ticinterval = 4.0;

         if( _pg_chart( &env, category, value, MONTHS ) )
         {
                 _setvideomode( _DEFAULTMODE );
                 _outtext( "Error: can't draw chart" );
         }
         else
         {
                 getch();
                 _setvideomode( _DEFAULTMODE );
         }
         return( 0 );
 }

 For more information about line charts, see pages 252-273 of
 "Microsoft C Advanced Programming Techniques", and pages 267-296 of "C
 for Yourself."


 656. Using float/double Function as Subscript May Cause Bad Code

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68921

 Multiple calls to float functions in the same logical statement may
 cause the floating-point accumulator to be overwritten if the result
 of one of the calls is used as a subscript.

 In the sample code below, "fone" returns "0.0" in the floating-point
 accumulator. However, the floating-point accumulator is not saved
 before "ftwo" is called. The function "ftwo" returns "12.0" in the
 floating-point accumulator, which overwrites the "0.0" returned by
 "fone". As a result, array[12] is changed, instead of array[0]. As a
 workaround, the function's return value may be stored in a temporary
 variable, or the two functions may be declared as "pascal".

 This behavior occurs only when using the Microsoft C Optimizing
 Compiler, under all optimizations and all memory models. The code
 performs as expected using QuickC or compiling with the "/qc" option.

 Sample Code
 -----------

 #include <stdio.h>

 float fone(void);
 float ftwo(void);

 float goo[20];

 void main(void)
 {
 int   i;

 // This doesn't work.
    goo[(int)fone()] = ftwo();
    printf("goo[0] (should equal 12.0) = %f\n",goo[0]);

 // This works.
    i = (int)fone();
    goo[i] = ftwo();
    printf("goo[0] (should equal 12.0) = %f\n",goo[0]);
 }

 float fone()
 {
    return((float)0.0);
 }

 float ftwo()
 {
    return((float)12.0);
 }

 Microsoft has confirmed this to be a problem in Microsoft C versions
 6.00 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 657. Limitations on Writing Device Drivers in C

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 14-DEC-1990    ArticleIdent: Q10826

 Question:

 I am writing an MS-DOS device driver. All of the code is written in
 Microsoft C, with the exception of the standard device driver header
 (which is written in assembly language). Can all of a device driver be
 written in C?

 Response:

 You cannot write complete device drivers in C. You must write some
 parts in assembly, and you cannot use the majority of the C run-time
 library support.

 These are the major problems in using C for device drivers:

 1. The .EXE loader is in COMMAND.COM, and therefore, not available to
    load device drivers. In this case, the device driver must be a
    binary image of a single-segment program. The C compiler does not
    generate such code. At best, in small model, you have two disjoint
    physical segments [one for code (CS) and one for data (SS AND DS)].

 2. The C run-time initialization code depends on the PSP being set up
    properly and it relies on DOS being available. Although, the
    start-up source is provided, it is mainly assembly code and it will
    require major modifications.

 3. The entry-exit sequences for C functions are not appropriate for
    being called as a DOS driver.

 You can work around some of these limitations by using assembly code
 generated by the C compiler. The -Fa switch will direct the compiler
 to output assembler source. This assembler source code then can be
 edited and used as part of the driver source. Depending on the
 complexity of the DOS driver, it is possible that most of the driver
 could be written in C and still provide for reasonably easy
 modification and maintenance.


 658. _dos_setftime() Fails to Set Date and Time for File on Network

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q68797

 The _dos_setftime() function is used to set the date and time of a
 file. If the file is on a local drive, the function behaves as
 expected; however, if the file resides on a network drive, the date
 and time will not get set correctly. In this case, the _dos_setftime()
 still returns a value indicating successful operation.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 659. tan(pi/2) Does Not Cause an Error Because of Precision

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q11158

 Question:

 If you try to calculate tan(pi/2), which is in fact not defined, tan()
 will return a value. This value is not large. Why isn't there an error
 message for such an overflow?

 Response:

 This is a precision limitation. Because you are constrained to work in
 single or double precision accuracy, it isn't possible to specify a
 value close enough to the true value of pi/2 so that tan(X) overflows.


 660. Documentation Errors on Page 315 of APT Manual

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 31-JAN-1991    ArticleIdent: Q68821

 The following are several documentation errors in the mixed-language
 example on page 315 of the "Microsoft C Advanced Programming
 Techniques" shipped with C version 6.00:

 The line shown as

    #pragma pack(2);

 should read as follows:

    #pragma pack(2)

 The lines that read

    block_hed-n = 1;
    block_hed-x = 10.0;
    block_hed-y = 20.0;

 should read as follows:

    block_hed->n = 1;
    block_hed->x = 10.0;
    block_hed->y = 20.0;


 661. Italics (and Other Fonts) on a Monochrome Monitor

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q11274

 Question:

 On some Microsoft products (such as Microsoft Word), I have seen text
 represented in italics on a monochrome monitor without a graphics
 adapter. How can I get italics on the monitor using Microsoft C or
 Macro Assembler?

 Response:

 These products create the italics font internally, in graphics mode
 (regardless of whether or not you have a monochrome monitor or color
 monitor attached), then it is mapped into the BIOS graphics ASCII
 table and presented on the screen.

 To get italics on the screen, you must first create this graphics font
 (or purchase a library of fonts from a software vendor), then map the
 graphics font to the BIOS graphics font table.

 It is possible to incorporate many desired fonts into your application
 by writing your application to interface with Microsoft Windows.


 662. When Compiling with /P, Errors Are Directed to STDERR

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q68834

 The Microsoft C compiler can create a preprocessor listing by compiling
 with the /P option. When this option is used and when output is
 redirected to a file, preprocessor error messages that are generated
 will go to the screen and not to that file because these errors are
 directed to STDERR, rather than STDOUT.

 To resolve the problem, redirect STDERR to the file where you want the
 error messages to go. This can been done in DOS by using a utility,
 such as ERROUT.EXE, which comes with C 5.10. Under OS/2, the STDERR
 output can be redirected to a file by specifying the handle for
 STDERR, which is 2, followed by ">" and then the name of the file. The
 examples below demonstrate the syntax.

 For DOS using ERROUT.EXE, use the following:

    ERROUT /f err.txt cl /P example.c

 For OS/2, use the following:

    CL /P 2>outfile.txt example.c

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 663. Compiler Prints Filename but Does Not Compile the Program

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER |
 Last Modified:  5-FEB-1991    ArticleIdent: Q68835

 If your program prints out your filename after you type in the
 following

    cl filename.c

 and then returns to the DOS prompt without creating an executable
 file, there may be duplicate compiler filenames. Within the
 Programmer's WorkBench, it will indicate that there are no warnings or
 errors after rebuilding, but the compiler will not create an
 executable file.

 The C compiler is a three-pass compiler, and invokes the files C1.EXE,
 C2.EXE, and C3.EXE. If there are any other files with these names on
 the path before the compiler, then the compiler may incorrectly
 execute the wrong file.

 There is a compiler switch that will enable you to print out which
 files are being invoked during each pass of the compiler. To implement
 this switch, enter the following:

    cl /d filename.c


 664. Setting _settextcolor() to 0 May Give Unexpected Results

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q68865

 When in a graphics mode, using the function _settextcolor() with an
 argument of "0" to select black does not work as expected. For
 example, the code below sets the background color to _WHITE, sets the
 text color to 0 (Black), and tries to print text to the screen.

 In this example, the resultant foreground and background colors are
 the same. Remember that _setbkcolor() sets the color for index 0. When
 _settextcolor() is called with the same index, nothing will seem to
 appear because the _setbkcolor() function resets color index 0 to the
 new color. When _settextcolor() is called with index 0, the foreground
 and background colors are the same, and therefore, nothing appears on
 the screen.

 To work around the problem, just call _remappallette() to move the
 desired color off index 0. The comments in the following code
 illustrate this:

 Sample Code
 -----------

 #include <stdio.h>
 #include <conio.h>
 #include <graph.h>

 void main()
 {
    _setvideomode(_MAXRESMODE);

    // _remappalette(1,0);    // Uncomment for the workaround.

    _setbkcolor(_WHITE);

    _settextcolor(0);

    // _settextcolor(1);      // Uncomment for the workaround.
    _outtext("foo");

    getch();

    _setvideomode(_DEFAULTMODE);
 }


 665. Ternary Operator Generates Incorrect Code for Bit Fields

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68872

 In some situations, the ternary operator does not recognize that the
 first bit in a structure has been set. For example, when the code
 example below is compiled with

    cl test.c

 it prints out

    NOT_SET  NOT_SET

 when it should print the following:

    SET      NOT_SET

 Code Example
 ------------

 #include <stdio.h>

 typedef struct tag
 {
    unsigned int a: 1;
    unsigned int b: 1;
    unsigned int c: 14;
 } BIT, *PBIT;

 void foo(PBIT px)
 {
    printf("%s\t%s", px->a ? "SET" : "NOT_SET", px->b ? "SET" : "NOT_SET");
 }

 void main(void)
 {
    BIT  x;

    x.a = 1;
    x.b = 0;
    foo( &x );
 }

 The following are three workarounds:

 1. Update to C version 6.00a.

 2. Compile with /Od.

 3. Simplify the printf() statement by moving the ternary condition to
    another line, or by using an else if statement.


 666. Using ANSI.SYS Escape Codes with printf() for Screen Control

 Product Version(s): 3.x 4.x 5.x 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                 | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q68874

 The DOS ANSI.SYS driver may be used to perform screen control
 functions in printf() output. Setting screen attributes, positioning
 the cursor to a row and column, and clearing the screen are some
 examples of functions that may be done with this driver using the
 correct escape sequences.

 The ANSI.SYS driver must be loaded from CONFIG.SYS in order for these
 functions to work correctly. All of the sequences start with the
 escape code "\33" (representing the value for escape in octal),
 followed by the appropriate set of characters needed to perform the
 desired function.

 This topic is discussed in detail on pages 224-225 in the Microsoft
 Press book "Variations in C."

 The following sample code demonstrates some of these functions:

 Sample Code
 -----------

 #include <stdio.h>

 void main( void)
 {
    int row = 10;
    int col = 20;
    int num = 1;

    printf( "\33[2J");                // clears the screen

    printf( "\33[%d;%dH", row, col);  // positions the cursor at row 10,
                                      // column 20

    printf( "\33[%dA", num);          // moves the cursor up 1 line

    printf( "\33[%dB", num);          // moves the cursor down 1 line

    printf( "\33[7m");                // sets the attribute to reverse
                                      // video
 }

 There are other sequences available. Information about them may be
 found in DOS manuals under the "prompt" command, or any other sections
 dealing with ANSI.SYS.

 Under OS/2, the ANSI driver is enabled by default for all sessions
 except the Presentation Manager. To enable ANSI support in the DOS
 box, a line must be added to the CONFIG.SYS file. See your OS/2
 documentation for more information on the exact syntax.


 667. Error L2029 May Be Caused by Improperly Renaming Libraries

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_link s_quickc
 Last Modified:  1-FEB-1991    ArticleIdent: Q68875

 Although you may have been able to link other programs without a
 problem, in certain cases, the link error "L2029: Unresolved External"
 may be generated for some of the following symbols:

    __aFlmul
    __aFfalrem
    __aFalshl
    __aFnaldiv

 The L2029 error may be occurring because you are using a library that
 does not contain all of the necessary functions, due to improper
 installation or renaming.

 The problem could result because the C compiler was installed without
 combined libraries, or because the file

    xLIBCR.LIB

 was improperly renamed to the following

    xLIBCE.LIB

 (where x = S, M, C or L).

 In this case, the linker will incorrectly use xLIBCE.LIB, assuming
 that it is a combined library containing all of the necessary
 functions.

 To resolve the problem, reinstall the C run-time libraries by typing
 "setup /lib" from drive A with the Setup disk loaded. Then choose
 "Yes" for "Combined Libraries" when prompted.

 Note that this problem may also occur with QuickC versions 2.50 and
 2.51.


 668. Accessing Interrupt Return Status in Zero Flag

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68886

 If you want to call BIOS interrupts from a C program, the int86()
 function is typically used. Passing of register values is done by
 initializing fields of a variable declared as union REGS, and then
 reading them on return. However, there is no way to check the value of
 the zero flag upon completion of the BIOS function. Thus, there is no
 way of checking the return status of BIOS interrupt 16h function 01h
 and function 11h, which both return a status in the zero flag.

 Under C versions 6.00 and 6.00a and QuickC versions 2.00, 2.01, 2.50,
 and 2.51, you can work around this by using inline assembly to call
 the interrupt function and then check the status of the zero flag.

 Sample Code
 -----------

 int KeyPeek(void)
 // Returns either the key value and scan code for that key or 0,
 // indicating no key waiting.
 {
    union
    {
       int rc;
       struct Key
       {
          char Value, ScanCode;
       };
    } KeyInfo;

    KeyInfo.rc = 0;

    _asm
    {
       mov   AH, 01h
       int   16h
       jz    done
       mov   KeyInfo.Value, AL
       mov   KeyInfo.ScanCode, AH
    done:
    }
    return(KeyInfo.rc);
 }


 669. Object Files Are Not Created in the Proper Directory

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68892

 Object files will not be created in a requested directory if all the
 following conditions hold:

 1. The /Fo<path> option is used to specify the target directory.

 2. More than one file is compiled at the same time.

 3. An error occurs in the first file compiled.

 An example of a command line that causes this is as follows:

    cl /c /Fo\objs\ *.c

 If an error occurs in the first file that is compiled, the path
 specified in the /Fo option will not be passed to pass 3 of the
 compiler. The compilation will complete as normal, but all object
 files will be placed in the same directory as the source files. If an
 error occurs in any file other than the first one, the path will be
 passed properly, and all object files will be placed in the desired
 directory.

 Microsoft has confirmed this to be a problem in the C compiler
 versions 6.00 and 6.00a. We are researching the problem and will post
 new information here as it becomes available.


 670. FPSEG() and FP_OFF() Require DOS.H to Avoid C2106 Error

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q26588

 Problem:

 When I use the FP_SEG() and FP_OFF() macros on the left side of an
 assignment statement to set (rather than get) segment and offset
 values, the compiler generates the error, "C2106: left operand must be
 an lvalue."

 Response:

 You must include the DOS.H header file in your program; otherwise, the
 compiler believes FP_SEG() and FP_OFF() are function calls rather than
 macro definitions. Because a function is not an lvalue, it generates
 the C2106 error. For more information on the FP_SEG() and FP_OFF()
 macros, consult the run-time library reference or online help that
 shipped with your version of the compiler.


 671. Incorrect Code Generated for "FILD QWord Ptr"

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  1-FEB-1991    ArticleIdent: Q68907

 The sample code below generates incorrect code when compiled under
 Microsoft C versions 6.00 and 6.00a.

 Compiling the sample code with /Fa (to produce an assembly listing)
 shows the following statement to correspond with the inline assembly
 statement in the sample code:

    fld     QWORD PTR [bp+4]

 The correct instruction should be:

    fild      QWORD PTR [bp+4]

 Furthermore, CodeView version 3.00 shows the statement as:

    ???      QWORD PTR [bp+4]

 When the /qc (quick compile) option is specified, the code is
 correctly generated:

    fild     QWORD PTR [bp+4]

 Sample Code
 -----------

 /* Compile with /Fa /Zi /Od */

 typedef struct qw_tag {
     unsigned char b[10];
 } qw;

 void _cdecl foo( qw a );

 void main( )
 {
         qw a;
         foo( a );
 }

 void _cdecl foo( qw a )
 {
     _asm  fild qword ptr a
 }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 672. C 6.00 Library Source SETUP /copy May Fail for Some Files

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  6-FEB-1991    ArticleIdent: Q68922

 The SETUP.EXE program provided with the Library Source for C versions
 6.00 and 6.00a has a switch called /copy that allows you to install
 single files from the install disk. SETUP will prompt for the file to
 be installed. If the file is not unique, the SETUP.EXE program will
 prompt for a path where it can find the file. However, SETUP will not
 allow long pathnames to be entered; therefore, the install will fail
 for most files.

 Because the files on the disk are compressed, the only way to correct
 the problem is to install all of the files.

 Microsoft has confirmed this to be a problem in the C Compiler Library
 Source SETUP.EXE version 6.00. We are researching this problem and
 will post new information here as it becomes available.


 673. calloc() Can Return a Pointer to a Zero Length Block of Memory

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  6-FEB-1991    ArticleIdent: Q68943

 There is a documentation error in the description of the calloc()
 function in the "Microsoft C Run-Time Library Reference" manual and in
 the online help that shipped with Microsoft C versions 6.00 and 6.00a.

 Page 136 of the "Microsoft C Run-Time Library Reference" states, "The
 _fcalloc and _ncalloc functions return NULL if there is insufficient
 memory available or if num or size is 0." Actually, they will return
 NULL only if there is insufficient memory for the request. If one of
 the arguments is of size zero, calloc(), _ncalloc(), and _fcalloc()
 will return a pointer to a block of size 0 bytes.

 Sample Code
 -----------

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

 void _near *foo;
 void _far  *goo;

 void main(void)
 {
    foo = _ncalloc(0,1);
    goo = _fcalloc(0,1);

    if (NULL == foo) printf("Foo is null.\n");

    else printf("Foo points to a block %d bytes long.\n",_nmsize(foo));

    if (NULL == goo) printf("Goo is null.\n");

    else printf("Goo points to a block %d bytes long.\n",_fmsize(goo));
 }

 When this program is executed, the output is as follows:

    Foo points to a block 0 bytes long.
    Goo points to a block 0 bytes long.


 674. Program's First Command-Line Argument Is "C" Under DOS 2.x

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q27778

 Real-mode programs that access command-line arguments in order to
 determine their full pathname will find that their pathname is always
 "C" under MS-DOS versions 2.x. Under DOS versions 3.x and later, the
 full pathname is retrieved as expected.

 This is not a problem in the C compiler. Rather, it is a limitation of
 MS-DOS versions 2.x.


 675. Output to stdprn Is in Binary (Untranslated) Mode

 Product Version(s): 3.x 4.x 5.x 6.00a 6.00 | 5.10 6.00 6.00a
 Operating System:   MS-DOS                 | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68944

 The C start-up code automatically opens five files for a program's
 use. The "stdprn" file (PRN device) is opened in binary mode, which is
 important to remember when printing to printers that require a
 carriage return/line feed combination to end a line (for example, some
 laser printers). In those cases, you do one of the following:

 1. Change your output routines to send a CR/LF pair (\n\r).

 2. Reopen stdprn in text mode so that the translation is handled by
    the run-time library.

 3. Change the mode of the file to O_TEXT. You must remember to flush
    the buffer before doing this.

 The following is a code fragment that illustrates each method:

 #include <stdio.h>
 #include <io.h>
 #include <fcntl.h>

 void main(void)
 {
    FILE *txtprn;

    fprintf(stdprn, "untranslated\n");        // Standard mode

    fprintf(stdprn, "CRLF pair added \n\r");  // Method 1

    txtprn=freopen("PRN", "wt",stdprn);       // Method 2

    fprintf(txtprn, "translated\n");

    fflush(stdprn);                           // Flush the buffer first

    setmode(fileno(stdprn), O_TEXT);          // Method 3

    fprintf(stdprn, "translated\n");
 }


 676. Using qsort() to Sort on Multiple Fields Within a Structure

 Product Version(s): 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                    |
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q28244

 Question:

 I can sort on one structure member using the function qsort(). How can
 I sort on two or more structure members?

 Response:

 The library routine qsort() does not place any limits on how items are
 compared. When qsort needs to decide if one element is equal to,
 greater than, or less than another element, it calls a compare
 function which you write. Therefore, if you want to sort an array of
 structures by comparing multiple fields within the structures, you
 need to write a compare function that examines the appropriate fields
 of each structure being compared, then return a compare value
 indicating which was greater.


 677. How to Write Your Own __chkstk Routine

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm s_quickc
 Last Modified: 20-FEB-1990    ArticleIdent: Q58194

 Problem:

 I am trying to rewrite the stack checking routine (__chkstk) so that I
 can work around some of the assumptions that it makes.

 These assumptions are DS==SS, and that Microsoft's internal variables
 point to the beginning/end of the stack.

 Response:

 The stack checking routine actually allocates space on the stack, so
 doing a stack checking routine that just does a RET does not work. The
 following code demonstrates the bare necessities for writing your own
 __chkstk routine:

                 ;   a chkstk routine for the small/compact memory models
 .MODEL SMALL
 .DATA

 PUBLIC STKHQQ

 STKHQQ dw     dataoffset _end+STACKSLOP

 .CODE

 PUBLIC __chkstk

 __chkstk PROC

         pop     cx      ; grab the return address
         sub     sp, ax
         jmp     cx

 __chkstk ENDP

 END

                 ;   a chkstk routine for the medium/large memory models
 .MODEL LARGE
 .DATA

 PUBLIC STKHQQ

 STKHQQ dw    dataoffset _end+STACKSLOP

 .CODE

 PUBLIC __chkstk

 __chkstk PROC

         pop     cx      ; grab the return address
         pop     dx      ; (and its segment)

         sub     sp, ax

         push    dx      ; push the return address
         push    cx
         ret             ; and go back to that address

 __chkstk ENDP

 END

 Currently, STACKSLOP is defined as being 256 bytes for DOS and 512
 bytes for OS/2, although this may change with future versions of the
 compiler.

 It is unsafe to do just a simple return from inside this function
 because the stack would not be modified. In one scenario, if a
 function assumes that it has X amount of stack space and that the
 stack space hasn't been allocated, the function will write over
 whatever is currently on the stack (this function could do a memory
 move of data onto the stack rather than pushing and popping the
 stack). Because of this, you must allocate space on the stack.

 You cannot simply turn off stack checking because some functions
 (printf() in particular) have a call to __chkstk hardcoded.

 To get the above example working, let's assume that it is in a file
 called CHKSTK.ASM. Assemble with the /MX switch, to make all symbols
 case sensitive, as follows:

    MASM /MX chkstk.asm ;

    or

    QCL /Cx chkstk.asm

 You can then link your program with this module in the following way:

    LINK /NOE program chkstk ;

 This assumes that your program has been compiled successfully and that
 it is named "program." It also assumes that you are using the same
 memory model for both modules.

 This information is correct for Microsoft C Versions 5.10 and earlier.
 It is also correct for QuickC Versions 2.00 and earlier, as well as
 QuickAssembler Version 2.01.


 678. Example of Passing C Strings to Assembly Language

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | h_masm
 Last Modified:  5-FEB-1991    ArticleIdent: Q29113

 The following code is an example program that passes a string to an
 assembly language routine. The routine will access the string, change
 one character, and return.

 Sample Code
 -----------

 /*  C program - compile with defaults (small model) */

 #include <string.h>
 #include <stdio.h>

 void main(void);             /* Prototype for main */
 void extern changit(char *); /* Assembly routine declaration*/
 char s[10];                  /* String to be changed */

 void main()
 {
         strcpy(s,"xxxxxxxxx"); /* Initialize string to x's */
         printf("s = %s\n",s);
         changit(s);            /* Call assembly routine */
         printf("s = %s\n",s);  /* See if string changed */
 }

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

 ;Assembly language routine -- assemble with /Mx
 ;

 .MODEL SMALL
 .CODE
         PUBLIC  _changit
 _changit PROC
         push    bp                  ;Entry sequence
         mov     bp,sp

         mov     bx,[bp+4]           ;Put array address in bx
         mov     [bx+8],byte ptr 'Y' ;Change the 9th character
                                     ;0 is the first, 1 is second...

         pop     bp                  ; Exit sequence
         ret

 _changit ENDP
         END


 679. Using printf() with Far Pointers in Small Model Programs

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q29281

 Problem:

 I have a number of far pointers pointing to various data items in my
 program. I compiled the program in the small-memory model. However,
 printf() will not return the data to the area in which the pointers
 are pointing.

 Response:

 To use printf() to print data items (strings and pointers only) that
 have been declared as far in a small- or medium-memory model, use F to
 modify the %s or %p field. For example, if you have the following
 declaration

    char far *ptr;

 you can print out the value of the pointer with the following call:

    printf("%Fp",ptr);

 You also can print out the string pointed to by ptr (assuming that it
 has been initialized in your code) with the following call:

    printf("%Fs",ptr);

 For additional information on the use of the F specifier with
 printf(), refer to the  C run-time library reference or online help
 that was supplied with your particular version of the compiler.


 680. Precision of Floating Point Numbers with printf()

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q29557

 The printf() function defaults to six digits of precision when
 displaying floating point numbers, even when the value displayed is a
 double precision number.

 To see more precision, use the precision field in the following
 printf() format specification:

    %[flags][width][.precision]

 The following program demonstrates what appears to be a problem in
 printf(), but is actually documented behavior that is described in the
 online help and run-time library references for printf():

    #include <stdio.h>

    main()
    {
        double d = 1.2345678912;

        printf("%e\n", d);
        printf("%le\n", d);
    }

 The following is the output from this program:

    1.234568e+000
    1.234568e+000

 This may seem incorrect because the double variable d actually has 10
 digits of accuracy after the decimal place. However, the documentation
 for printf() states that default precision is 6 decimal places.

 To see the full precision of this number, you should use the following
 line of code:

    printf("%.15le",d);


 681. Predefined File Handles in OS/2 Are Stdin, Stdout, and Stderr

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q29559

 The only files predefined in OS/2 are the following:

    stdin, stdout, and stderr

 By default, these files have the integer file handles 0, 1, and 2.
 Under OS/2, the file handles stdprn and stdaux are not predefined as
 they are under DOS.

 Problems may occur when using the compiler for creating programs that
 attempt to write to stdaux and stdprn in OS/2 protect mode. References
 to these files are not detected by the compiler because it works in
 dual mode under both OS/2 and DOS. However, writing to stdaux or
 stdprn will fail under OS/2.

 No compiler errors, linker errors, or warnings are generated in these
 cases.


 682. _remappalette() Does Not Work on Hercules or Olivetti Cards

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q30364

 Question:

 When I try to remap the default black background color to white,
 nothing changes on my screen. I have tried _remappalette() and
 _remapallpalette(), but neither work. I am working with a Hercules
 monochrome graphics card.

 Response:

 These functions do not support the Hercules card. On page 488 of the
 "Microsoft C Version 5.10 Run-time Library Reference Manual," there is
 a note stating that _remappalette() and _remapallpalette() work only
 with an EGA or VGA card. In the C 6.00 and 6.00a online help, there is
 a note explaining that either of these functions will generate an
 error if they are called on a system with an Olivetti and Hercules
 display adapter.


 683. Linking .OBJ Files from Compilers Prior to 5.00 May Give L4051

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q30368

 Question:

 When I try to link an object module compiled with the C version 3.00
 or 4.00, the linker generates the error L4051: cannot find library.
 It then prompts me for the location of LLIBC.LIB, EM.LIB, LLIBFP.LIB,
 and LIBH.LIB. Why is it looking for these files?

 Response:

 The C compilers embed references to the default libraries in each .OBJ
 module. When you link, the linker detects these library names and
 searches the specified libraries for any unresolved references in the
 code. If the .OBJ files were compiled with C version 4.00 or earlier,
 the .OBJ modules will contain the names of the component C libraries,
 rather than the combined libraries that have been used since C 5.00.
 Because these libraries are usually not available under their separate
 names, the linker prompts you for the path specification.

 To avoid this error when linking object modules compiled with the C
 version 3.00 or 4.00 compiler with object modules compiled with C
 version 5.00 or later, you must list the combined C library explicitly
 along with the link switch /NOD. This tells the linker to ignore any
 embedded library references in the object modules.

 The following are two examples of how to link C 4.00 .OBJ files with C
 5.00 or 5.10 .OBJ files:

    link c4mod c5mod,,,llibce.lib/NOD;

 or

    cl c4mod c5mod /link llibce.lib/NOD;


 684. printf() Does Not Display Text in the Current Text Color

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 14-DEC-1990    ArticleIdent: Q30371

 It is not possible to display colored text with printf() by setting
 the text color with _settextcolor() because text output with printf()
 is not affected by the current text color.

 To display colored text, you can use the _outtext() routine but
 _outtext() does not provide text formatting capabilities like printf().
 If you need the printf() type of text formatting as well as color,
 then you should use a function such as sprintf() to print the
 formatted text to a buffer and then you can use _outtext() to print
 the buffer in the desired color.


 685. Declaring an Array of Pointers to Functions

 Product Version(s): 3.00 4.00 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-JAN-1991    ArticleIdent: Q30580

 Question:

 How do I make an array that contains callable functions?

 Response:

 The following program is an example of building an array containing
 function addresses and calling those functions:

 test1() ;
 test2() ;            /*  Prototypes */
 test3() ;

 /* array with 3 functions */
 int (*functptr[])() = { test1, test2, test3 } ;

 main()
 {
     (*functptr[0])() ;    /*  Call first function  */
     (*functptr[1])() ;    /*  Call second function */
     (*functptr[2])() ;    /*  Call third function  */
 }

 test1()
 {
     printf ("hello 0\n") ;
 }

 test2()
 {
     printf ("hello 1\n") ;
 }

 test3()
 {
     printf ("hello 2\n") ;
 }


 686. .EXE Linked with LLIBCMT Cannot Call DLL Linked with CRTLIB

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | CRTLIB DLL
 Last Modified: 14-MAR-1990    ArticleIdent: Q50695

 A design limitation in the C 5.10 library support of Dynamic Link
 Libraries (DLL) prevents statically linked, multi-threaded (MT)
 .EXE files from calling MT DLL routines. For the present, you
 must create your MT EXE files with the C run-time DLL (i.e.,
 CRTLIB.LIB).

 A specific illustration of this would be the following (assume that
 you have the following files):

    TheExe.exe: Contains a call to FOOPER, which is defined in TheDLL.dll

    TheDLL.dll: Contains the function FOOPER

 TheDLL.dll is a multi-threaded DLL, which is linked with CRTLIB.LIB
 (the multi-threaded DLL version of the C run time).

 In general, the file TheExe.exe can be linked with either LLIBCMT.LIB
 or CRTLIB.LIB (depending upon whether you desire a statically or
 dynamically linked C run-time). The following are examples of both
 link statements:

 1. Statically linked with LLIBCMT.LIB:

       link TheExe.obj,,,Doscalls.lib Llibcmt.lib/nod, TheExe.def;

 2. Dynamically linked with CRTLIB.LIB:

       link TheExe.obj Crtexe.obj,,,Doscalls.lib Crtlib.lib/nod,TheExe.def;

 However, since this example requires that TheExe.exe call FOO, which
 resides in TheDLL.dll, you must link with CRTLIB.LIB as detailed in #2
 above.

 The common symptom of linking your .EXE with LLIBCMT.LIB and calling a
 multi-threaded DLL routine is a General Protection violation (GP
 fault) upon entry into the DLL routine. The generated assembly for
 this entry is listed below:

    pop     cx
    pop     dx
    mov     bp, sp
    push    ds
    push    154F
    pop     ds
    jb      02A0

    mov     es, word ptr [005E]     <-- es loaded with trash (0)
    mov     ax, word ptr es:[0006]  <-- GP fault.

 This is an assumption that is not valid. The loading of ES assumes
 that the C run-time DLL data area is already initialized. However, it
 was not.

 The reason why this initialization did not take place is explained in
 the following scenarios:

 Note: CRT refers to C run-time.

 1. There are multiple C start-up initializations that must occur at
    process creation time:

    a. TheEXE.EXE -- Has its own start up (__astart).

    b. TheDLL.DLL -- Program's DLL must be initialized (C_INIT).

    c. C run-time DLL -- CRT's DLL DGROUP must be initialized
       (__CRT_INIT).

 2. The way these initializations happen are as follows:

    a. TheEXE.EXE -- Start up occurs "normally" when __astart gets
       control.

    b. TheDLL.DLL -- The user DLL has a starting address specified
       internally so that OS/2 executes C_INIT each time a new process
       connects to it.

    c. C run-time DLL -- The CRT DLL initialization needs information
       from the EXE start up (e.g. arguments, etc.). Thus, the current
       scheme is that the EXE start up (__astart code) explicitly calls
       the CRT DLL start-up code (__CRT_INIT).

 3. The problem: In this supplied scenario, the problem is that the EXE
    is not built with the CRT DLL model; thus, CRTEXE.OBJ is not linked
    into the user's program. It is the CRTEXE.OBJ module that makes the
    explicit call to __CRT_INIT to init the CRT DLL. Since this init
    code never gets called, the CRT's DGROUP is not initialized; later,
    when we load a value out of the CRT's DGROUP into ES,

       mov     es, word ptr [005E]     <-- es loaded with trash (0)
       mov     ax, word ptr es:[0006]  <-- GP fault.

    the value is invalid and you get the GP fault.

 Note: A program is multi-threaded when it is compiled with the
 appropriate include files and linked with the libraries that support
 multiple threads. A program does not have to call _beginthread() or
 DosCreateThread to be multi-threaded.

 If a program is compiled and linked as such, then the above problem is
 applicable regardless of the number of threads in the program. This
 means that a program with no calls to DosCreateThread and/or
 _beginthread() will lie within the scope of this problem if it is
 built as a multi-threaded executable.


 687. Time and Date from _dos_findfirst(), _dos_findnext()

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q31561

 The 2-byte return values of the time and date fields returned by
 _dos_findfirst and _dos_findnext are divided into bit ranges that must
 be translated to meaningful values. This translation is usually done
 by combinations of masking and right-shifts (>>).

 The following is the time field:

    Bits 0BH-0FH = hours (0 through 23)
    Bits 05-0AH  = minutes (0 through 59)
    Bits 00-04H  = number of 2-second increments (0 through 29)

 The following is the date field:

    Bits 09-0FH  = year (relative to 1980)
    Bits 05-08H  = month (0 through 12)
    Bits 00-04H  = day of month (0 through 31)


 688. C Run Time Can't Be Used in DLL Initialization with CRTLIB.DLL

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | SR# G891005-116
 Last Modified: 30-NOV-1989    ArticleIdent: Q50700

 Question:

 I am writing a DLL with a start-up routine written in C.

 The start-up routine is getting a protection violation within a
 sprintf call (the first call to a C run-time function).

 Can the start-up routine call the C Run Time Library?  Why is this
 bombing?

 This works correctly if I link the .DLL with LLIBCDLL.LIB and use the
 appropriate .OBJ files.

 Response:

 In general, you cannot call the run time library from a multithreaded
 .DLL initialization routine (one that uses CRTLIB.DLL).

 The reason is that C_INIT() doesn't completely initialize CRTLIB.DLL;
 this is not initialized until the .EXE start-up code is executed.

 You still must call C_INIT() from within your .DLL initialization
 routine in order to perform other necessary initializations.

 There are two possible workarounds:

 1.  Write your own functions to replace sprintf().

 2.  Don't use user initialization; instead, call an initialization
     routine in your .DLL from the beginning of your .EXE. Since
     your code in your .EXE does not execute until after the .EXE's
     start-up is executed, CRTLIB.DLL will be initialized by the time
     you attempt to initialize your .DLL.


 689. _fmalloc and halloc Run-Time Library Update

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote softlib buglist5.10 c51lib.arc
 Last Modified: 14-JUN-1990    ArticleIdent: Q32743

 The following is an application note describing the _fmalloc and
 halloc allocation limit of 4 megabytes.

 Note: This information applies to the standard run-time libraries such
 as SLIBCE.LIB, MLIBC7.LIB, etc. This information is not applicable to
 the LLIBCMT.LIB, LLIBCDLL.LIB, or CRTLIB. The 4 megabyte limit remains
 embedded in these libraries.
 The _fmalloc (which is equivalent to malloc in large and compact
 models) run-time library functions that were released with Version
 5.10 of the Microsoft C Optimizing Compiler impose an arbitrary limit
 of 4 megabyte as the amount of memory you can allocate in OS/2. In
 addition, the halloc run-time library routine impose a single
 allocation limit of 4 megabyte on memory requests.

 The files described below can be used to replace existing modules
 in your libraries in order to overcome these limits. The new limit for
 _fmalloc is 16 megabytes, while the new limit on single allocations
 with halloc is a function of the operating system, i.e., you can
 allocate as much memory as OS/2 allows.

 To update your libraries, copy all of the files listed below from
 the Software Library into the same directory as your libraries. Make
 sure that the library manager LIB.EXE also is in the current directory
 or in your PATH. You then can run the file LIBFIX.CMD to update your
 libraries. If you are running in DOS or in the DOS Compatibility Box
 in OS/2, you can run the LIBFIX.BAT batch file.

 Note that LIBFIX.CMD and LIBFIX.BAT assume that your protect-mode
 combined libraries use the default naming convention, i.e., the
 protect-mode combined library names are of the form where X is the
 memory model (S,M,C,L) and Y is the floating point option (E,A,7), as
 follows:

    XLIBCYP.LIB

 For example, LIBFIX will attempt to update the file SLIBCEP.LIB,
 the small-model emulator library for protect mode. If your protect-mode
 combined libraries are not of the form given above, it will be
 necessary for you to update your libraries manually or else modify the
 .BAT or .CMD file so that the proper libraries are updated. A sample
 command line to the library manager is as follows:

    lib -+halloc.s -+crt0.s slibcep.lib ;

 This command line will update the small-model protect-mode combined
 library. If your protect-mode library has a different name (e.g.
 slibce.lib), you would use the following command line:

    lib -+halloc.s -+crt0.s slibce.lib ;

 It is not necessary to update the real-mode combined libraries because
 the fix to the libraries does not affect programs that use the real-mode
 libraries.

 Please note that the library manager will create a backup of each
 library that it updates. Once you are satisfied that the update
 procedure is completed successfully, you can delete the files with the
 .BAK extension.

 Below is a description of the files included with this application
 note. These files can be found in the Software Library by searching
 for the filename C51LIB, the Q number of this article or S12001.
 C51LIB was archived using the PKware file-conversion utility.

    halloc.txt   This file

 The following are replacement modules to correct the limit on
 halloc:

         halloc.s    halloc.obj for small model libraries
         halloc.m    halloc.obj for medium model libraries
         halloc.c    halloc.obj for compact model libraries
         halloc.l    halloc.obj for large model libraries including
                                multi-thread and dynamic link libraries

 The following are replacement modules to correct the limit on
 _fmalloc:

         crt0.s      crt0.obj for small model libraries
         crt0.m      crt0.obj for medium model libraries
         crt0.c      crt0.obj for compact model libraries
         crt0.l      crt0.obj for large model libraries
         crt0.mt     crt0.obj for multi-thread support library LLIBMT.LIB
         crt0.cdl    crt0.obj for multi-thread DLL library CDLLOBJS.LIB
         csu.dll     crt0.obj for single thread DLL library LLIBCDLL.LIB

 If you are using _fmalloc and you require more than 16 megabytes of
 memory, you can edit the file BRKCTL.INC, which is included with the
 startup source code. Change the value MAXSEG_PM in this file and then
 rebuild the appropriate modules as outlined in the README.DOC that is
 included in the startup code directory. This value was originally 64;
 the CRT0.OBJ modules on this disk were assembled with the value of
 MAXSEG_PM set to 256.

 If the start-up code is not on your hard disk, you will need to go
 through the C Version 5.10 setup procedure again and choose the option
 to copy the start-up code to your hard disk.


 690. C2085 Error May Be the Result of a Missing Semicolon

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q32776

 The compiler error "C2085 'identifier': not in formal parameter list"
 can occur when a semicolon (;) is missing at the end of a function
 prototype.

 The following program demonstrates this error:

 void foo(void)

 void main(void)
 {
 }

 When this code is compiled, the following errors occur:

    error C2085: 'main' : not in formal parameter list
    error C2143: syntax error : missing ';' before '{'

 The C2085 error normally means that the listed parameter was declared
 in a function definition for a nonexistent formal parameter, but it's
 misleading in this case. With no semicolon to mark the end of the
 prototype, the compiler interprets the prototype as the start of a
 function definition, and interprets the next line to follow the
 prototype as if it were the first declaration within a function
 definition.


 691. C4001 and C4074 "Function Given File Scope" Warnings

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER |
 Last Modified: 31-JAN-1991    ArticleIdent: Q32778

 When compiling at warning level 4 (/W4), with language extensions
 enabled, a function prototype placed within a function will cause the
 compiler to generate the following warning:

    C4001 nonstandard extension used - 'function given file scope'

 According to the ANSI standard, functions cannot be declared with
 block scope; they must appear at file scope. The warning indicates
 that allowing the placement of the function prototype inside the block
 is an extension to the C language, and the compiler will behave as
 though the function was declared at file scope. The warning can be
 avoided by placing the function prototype outside the function.

 With C versions 5.10 and earlier, this warning occurs at warning level
 3 (/W3) and appears as follows:

    C4074 non-standard extension used - 'function given file scope'

 The sample program below demonstrates this warning.

 Sample Code
 -----------

 void main (void);
 void main (void)
  {
  void foo(int x);
  }


 692. Change in Hex Literal Interpretation with C 6.00

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 18-APR-1990    ArticleIdent: Q58488

 ANSI mandates that the \0x... character constant doesn't end until the
 first nonhexadecimal character, regardless of how many characters that
 might be.

 Microsoft C Version 5.10 ends the constant at the third character or
 just before the first nonhexadecimal character, regardless of whether
 or not characters after the third were valid hexadecimal characters.

 Therefore, while "abc\x34564gh" is represented in Version 5.10 as
 shown below

    Character       a   b   c   E   6   4   g   h
    Hex            61  62  63  45  36  34  67  68
    Decimal        97  98  99  69  54  52 103 104

 note that the character after "c" is "\x345". Since this has to fit in
 one byte, and since the rules of C say that the low bits are preserved
 when converting to a shorter type, "\x345" is equivalent to "\x45".

 In Microsoft C Version 6.00, the string is represented as follows:

    Character       a   b   c   d   g   h
    Hex            61  62  63  64  67  68
    Decimal        97  98  99 100 103 104

 Note that "\x34564" -- the character after the "c" -- is equivalent to
 "\x64" for the same reason as "\x345" was equivalent to "\x45" under
 the old rules above. The reason that the hexadecimal constant includes
 all the characters up to but not including the nonhexadecimal
 character "g" is the rule change described above. C 6.00 will issue a
 warning if the character is too large to fit in a byte -- C 5.10
 compiles such code without warnings.

 The best workaround for this change is to end the string immediately
 after the hex character and restart it. For instance, the string
 "abc\x34""564gh" is interpreted by both C 5.10 and C 6.00 as
 containing the following:

    Character       a   b   c   4   5   6   4   g   h
    Hex            61  62  63  34  35  36  34  67  68
    Decimal        97  98  99  52  53  54  52 103 104

 Such a string works properly when compiled using any ANSI compatible
 compiler.


 693. Sizeof an Undeclared Struct Causes Violation in OS/2

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 29-DEC-1988    ArticleIdent: Q39343

 The code below causes a General Protection Violation under OS/2 when
 compiled with Version 5.10 of the C compiler. The code contains an
 error; it attempts to determine the size of an undeclared structure
 "q_block" using the sizeof() function.

 This problem does not exist if the code error is corrected or if the
 include file (OS2.H) is left out.

 Microsoft has confirmed this to be a problem in Version 5.10. We are
 researching this problem and will post new information as it becomes
 available.

 The following code demonstrates the problem:

 #define   INCL_BASE
 #include  <os2.h>

 struct  q_blok  {
     char          data[80];
     };

 int   add_to_queue( int num, char *pd )
 {
   size = sizeof (struct q_block) ;   /* error: should read 'q_blok' */

   /* size = sizeof (struct q_blok) ;    Corrected code.             */
 }


 694. Incorrect Code Generation with /J

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist5.00 buglist5.10
 Last Modified:  5-JAN-1989    ArticleIdent: Q40113

 If the following program is compiled with the /J compiler option
 (which changes the default for char type from signed to unsigned) in
 the Microsoft C Optimizing Compiler Versions 5.00 and 5.10, it will
 not calculate the value of the long integer variable "result"
 correctly:

 #include <stdio.h>
 void main(void)
 {
 unsigned long result = 'b';

 result = result - 'a' + 1  ;
 printf("result = %lx", result) ;
 }

 Compiled without /J, the program works correctly. Replacing "-a+1"
 with "-96", or using a char type variable to store the value "a" also
 prevents the problem.

 Microsoft has confirmed this to be a problem in Versions 5.00 and
 5.10. We are researching this problem and will post new information as
 it becomes available.

 The following is the assembly-code listing generated with /J :

 ;|*** unsigned long result = 'b';
         mov     WORD PTR [bp-4],98      ;result
         mov     WORD PTR [bp-2],0
 ;|***
 ;|*** result = result - 'a' + 1  ;
         add     WORD PTR [bp-4],-96     ;This sets the carry flag
                                         ;incorrectly.
         adc     WORD PTR [bp-2],0

 The following is the code generated without /J :

 ;|*** unsigned long result = 'b';
         mov     WORD PTR [bp-4],98      ;result
         mov     WORD PTR [bp-2],0
 ;|***
 ;|*** result = result - 'a' + 1  ;
         sub     WORD PTR [bp-4],96      ;result
         sbb     WORD PTR [bp-2],0


 695. /Ss Fails under Environment Variable Setting

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 29-DEC-1988    ArticleIdent: Q39638

 If you set CL= in your environment with the /Ss switch and a string
 with embedded spaces within quotation marks, the listing file will not
 contain the expected results.

 For example if your AUTOEXEC file contains the following line

    SET CL=/Fs /Ss"Line with spaces"

 and you invoke the compiler with the following command, the compiler
 produces the .LST file as expected:

    CL filename.C

 However, the header would read as follows

    "Line

 instead of the following:

    "Line with spaces"

 Microsoft has confirmed this to be a problem in Version 5.10. We are
 researching this problem and will post new information as it becomes
 available.

 The workaround is to remove the /Ss"Line with spaces" from the
 environment CL setting, and either type it on the command line, or put
 it into a batch file, or make file.


 696. Graphic Functions Not Supported under OS/2 Protected Mode

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 30-DEC-1988    ArticleIdent: Q39918

 The graphics library provided with the Microsoft C Version 5.10
 Optimizing Compiler does not support OS/2 protected mode. These
 graphic functions are written strictly for real mode.

 On the Update Page 25 of the "Microsoft C 5.1 Update" section of the
 "Microsoft C 5.10 Optimizing Compiler User's Guide" section 7.2.1,
 there is a list of functions supported in real mode only. All of the
 graphics functions also should be listed.



 697. Internal Compiler Error: regMD.c 1.117 Line 292

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 14-JUL-1989    ArticleIdent: Q40499

 The following error is produced when the code sample below is compiled
 in either the large- or compact-memory models (/AL and /AC):

        fatal error C1001: Internal Compiler Error
         (compiler file '@(#)regMD.c:1.117', line 292)
         Contact Microsoft Technical Support

 The memory models small, medium, and huge do not generate this error.
 This error is produced with optimizations disabled as well as with the
 default optimizations. The error occurs on the following line:

    temp_sub[x + 1] = Themain.sub[x];

 The workaround to this problem is to declare a temporary structure to
 serve as an intermediate storage place for this assignment as follows:

    temp = Themain.sub[x] ;
    temp_sub[x+1] = temp ;

 Microsoft has confirmed this to be a problem with Version 5.10 of the
 C compiler. We are researching this problem and will post new
 information as it becomes available.

 The code below produces the offending internal compiler error. The
 workaround has been noted and commented out.

 The following is a code example:

 struct   main_def
  {
    struct   sub_def
     {
       int      max_width;
       long     start_byte, end_byte;
     } *sub;

  } Themain;

 static int test (int x)
 {
    struct sub_def *temp_sub, temp ;

    /*                           To workaround the error, replace
    temp = Themain.sub[x] ;      the assignment below with these two.
    temp_sub[x+1] = temp ;
    */

    temp_sub[x + 1] = Themain.sub[x];  /* Error occurs on this line. */
 }


 698. Internal Compiler Error getattrib.c from typedef

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 16-MAY-1989    ArticleIdent: Q40606

 The code below causes the following error in the C Version 5.10
 compiler:

    Fatal error C1001:  Internal Compiler Error
    (Compiler file '@(#)getattrib.c:1.42' line 170)
    Contact Microsoft Tech Support

 In C Version 5.00, the error will be in the following:

    (Compiler file '@(#)getattrib.c:1.40' line 162)

 In the QuickC compilers, it has random results, including hanging the
 machine, returning to the editor after compilation with no messages,
 and entering debug mode.

 The following code demonstrates the problem:

 typedef struct {
                char  foo;
                float bar;
                int   baz;
                }                /* missing declarator, semicolon */
 void main(void)
 {
 }

 The error occurs whenever the declarator and terminating semicolon are
 both omitted. If the declarator is present, but there is no semicolon,
 then the compiler catches the error.

 The declarator and semicolon are both syntactically mandatory to
 conform to the ANSI draft standard; however, C Versions 5.x0 and
 QuickC Versions 1.0x allow a typedef without a declarator to compile
 if the semicolon is present. The proper statement is as follows:

 typedef struct {
                char  foo;
                float bar;
                int   baz;
            }  boink;

 void main(void)
 {
 }



 699. Bad Code for Expression Parameter of outp() with -Oi

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881205-7390
 Last Modified: 15-JAN-1990    ArticleIdent: Q40756

 When compiling the source line below, the Microsoft C Compiler Version
 5.10 generates incorrect code in some cases for the intrinsic outp and
 outpw functions when the -Oi option is used and the second parameter
 is an expression. Workarounds are listed below.

 The following is the C source line and the generated code:

         outp(port + INT_ENABLE_OFF, (i == SIO_CNT) ? 3 : 1);

             cmp    WORD PTR [bp-6], 8                     ;i
             je    $L20003                                 ;error !
             mov   ax, 3
             jmp   SHORT $L20004
 $L20003:
             mov   ax, 1
 $L20004:
             push  ax
             mov   ax,   WORD PTR [bp-4]                   ;port
             inc   ax
             push  ax
             call  FAR PTR _outp

 This assembly code would be equal to a source line such as the
 following:

    outp(port + IN_ENABLE_OFF, (i == SIO_CNT) ? 1 : 3);

 This is the exact reverse of the original source line. Therefore, the
 generated assembler code should read as follows:

             cmp    WORD PTR [bp-6], 8                     ;i
             jne    $L20003                                ;
             mov   ax, 3
             jmp   SHORT $L20004
 $L20003:
             mov   ax, 1
 $L20004:
             push  ax
             mov   ax,   WORD PTR [bp-4]                   ;port
             inc   ax
             push  ax
             call  FAR PTR _outp

 There are two workarounds:

 1. Use a temporary variable -- for example:

        x = (i == SIO_CNT) ? 1 : 3;
        outp(port + stuff, x);

 2. Don't use -Oi.

 3. Use -Oi, but use the "#pragma function(outp outpw)" statement to
    have the non-intrinsic version of the function used.


 700. C 6.00 STARTUP.DOC: C Run-time Library Startup Sources

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | readme readme.doc start-up runtime
 Last Modified: 15-AUG-1990    ArticleIdent: Q60647

 The following information is taken from the C Version 6.00 STARTUP.DOC
 file.

 C Run-Time Library Startup Sources
 ----------------------------------

 The directory \startup and its subdirectories contain the files
 necessary for building the startup portion of the C run-time library.
 The \startup directory contains the startup source files, the include
 files, the batch file, and the make file used to build the startup
 object files. The subdirectories of \startup contain OS specific
 sources.

 The startup object files can be built by invoking STARTUP.BAT (DOS) or
 STARTUP.CMD (OS/2) from within the \startup directory. This batch file
 assumes the following:

 1. NMAKE.EXE, NMK.COM, LINK.EXE, the C compiler, and the assembler
    must be in the execution path. MASM 5.00 and C 6.00 or later are
    required to build the startup sources.

 2. For OS/2, OS2.LIB must be in the directory specified by the LIB
    environment variable.

 3. Environment variable INCLUDE must be set to the directory that
    contains your C include files.

 Startup will create four memory model specific subdirectories (i.e.,
 S, M, C, and L) and place the appropriate object files there. Under
 each memory model subdirectory, startup creates two additional
 subdirectories, OS2 and DOS, where OS specific objects reside.

 The include files STDIO.H and CTYPE.H are required for building the
 startup source file WILD.C but are not included on the \startup
 directory because they exist on the directory containing the standard
 include files. A make variable called CINC controls where the makefile
 looks for these include files. STARTUP sets CINC to the current value
 of the INCLUDE environment variable. This variable should be set to
 the location of the C include files. CINC can also be set in the
 makefile if you wish to run the makefile separately.

 The message "<cEnd - nogen>" is generated when some of the assembly
 language source files are assembled. This message is expected and is
 totally benign.

 The startup batch file requires as arguments a list of capital letters
 describing the memory models you wish to build. For example, "startup
 S L" will build the small and large model startup objects. Startup
 will then link the objects with a sample C program called NULBODY.C
 (consisting of a null main functions) to produce NULBODY.EXE.
 [Invoking startup.<bat,cmd> with no arguments will give usage
 information.]

 If you wish to build startup sources for only one operating system
 (i.e. DOS or OS/2), type "DOS" or "OS2" as the first argument to the
 startup batch file.

 Note: Startup sources written in assembly language have been edited
 with tab stops set to 8. Startup sources written in C have been edited
 with tab stops set to 4.

 The following files are contained in the \startup directory:

 Startup source files (OS independent):

   rchkstk.asm
   fmsghdr.asm
   chkstk.asm
   chksum.asm
   crt0fp.asm
   setargv.asm
   wild.c

 Startup source files (OS specific):

   crt0.asm
   crt0dat.asm
   crt0msg.asm
   execmsg.asm  (DOS only)
   nmsghdr.asm
   stdalloc.asm
   stdenvp.asm
   stdargv.asm

 Startup include files:

   cmacros.inc
   heap.inc
   msdos.inc
   msdos.h
   register.h
   rterr.inc
   version.inc

 File count files:

   _file.c
   file2.h

 Make and batch files:

    startup.bat:  Builds objs and links null program on DOS
    startup.cmd:  Builds objs and links null program on OS/2
    makefile:     Contains rules for building startup sources
    nulbody.c:    Null c program
    nulbody.lnk:  Link script for linking null program

 Documentation:

   README.DOC: Information about \startup directory structure and
               contents


 701. C 6.00 STARTUP.DOC: Placing the Stack Outside of DGROUP

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | readme readme.doc start-up
 Last Modified: 19-APR-1990    ArticleIdent: Q60648

 The following information is taken from the C Version 6.00 STARTUP.DOC
 file.

 Placing the Stack Outside of DGROUP
 -----------------------------------

 If your program requires a large amount of stack space, the run-time
 library can be configured to place the stack in a separate segment
 outside of DGROUP. By doing this, the stack can be up to 64K in size
 without reducing the amount of storage available in DGROUP for near
 data. In order to do this your program must be either compact, large,
 or huge model. You must also direct the compiler to assume that that
 SS != DS. Thus, your memory model specification should be -ACw, -ALw,
 or -AHw. See the compiler documentation for more information about
 these options.

 To use a far stack, you must assemble the startup sources provided
 with C 6.0. In the startup sources directory is a file called
 "makefile" which controls the startup module build process for the run
 time library. To enable a far stack, you need to edit the makefile.
 Near the top of the file are two lines which begin "CFLAGS=" and
 "ASMFLAGS=". You should add the text " -DFARSTACK" to the end of these
 two lines. Then build the startup modules according to instructions
 given previously in this file. You should then use the LIB utility to
 replace the startup modules in your library with the new modules you
 have built. When linking, the size of the stack can be controlled with
 the /STACK command line option.

 If you are creating DOS programs, the size of your .EXE file will be
 increased by the size of your stack. This is a consequence of the DOS
 .EXE format. To reduce the size of your .EXE file, link with the
 /EXEPACK option.


 702. Error in Adding Longs Returned by Reference

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.01 fixlist2.00 buglist5.10
 Last Modified: 16-JAN-1990    ArticleIdent: Q42213

 The program below does not properly perform the addition specified
 when compiled for the compact- or large-memory model.

 Any time three or more numbers are added (e.g in the example below)
 all values between the first and last number are incorrectly added.
 The workaround is to use temporary variables as necessary.

 Microsoft has confirmed this to be a problem in Version 1.01 and 5.10.
 This problem was corrected in Version 2.00.

 The following code demonstrates the problem:

     #include <stdio.h>

     void     * foo( long * num );

     void * foo( long * num )
     {
         return( (void *) num );
     }

     void main()
     {
         long num1  = 100,
              num2  = 200,
              num3  = 300,
              total = 0;

         total = * (long *) foo( &num1 ) +
                 * (long *) foo( &num2 ) +
                 * (long *) foo( &num3 );
         if (total != 600)
         {
             printf("Did not compute.\n");
         }
     }

 The addition is performed incorrectly because of the manner in which
 the compiler generates code to handle the intermediate value obtained
 by dereferencing the pointer returned by foo( &num2 ). In compact
 model, the relevant assembly code appears similar to the following:

     .
     .
     .
     mov     ax, word ptr es:[bx]        ; here we dereference &num2
     mov     word ptr [bp-22], ax        ;     storing the 200
     mov     ax, word ptr es:[bx+2]      ;     in bp-22
     mov     word ptr [bp-20], ax        ;     and bp-20
     .
     .
     .
     mov     word ptr [bp-24], es    ; store segment of &num2 (this was
                                     ; moved into es after being
                                     ; returned in dx earlier)
     call    _foo                        ; passing &num1 this time
     add     sp, 4
     mov     bx, ax                      ; es:bx holds address of num1
     mov     es, dx                      ; returned from foo
     mov     ax, word ptr es:[bx]        ; dereference address of
     mov     dx, word ptr es:[bx+2]      ; num1, store in ax, dx
 *   mov     bx, word ptr [bp-24]        ; here's the bad one:  bp-24
 *   add     ax, word ptr [bx]        ; contains the segment of &num2
 *   adc     dx, word ptr [bx+2]         ; not the contents of &num2
     add     ax, si                      ; add num3, which was
     adc     dx, si                      ; stored in si + di
     .
     .
     .

 The function foo is called with &num3, &num2, and &num1, in that order.
 The contents of num3 (300 in this case) are stored in the si and di
 registers. The contents of num2 (200 in this case) are stored in bp-22
 and bp-20. At the same time this is done, the segment of &num2 is stored
 in bp-24. The contents of num1 (100 in this case) are stored in the ax,
 dx register pair.

 The problem occurs when an attempt is made to add num2. Even though
 it was stored properly, the instructions generated to perform the
 addition try to retrieve the value of num2 by using the segment stored
 in bp-24 as an offset, rather then directly adding what was stored.
 Replacing the three lines marked with an asterisk with these three
 lines produces the correct result, as follows:

    mov     es, [bp-24]
    add     ax, es:[bp-22]
    adc     dx, es:[bp-20]



 703. C 6.00 SAMPLES.DOC File

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | readme readme.doc programmer's workbench
 Last Modified: 19-APR-1990    ArticleIdent: Q60649

 The following information is taken from the C Version 6.00 SAMPLES.DOC
 file.

 SAMPLES.DOC File
 ----------------

 Notes on sample programs included with the Microsoft(R) C Optimizing
 Compiler Version 6.00 (C) Copyright Microsoft Corporation, 1990.

    Files              Description
    -----              -----------

    GRDEMO.MAK         GRDEMO illustrates general graphics techniques
    GRDEMO.C           including drawing, animation, palette
    MENU.C             switching, window adjustment, menus, and
    MENU.H             turtle graphics. The MENU and TURTLE modules
    TURTLE.C           are independent modules that could be used
    TURTLE.H           in your own programs. Real mode only.

    CHRTDEMO.MAK       CHRTDEMO illustrates presentation graphics
    CHRTDEMO.C         techniques. You can use this program as a tool
    CHRTSUPT.C         for testing different modes and options before
    CHRTDEMO.H         building them into your own programs. Real mode
                       only.

    SORTDEMO.C         Visually illustrates six different sorting
                       algorithms. The source code demonstrates how
                       to make OS/2 calls. Real or protect mode.

    SNAP.C             Runs in the background and saves the current
                       screen in a file when a hot key is pressed.
                       Protected mode only.

    INCLUDE.C          A PWB extension file that implements an include
                       command that finds and opens include files.

    TXTFMT.C           A PWB extension file that implements various
                       commands related to text formatting. You can use
                       these commands to format paragraphs, center
                       text, change case, and insert or delete tab
                       spaces.

    FILTER.C           A PWB extension file that implements a filter
                       command. You can use it to replace a block of
                       text with the output of a user-specified
                       filter (such as the DOS SORT program).


 704. /Zg Misspells the Word "Interrupt" for Function Pointers

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 18-MAY-1989    ArticleIdent: Q42760

 When the following program is compiled with /Zg switch to generate
 function declarations from function definitions, an incorrect function
 declaration for function X is generated. Part of the output that /Zg
 produces is the following:

 extern int x(void(_interrurt far *r)());

 The word "interrupt" is misspelled.

 The correct function declaration should be the following:

 extern int x(void (interrupt far *r)());

 To work around the problem, use an editor to correct the misspelling
 in the output file.

 Microsoft has confirmed this to be a problem in Version 5.10. We are
 researching this problem and will post new information as it becomes
 available.

 A program example that demonstrates this problem is the following:

 main()
 {
 }

 x(r)
 void (far interrupt *r)();
 {
 }


 705. Activating Hercules Card on a Dual-Monitor System

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist5.10 S_QUICKC
 Last Modified: 17-MAY-1989    ArticleIdent: Q42925

 Part 3 of the Microsoft C Optimizing Compiler Version 5.10 README.DOC
 states the following:

   If you have both a Hercules monochrome card and a color video
   card, you should invoke MSHERC.COM with the /H (/HALF) option.
   The /H option causes the driver to use one instead of two
   graphics pages. This prevents the two video cards from
   attempting to use the same memory. You do not have to use the
   /H option if you have only a Hercules card.

 The /H option fails to work correctly on a system with two video
 cards, where one of the cards is a compatible Hercules card.

 This is not a problem with MSHERC.COM. The source of the problem lies
 in the graphics library provided with Microsoft C Optimizing Compiler
 Version 5.10 and QuickC Version 1.01.

 This problem has been corrected in QuickC Version 2.00. The QuickC
 Version 2.00 include files, libraries, and linker are fully compatible
 with C 5.10. Upgrades are available for the C Optimizing Compiler and
 prior versions of QuickC. Information on upgrades is available from
 Customer Service.

 You also must use the DOS MODE command to activate the monochrome card
 prior to sending output to the Hercules display adapter.

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



 706. Optimization Problem with SHIFTing and ANDing

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 17-MAY-1989    ArticleIdent: Q43061

 When compiled with CL, the default optimization setting (/Ot) will
 cause the following source code to produce erroneous results. The
 problem only appears if the value being shifted is a variable and the
 masking value is a constant. The number of bits to shift can be a
 constant or a variable. Other combinations of variables and constants
 are evaluated correctly by the compiler.

 Compiling with /Od solves the problem. Using temporary variables also
 produces the correct results.

 Microsoft has confirmed this to be a problem with Version 5.10. We are
 researching this problem and will post new information as it becomes
 available.

 Both of the expressions should evaluate to 0x0000, but when optimized,
 they evaluate to 0x0100.

 /*  Example of optimizing problem with SHIFTing and ANDing.
  */
 #include <stdio.h>

 #define SHIFT 0x0002
 #define MASK  0x00FF

 void main( void )
 {
     unsigned short usResult;
     unsigned short usStart;
     unsigned short usShift;

     /*  With a variable, a constant, and another constant.  */
     usStart = 0x0040;

     /***  PROBLEM WITH FOLLOWING EXPRESSION!  ***/
     usResult = (usStart << SHIFT) & MASK;
     printf( "Result #1: %4.4X\n", usResult );

     /*  With a variable, another variable, and a constant.  */
     usStart = 0x0040;
     usShift = SHIFT;

     /***  PROBLEM WITH FOLLOWING EXPRESSION!  ***/
     usResult = (usStart << usShift) & MASK;
     printf( "Result #2: %4.4X\n", usResult );
 }



 707. Incorrect Code Generated with Conditional Operator

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist5.10
 Last Modified: 16-JAN-1990    ArticleIdent: Q43062

 Using the conditional with incremental operators on pointers can
 generate incorrect code. The following routine should reset ptr to the
 beginning of the list if the end of the list has been reached. If the
 end of the list has not been reached, ptr should be incremented. The
 code generated does not increment ptr as expected; ptr is actually
 reset to itself, i.e., ptr = ptr.

 Replacing the ternary operator (? :) with an if -- else construct
 corrects the problem.

 Microsoft is researching this problem and will post new information as
 it becomes available.
 The following routine illustrates this behavior:

 test()
 {
         char *ptr,*str,*end;

         ptr = ((ptr == end)? str: ptr++);

 }


 708. Using printf with %p in Small or Medium Model

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q43173

 When using the %p format in the C Run-Time Library function printf()
 in the small or medium memory model, the corresponding argument must
 be cast to a far pointer. If the argument is not cast to a far
 pointer, the segmented address of the pointer will not be displayed
 correctly.

 This behavior occurs because printf does not have a formal parameter
 list that will automatically cause the type conversion to take place.
 In small or medium memory model, a pointer argument will be pushed
 onto the stack as a near address if it is not cast to a far pointer,
 i.e., only the offset is pushed onto the stack. At run time, printf
 sees %p and then assumes both the segment and the offset for the
 corresponding argument are pushed onto the stack. This action causes
 the function to print an incorrect segment for that argument.
 Explicitly casting the argument to a far pointer will force the
 segment address to be pushed onto the stack as well.

 The following program will point the wrong content of the variable ch:

 /* sample program */
 #include <stdio. h>

 char ch[1] ;
 void main (void)
 {
 printf ("ch = %p\n", ch) ;    /* wrong !! */
 }
 /* end of sample program */

 The following is the correct statement in small and medium model:

     printf ("ch = %p\n", (char far *) ch) ;



 709. Tips for Reducing Prolog/Epilog Code in Windows or PM Apps

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q58489

 -Gq was a secret switch in C Version 5.10 to generate a reduced
 Windows prolog/epilog code sequence for routines that were not
 "callbacks"; it was identical in functionality to the new (documented)
 -GW switch.

 The table below lists the changes to the command line when compiling
 with C Version 6.00. The first column (Old Way) lists switches as
 recommended by Charles Petzold in "Programming the OS/2 Presentation
 Manager" and "Programming Windows." The second column is the new
 recommended way.

 Presentation Manager
 --------------------

                      Old Way           New Way
                      -------           -------

    User code         -Gw               ---
    User callback     -Gw _export       _loadds

    DLL entry         -Au _export       -Aw _loadds _export
    DLL internal      -Au               -Aw

 Windows
 -------

    User code         -Gw               -GW
    User callback     -Gw _export       (unchanged)

    DLL entry         -Gw -Aw _export   (unchanged)
    DLL internal      -Gw -Aw           -GW -Aw

 Windows Notes:

 1. You also need -Zp.

 2. Winmain is a special case and should be -Gw _export, not -GW.

 3. By using _export you don't need a def file; however, there are
    other advantages to using a def file. For example, you can export
    your entry points by number instead of by name, saving space in the
    resident name table and making more space for your application.

 4. Other references claim you should use -Au (equivalent to -Aw +
    _loadds); we claim the _loadds is not needed for windows since they
    all have a special DS sequence.


 710. C 5.10 Won't Compile QuickC 2.00 GRDEMO.C and TURTLE.C

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-MAY-1989    ArticleIdent: Q43704

 The QuickC Version 2.00 sample programs GRDEMO.C and TURTLE.C produce
 internal compiler errors when compiled under the Microsoft C
 Optimizing Compiler Version 5.10. Several particularly complex
 expressions cause the problem, some of which are due to macro
 expansions from the QuickC 2.00 GRAPH.H include file. Using
 temporary variables in these expressions eliminates the errors. The
 following error message is displayed:

    grdemo.c(291) : fatal error C1001: Internal Compiler Error
              (compiler file '@(#)grammar.c:1.29', line 108)
              Contact Microsoft Technical Support

 The GRDEMO.C and TURTLE.C programs were developed for QuickC 2.00 and
 as such are not guaranteed to compile with the C 5.10 optimizing
 compiler. C 5.10 compiles its own demonstration programs without
 difficulty.


 711. C: /Oa Causes Changes in Variable Values to Be Ignored

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890421-16911 alias buglist5.10
 Last Modified:  1-JUN-1989    ArticleIdent: Q43912

 The code generated by the following program is incorrect when
 compiled with /Oa (with or without other optimizations). Two workarounds
 are to compile without /Oa or to use a temporary variable.

 A program that demonstrates the error and an assembly listing of the
 code follows:

 Source:

 static int index;
 static int len;
 static char *strbuf;

 void main()
 {
     if (index >= len)
     {
         strbuf[len++] = ' ';      /* works correctly */
         strbuf[len] = '\0';       /* null is put in the wrong place! */
     }
 }

 Assembly listing:

 _main:
 7:      {
 5C83:0000 56             PUSH      SI
 8:          if (index >= len)
 5C83:0001 A1DE01         MOV       AX,Word Ptr [len (01DE)]
 5C83:0004 3906DA01       CMP       Word Ptr [index (01DA)],AX
 5C83:0008 7C13           JL        _main+1d (001D)
 10:            strbuf[len++] = ' ';               /* works correctly */
 5C83:000A BEDE01         MOV       SI,len (01DE)
 5C83:000D 8B1C           MOV       BX,Word Ptr [SI]
 5C83:000F FF04           INC       Word Ptr [SI]
 5C83:0011 8B36DC01       MOV       SI,Word Ptr [strbuf (01DC)]
 5C83:0015 C60020         MOV       Byte Ptr [BX+SI],20
 11:            strbuf[len] = '\0';    /* null is put in the wrong place */
 5C83:0018 8BD8           MOV       BX,AX
 5C83:001A C60000         MOV       Byte Ptr [BX+SI],00
 13:     }
 5C83:001D 5E             POP       SI

 The "MOV BX, AX" generated for "strbuf[len] = '\0';" above should be a
 "MOV BX, [len]". AX contains the old value of len at this point, not
 the incremented value.


 712. Internal Compiler Error: grammar.c:1.29, Line 108

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10 s_quickc
 Last Modified: 26-JAN-1990    ArticleIdent: Q44077

 The program below causes the Microsoft C 5.10 Optimizing Compiler to
 produce the following error:

    foo.c(10) : fatal error C1001: Internal Compiler Error
         (compiler file '@(#)grammar.c:1.29', line 108)
         Contact Microsoft Technical Support

 This error also may be caused by using either graphics function
 _moveto_w or _lineto_w when compiling with QuickC 2.00 header files
 such as graph.h. In this case, the error is a result of the expression
 resulting from the expansion of the _moveto_w and _lineto_w macros, or
 several other window macros. An example of this is TURTLE.C and
 WINDOW.C from the GRDEMO sample program that comes with QuickC 2.00.

 Microsoft has confirmed this to be a problem in Version 5.10. We are
 researching this problem and will post new information here as it
 becomes available.

 The following program causes the internal compiler error:

 struct ice
 {
      short x, y;
 };

 struct ice think(double);
 void Just(struct ice);

 void main(void)
 {
     Just(think(6.00));
 }

 In the sample program above, the error can be worked around by
 changing the structure ice to the following:

 struct ice
 {
      short x,y;
      int fudge_factor;
 };


 713. Internal Compiler Error: omf.c:1.70 Line 146

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 30-MAY-1989    ArticleIdent: Q44300

 The following error message is produced when the example below is
 compiled with the Microsoft C Optimizing Compiler Version 5.10:

    fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)omf.c:1.70', line 146)
                    Contact Microsoft Technical Support

 To prevent the error message, reverse the order of the #pragma and
 #include directives.

 Microsoft has confirmed this to be a problem in Version 5.10. We are
 researching the problem and will post new information as it becomes
 available.

 Support for the data_seg pragma may be eliminated from future releases
 of the C Optimizing Compiler. We recommend that you use the /ND
 compiler option which provides equivalent functionality.

 The following example demonstrates the problem:

 #include "os2def.h"            /* os2def.h from IBM's toolkit v1.1 */
 #pragma data_seg( global )

 char *errors[] = {
    "no error",
    "unknown error"
   };

 To prevent the problem, reverse the order of the #pragma and #include
 directives, as follows:

 #pragma data_seg( global )
 #include "os2def.h"


 714. Short Jump to 80 Bytes Forward Generated with C 5.10

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 19-SEP-1989    ArticleIdent: Q44564

 The C Version 5.10 compiler has been shown to produce code for a short
 jump 0x80 bytes forward. However, when this code is executed, it jumps 0x80
 bytes backward because the number is considered negative. Source code
 that exemplifies this problem is too large to post here, and the
 problem disappears with almost any change to the source code.

 Microsoft has confirmed this to be a problem with C Version 5.10. We
 are researching this problem and will post new information as it
 becomes available.

 The executable file symptoms can range from hanging to infinite
 looping.

 The following is an excerpt from a .COD file produced by the C 5.10
 compiler when compiled with /AL /Ox. The second assembly statement for
 Line 79 shows the incorrect jump (je $FB331) of 80 hex bytes.

 ;|***         if(didid == -1)
 ; Line 79
   *** 00034f 83 be 52 fe ff  cmp WORD PTR [bp-430],-1 ;didid
   *** 000354 74 80           je  $FB331
 ;|***              break;
 ; Line 80
                     .
                     .
                     .

   *** 0003d1 2a e4           sub ah,ah
   *** 0003d3 e9 62 fe        jmp $L20017
                    $FB331:


 715. Side Effects in ISRs and Signal Handlers Confuse Optimizer

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuicKc
 Last Modified:  1-JUN-1989    ArticleIdent: Q44723

 It can be dangerous to allow the Microsoft C or QuickC compiler to
 perform loop optimization on code that contains global variables that
 may be modified in interrupt service routines or signal handlers.
 For example, consider the following code

     int TimerCount = 1000;

     while( TimerCount );
     printf( "Timer expired." );

 where an ISR is concurrently executing the following:

     void interrupt far ISR()
     {
         TimerCount--;
     }

 This is acceptable code and performs a simple task -- it waits for a
 global timer variable to reach 0, indicating that the ISR has been
 executed a specified number of times. However, the loop optimization
 optionally performed by the compiler results in the while() loop being
 completely removed from the executable code. Because the compiler does
 not know that the ISR is simultaneously accessing TimerCount, it sees
 no reason to keep an expression that obviously evaluates to true and
 does nothing but waste time. This is NOT a problem with the compiler.
 Section 2.1.2.3 of the 7 December 1988 ANSI C draft standard states
 the following:

    An actual implementation need not evaluate part of an expression
    if it can deduce that its value is not used and that no needed
    side effects are produced (including any caused by calling a
    function or accessing a volatile object).

 Because C 5.10 does not semantically implement the "volatile" keyword,
 there is no way to indicate that TimerCount is volatile and that the
 expression involving TimerCount should not be removed from the program
 by the optimizer. Thus, it is reasonable for the compiler to assume
 that this expression is not necessary and may be safely removed.

 When writing code for Interrupt Service Routines or signal handlers
 that expect conditions that the compiler cannot predict, care should
 be used in the choice of optimizations; and, if needed, an assembly
 code listing should be generated with the /Fc or /Fs /Fa switches and
 examined for the optimization's effect. Disabling optimization with
 /Od may result in slower executable programs but will prevent
 optimizer side effects.


 716. -FPc Generates Call to __fld1 with ++ Operator

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 19-SEP-1989    ArticleIdent: Q45094

 In certain cases, code that uses the post increment operator on a
 float variable causes the Microsoft C 5.10 compiler to generate a call
 to __fld1. This function is not present in any of the Microsoft C
 libraries and results in an unresolved external at link time. If the
 post increment is performed on the right side of an assignment
 statement and the code is compiled for floating point coprocessor
 calls, the reference to __fld1 will be made. The following program
 demonstrates the problem when compiled with this command line:

     cl -FPc file.c

     /* file.c */
     void main(void) {
         float a;
         a = a++;        /* Generates call to __fld1 */
         a++;            /* Does not generate call to __fld1 */
         a += 1.0;       /* Does not generate call to __fld1 */
     }

 fld1 is an 8087 instruction that increments a real by 1.0. Microsoft
 has chosen not to emulate this instruction. The call to this
 instruction is a code generation error on the part of the compiler.

 To work around this problem, add 1.0 to the variable instead of using
 the post increment operator. Compilation with the -FPi (default)
 option does not produce such an error. Compiling for floating point
 emulation math eliminates the problem as well.

 Microsoft has confirmed this to be a problem with C Version 5.10. We
 are researching this problem and will post new information as it
 becomes available.


 717. Internal Compiler Error: ctypes.c Line 474

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-SEP-1989    ArticleIdent: Q46206

 The program below, when compiled with /Oi, will generate the following
 error:

    program.c(27) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)ctypes,c:1.107', line 474
                    Contact Microsoft Technical Support

 The program has only one line of executable code, which is a memcpy
 statement. If the program is recompiled at warning level 3, it becomes
 obvious that the header file <memory.h> has not been included. If the
 proper header file is included, the program will not compile, giving
 the following two errors:

    Error C2172 : 'memcpy' : actual is not a pointer : parameter 1
    Error C2172 : 'memcpy' : actual is not a pointer : parameter 2

 The program is in error. Instead of trying to pass structures to
 memcpy, it should pass a pointers to structure. To solve the problem,
 correct the program to pass pointers to structure.

 Program Sample
 --------------

 #include <stdio.h>

 struct r_buff
 {
    union
       {
       unsigned char far *in_offset;
       struct
          {
          unsigned char *index;
          unsigned char *segment;
          } in_s;
       } in_u;
    unsigned char *out_index;
    unsigned char *lim;
    unsigned char *first;
    int loww;
    int hiw;
    unsigned char stat;
    char reserved[5];
 } read_b;

 struct r_buff old_read_b;

 void main(void)
 {
   memcpy(old_read_b, read_b, sizeof(old_read_b));
   /* This code is incorrect.  Instead use:
       memcpy(&old_read_b, &read_b, sizeof(old_read_b));
   */
 }


 718. C 5.10 Internal Compiler Error C1001: pgoMD.c : 1.134 Line 146

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q46379

 Using a structure as the conditional argument of a ternary expression
 causes an internal compiler error if the structure contains three or
 more elements. The following error message is displayed:

    struct.c(15) : fatal error C1001: Internal Compiler Error
              (compiler file '@(#)pgoMD.c:1.134', line 1467)
              Contact Microsoft Technical Support

 The ternary operator, as defined in the Microsoft C Version 5.10
 user's guide, accepts three operands. The conditional operand is
 required by Microsoft C to be of type integral, float, or pointer. Any
 other type (including struct) is undefined.

 If the structure contains less than three elements, no error is
 produced but the code will be undefined.

 To work around the problem, use an if statement with appropriate
 assignments rather than the conditional operator.

 The following program produces the internal compiler error:

 #include <stdio.h>
 struct { int a;
          int b;
          int c; } s;
 void main(void)
 {
   printf("the value %d\n", s ? 1 : 2);
 }

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


 719. Library Support for Near, Far, and Huge Keywords

 Product Version(s): 5.00 5.10 | 5.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | mixed memory model S_QuickC
 Last Modified: 18-AUG-1989    ArticleIdent: Q46820

 When using the "near", "far", and "huge" keywords to override
 addressing conventions within specific memory models, you can usually
 use one of the standard libraries. Often, you cannot pass far
 pointers, or the addresses of far data items, to a small-model library
 routine. Some exceptions are the library routines "halloc", "hfree",
 and the "printf" family of functions.

 For additional information, refer to the "Microsoft C Optimizing
 Compiler User's Guide," Page 145.

 Mixed-memory-model programming uses the "near", "far", and "huge"
 keywords to locate code or data outside of the segments specified by
 the memory model, e.g. declaring a "far" character array in a small
 memory model where it would ordinarily be "near".

 Mixed-model programming is useful when you have only a bit of data to
 put outside of the single data segment and you don't want to switch to
 a multiple-data-segment memory model. The standard library routines,
 however, were written to support the standard memory models, and so
 must be used with care.

 The following example demonstrates a function that performs as
 expected in large or compact model but returns incorrect results in
 the medium or small model because its data, "buffer", was declared
 "far":

 char far buffer[100];
 .
 .
 .
 fwrite ( buffer, size, count, stream);

 In single-data-segment models, data addresses are 2-bytes long. In
 multiple-data-segment models, data addresses are 4-bytes long. Data
 declared "far" also has 4-byte addresses. When fwrite() is called in a
 single-data-segment model, it expects 2-byte, not 4-byte, data
 addresses.

 Removing the "far" keyword or compiling in a multiple-data-segment
 model corrects the problem. Another solution is to assign the value of
 the far variable to a near variable. In the example below, each
 element of the far array is assigned to the near array. A strcpy()
 cannot be used in this case, since it is one of the library functions
 that operates properly only when the data addresses are consistent
 with their memory model:

 char far buffer[];
 char nearbuffer;   /* near by default in small and medium models */
 int i;

 for (i = 0; i < 100; i++)
   nearbuffer[i] = buffer[i];
 .
 .
 .
 fwrite ( nearbuffer, size, count, stream);



 720. C Version 5.10 Does Not Handle const Keyword Like ANSI

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890706-22068
 Last Modified: 18-AUG-1989    ArticleIdent: Q46993

 Consider the following program "fubar.c":

 1:  void main(void)
 2:      {
 3:      char * const String;
 4:
 5:      *String   = 'a';
 6:      String[0] = 'a';
 7:      }

 Lines 5 and 6 would be expected to have the same effect. However,
 compiling

    cl fubar.c

 produces the following error message:

    fubar.c(6) : error C2166: lval specifies 'const' object

 If the "const" attribute is removed from the declaration of "String",
 the error message is eliminated. As per the ANSI C usage of "const",
 Lines 5 and 6 should indeed be synonymous.

 Response:

 Version 5.10's handling of const doesn't quite match the current ANSI
 draft, and works inconsistently.

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

 Note: according to ANSI, to create the error on the two lines
 consistently, you need to use

    const char * string = "This is a string";

 or (equivalently)

    char const * string = "This is a string";

 both of which say that "string" points to a const char. The following
 line says that the pointer "string" is constant, but the char to which
 it points is not -- so no error occurs:

    char * const string = "This is a string";

 To make both constant, use the following:

    const char * const string = "This is a string";

 Note that the above four examples do not work correctly on Version
 5.10. This feature is under review and should be fixed in the next
 release.


 721. Internal Compiler Error: grammar.c:1.29, Line 108

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q46994

 The program below generates the following error when compiled with the
 default command line options under the Microsoft C Optimizing Compiler
 Version 5.10:

    func.c(11) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)grammar.c:1.29', line 108)
                    Contact Microsoft Technical Support

 Compiling the following program demonstrates the error:

 #include <stdio.h>

 double fctn( void )
 {;}

 double( *call[] )( void ) = { fctn };

 void main( void )
 {
     printf("%lf\n", call[0]() );
 }

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

 To eliminate the problem, the printf() statement can be broken up into
 two statements, thereby making the function call and assigning it to a
 temporary double variable in one statement, then printing that
 variable in a second statement. The following code exemplifies this:

 #include <stdio.h>

 double fctn( void )
 {;}

 double( *call[] )( void ) = { fctn };

 void main( void )
 {
     double temp;

     temp = call[0]();
     printf("%lf\n", temp );
 }


 722. Variable Arguments of Type CHAR Incorrectly Retrieved

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | s_quickc buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q58490

 If a procedure with variable parameters uses either va_start or va_arg
 on a variable of type CHAR, all subsequent parameters retrieved with
 va_arg will return an incorrect value.

 Below there are two separate discussions, one for the workaround, and
 one for a description of the problem.

 Discussion of the Workaround
 ----------------------------

 The following program illustrates the problem:

 #include <stdio.h>
 #include <stdarg.h>

 #define VA_START_CHAR(ap,v) (ap) = ((va_list) (&v) + sizeof (int))

 void main (void) ;
 void foo  (int, ...) ;
 void goo  (char, ...) ;

 void main (void)
 {
     int x = 3 ;
     char j = 'f' ;

     foo (5, j, x) ;
     goo (j, 5, x) ;
 }

 void foo (int s, ...)
 {
     char c ;
     int  i ;

     va_list arg_marker ;

     va_start (arg_marker, s) ;

     c = va_arg (arg_marker, char) ;
     i = va_arg (arg_marker, int) ;

         printf ("FOO (%d, %c, %d)\n", s, c, i) ;

         va_start (arg_marker, s) ;

         c = (char) va_arg (arg_marker, int) ;
         i = va_arg (arg_marker, int) ;

         printf ("FOO (%d, %c, %d)\n\n", s, c, i) ;
 }

 void goo (char s, ...)
 {
     int  i, i2 ;

     va_list arg_marker ;

     va_start (arg_marker, s) ;

     i = va_arg (arg_marker, int) ;
     i2 = va_arg (arg_marker, int) ;

         printf ("GOO (%c, %d, %d)\n", s, i, i2) ;

         VA_START_CHAR (arg_marker, s) ;

         i = va_arg (arg_marker, int) ;
         i2 = va_arg (arg_marker, int) ;

         printf ("GOO (%c, %d, %d)\n", s, i, i2) ;

 }

 The output of the program is as follows:

 FOO (5, f, 768)
 FOO (5, f, 3)

 GOO (f, 1280, 768)
 GOO (f, 5, 3)

 The program shows both the typical way to retrieve variable arguments,
 and a way around the problem with a variable of type CHAR.

 If a function has a type CHAR as being one of the variable arguments
 and attempts to retrieve it with a call to va_arg (arg_marker, char),
 the correct value will be returned. Unfortunately, the arg_marker is
 incremented to an incorrect value. The next time that a variable is
 referenced off of arg_marker, va_arg will return an incorrect value.

 An easy way around this is to have va_arg return an INT, then just
 typecast the return value of va_arg to a CHAR.

 The function foo demonstrates both ways of retrieving arguments and,
 as you can see from the output, using the INT and then typecasting
 that value to a CHAR does work.

 A second problem with variable arguments and variables of type CHAR is
 when the first argument (the one actually defined) is of type CHAR. A
 call to va_start is supposed to set arg_marker to the next parameter.
 Again, arg_marker is set to an incorrect value. Any subsequent calls
 to va_arg will return an incorrect value.

 One way around this is to redefine va_start to the following macro:

    #define VA_START_CHAR(ap,v)     (ap) = ((va_list) (&v) + sizeof (int))

 This works in the special case of a CHAR as being the value that you
 are attempting to set the frame reference (arg_maker in the program
 and ap in the macro) relative to. It also works if the type sent is an
 INT.

 Discussion of the Problem (Description of the Problem)
 ------------------------------------------------------

 All CHAR values are pushed onto the stack in two bytes, rather than
 one. In STDARG.H, both va_start and va_arg use a sizeof operation to
 decide how much to move the frame reference. Because sizeof returns a
 1 (one) for a type CHAR and the value actually takes two bytes on the
 stack, va_start initializes the frame reference incorrectly, and
 va_arg increments the frame reference incorrectly.

 When we force va_start to use a type INT, it moves the frame reference
 to the correct position, and when we use an INT in va_arg, it forces
 the frame reference to be incremented by the correct amount.


 723. Second sscanf Fails After sscanf Using %i Format

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 26-JUL-1989    ArticleIdent: Q47026

 The Microsoft C 5.10 run-time function sscanf fails to scan a string
 if the following conditions are met:

 1. An initial sscanf using the %i format specifier is carried out on a
    string with leading white space characters.

 2. A second sscanf of a string with leading white space characters
    will fail.

 To work around this problem, do one of the following:

 1. Change the format string "%i" to "%d".

 2. Change the format string for the second and all following sscanf's so
    that it causes all leading spaces to be removed. For example, use a
    format of " %d" instead of "%d".

 The following program demonstrates this problem when compiled
 with Microsoft C 5.10 using default compiler options:

 #include <stdio.h>

 void main(void)
 {
   char  *str1= "  23  ";
   char  *str2= "  99  ";
   int   val0;
   int   val1;
   int   val2;

   sscanf(str2,"%d", &val1);     /* this line works correctly */
   sscanf(str1,"%i", &val0);     /* this line works correctly */
   sscanf(str2,"%d", &val2);     /* this line will fail       */

   if(val1 != val2)
         printf("sscanf test failed \n");
   else
         printf("sscanf passed test\n");
 }

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


 724. How to Reboot Your Machine within a Pure C Application

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_QuickASM
 Last Modified: 16-AUG-1989    ArticleIdent: Q47634

 Question:

 How can I cause my machine to reboot itself from within my pure C
 program? Interrupt 19H does not accomplish this task.

 Response:

 You can do a complete reboot on an 8086-based machine by jumping to
 the address F000:FFF0. This action also reboots many 80286 and 80386
 machines. The address contains a jump instruction that leads to the
 machine's initialization code. For this method to succeed, your
 machine must be in real-mode operation.

 To prevent a memory check (on IBM and many compatibles), you should
 store the value 0x1234 in the memory location at 0040:0072.

 The following functions reboot your system without a memory check. If
 you wish to allow the memory check to occur, you must remove the
 single line comment delimiters, "//", from the lines involving
 "memchk".

 //int far *memchk ;

 void (far *reboot)( void ) = (void far *)0xf000fff0 ;

 void main ( void )
 {
   // memchk = (int far *)0x00400072 ; /* address of mem. check control */
   // *memchk = 0x1234 ;               /* disable memory check          */

   (*reboot)() ;                       /* reboot your machine           */
 }


 725. C 5.10 Multi-Thread Library or DLL Limited to 32 Threads

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 16-JAN-1990    ArticleIdent: Q47932

 The C 5.10 statically linked, multi-thread library LLIBCMT.LIB and
 the dynamically linked, multi-thread CRTLIB.DLL only support a single
 process's threads numbered 1 to 32 inclusive. This limits an
 application that uses C run-time functions to creating 31 threads with
 the _beginthread() function, in addition to the process's initial
 thread 1.

 If you call C run-time library (or DLL) functions from thread 33 or
 higher, no error message will be issued, but you will get undefined
 results including incorrect data and segment violations. Note that
 creating threads that call C run-time library functions should be done
 with the _beginthread() function to perform required C-library
 initializations that are not performed by DosCreateThread().

 Since the thread maximum number 32 limit is per process, calling
 another DLL does not increase the number of supported threads since
 the instance of the DLL called by the process is effectively part of
 the process. Spawning or exec'ing a child process allows the new
 process a new set of threads 1-32.

 A substantially greater number of threads will be considered for
 inclusion in a future release.


 726. Library Compatibility between BASIC and C

 Product Version(s): 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC appnote
 Last Modified: 16-JAN-1990    ArticleIdent: Q49314

 The following is a table of libraries that are compatible between
 different versions of BASIC and C:

    QuickBASIC      BASIC Compiler  <->     C       QuickC
    ----------      --------------  ---     -       ------

    4.00             --             <->    5.00     1.00
     --             6.00            <->    5.10     1.01
    4.00b    or     6.00b           <->    5.10     1.01
    4.50             --             <->    5.10     2.00 or 2.01

 In QuickBASIC Versions 1.00, 1.01, 1.02, 2.00, 2.01, and 3.00, you can
 call only QuickBASIC subprograms or Microsoft assembler routines.

 This table is available as an application note titled "How to Pass
 Parameters between BASIC and C", which also contains information on
 Basic and C mixed-language programming. You can obtain this
 application note by calling (206) 454-2030.


 727. typedefs Not Allowed for Function Definitions

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified: 16-JAN-1990    ArticleIdent: Q49571
 It is not valid to use a typedef statement in a function definition
 according to the ANSI C draft, December 7, 1988, Section 3.7.30, and
 also Footnote 76, which state, "The intent (of the rule) is that the
 type category in a function definition cannot be inherited from a
 typedef". This statement applies to Microsoft C Versions 5.00 and
 5.10. Using typedefs in function definitions can cause various errors
 at compile time. The function definition is followed by the function
 body included in "{}" (curly braces).

 The following code fragment produces errors at compile time due to the
 typedef in the function definition. In the code sample, error C1059
 "out of near heap space" is generated. Making slight modifications to
 the code, however, produces various other errors such as error C2055
 "expected formal parameter list, not a type list".

 Code Sample
 -----------

      #include <stdio.h>

      typedef void FTYPE (int f);

      FTYPE foo_function  /* function definition with type from typedef
                                 is a syntax constraint error */
      { printf ("f=%u",f);
      }

 Microsoft has confirmed this to be a problem with C Version 5.10. We
 are researching this problem and will post new information as it
 becomes available.


 728. DLLs Built with C 5.10's LLIBCDLL.LIB Limited to 20 Files

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50335

 Single-thread Dynamic Link Libraries (DLL) built with C 5.10's
 LLIBCDLL.LIB are limited to having 20 files open at one time. This
 limit of 20 files includes the six files automatically used by OS/2
 for stdin, stdout, and stderr (file handles 0, 1, and 2), plus OS/2
 subsystem use of file handles 3, 7, and 8, which leaves 13 additional
 files available for the process and its single-thread DLL to use. The
 files limit applies to low-level files opened with the open() function
 and to buffered stream files opened with fopen().

 Tests have shown that a single-thread DLL can open a 21st file (with
 file handle 20) without apparent error, and additional files with
 errors, but reading from or writing to these files fails with errors,
 and the 21st and additional files have zero length. The perror()
 function issues the error message "Too many open files" when
 attempting to open files after file handle 20, and perror() issues
 "Bad file number" when attempting to write to these files.

 The multithread, statically linked .EXE support library LLIBCMT.LIB,
 and the multithread, dynamically linked DLL support C run-time
 function DLL CRTLIB.DLL both allow a total of 40 file handles or
 buffered streams, though this total includes the six files used by
 OS/2, leaving applications or DLLs with 34 files available.

 The number of files for the special C libraries should be substantially
 increased in the next version of C.


 729. /Zp4 Does Not Work with Standard Stream Handles

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 15-JAN-1991    ArticleIdent: Q51865

 The Microsoft C compiler option /Zp4 (pack structures to four bytes)
 does not work correctly with the standard stream handles (stdin,
 stdout, stdaux, stderr, stdprn) when compiled under the large model.
 This happens with all optimizing compiler versions up to and including
 C 6.00a and QuickC compiler versions 2.00, 2.01, 2.50, and 2.51.

 To work around this problem, compile the STDIO.H header file with
 packing set to 1 or 2 bytes. This can be done with the #pragma pack(2)
 just before the #include <stdio.h>. After the include file is
 compiled, packing can be set back to 4 bytes with #pragma pack(4).
 Using this method allows for normal use of the standard devices.

 The following program will compile with /Zp4 /AL and run successfully:

 #pragma pack(2)
 #include <stdio.h>
 #pragma pack(4)

 #include <conio.h>

 void main(void)
 {
   fprintf(stderr,"U1001: Syntax Error\n");
   getch();
 }

 The reason STDIO.H must be compiled with packing set to 1 or 2 bytes
 is quite simple. The structure FILE is declared inside STDIO.H, but
 storage for the streams is not allocated. The stdin...stderr streams
 are assigned to an external array of stream file handles that were
 previously compiled inside the combined library with /Zp2 (the
 default). It becomes a simple case of linking two objects with
 different packing options.

 Microsoft has confirmed this to be a problem with C versions 5.10,
 6.00, and 6.00a; and QuickC versions 2.00, 2.01, 2.50, and 2.51
 (buglist2.00, buglist2.01, buglist2.50, and buglist2.51). We are
 researching this problem and will post new information here as it
 becomes available.


 730. fread() Can Fail When Return Code for fseek() Is Ignored

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist5.10
 Last Modified:  8-MAR-1990    ArticleIdent: Q57938

 If the return value from fseek() is ignored, subsequent calls to
 fread() can fail in certain circumstances. In OS/2, this results in a
 segmentation violation. In DOS, a wild pointer is created that could
 trash the system.

 The error may be difficult to reproduce because it is usually a result
 of malfunctioning or misadjusted hardware, for example, a floppy-disk
 drive that is slightly out of alignment. The error is caused by
 fseek() setting various fields in the FILE structure for the
 associated stream.

 Below is a code fragment from the C run-time library source for
 fread() along with a description of how the error occurs and a
 possible workaround.

 {File: FREAD.C}
 .
 .
 .
   /* if the stream has a buffer */
   if (bigbuf(stream))
     while (pending)

       /* if there are chars in the stream buffer */
       if (stream->_cnt)
       {
         tempcnt = (pending < (unsigned int)stream->_cnt) ?
         (unsigned int)pending : stream->_cnt;

         memcpy(buffer,stream->_ptr,tempcnt);

         stream->_ptr += tempcnt;
         buffer += tempcnt;
         pending -= tempcnt;
         stream->_cnt -= tempcnt;
       }
 .
 .
 .

 When an error occurs in fseek(), the _cnt field in the FILE stream
 structure is arbitrarily set to 8000h. In the above code, this caused
 tempcnt to be set to 8000h. Since the stream buffer size is by default
 512 bytes [BUFSIZE in stdio.h modifiable by setbuf()], the memcpy()
 causes the error in fread().

 If the existing code can't be modified to check the return value and
 recover gracefully, a temporary correction is to buy the C run-time
 library source code and modify fseek() to set _cnt to 0 (zero) if an
 error occurs. Also, whenever _cnt is set to 0, stream->_ptr should be
 set to stream->_base.


 731. Writing Optimized Dynamic Link Libraries (DDLs)

 Product Version(s): 5.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  8-MAR-1990    ArticleIdent: Q57939

 Problem:

 I have no problem building an /Od version of a DLL. However, I cannot
 build an /Ox optimized version. When I attempt to link the DLL, I get
 the following error:

    LINK : error L2029: Unresolved externals:

    __CIsin in file(s):
     FOO.OBJ(foo.c)

 I am using the alternate math library as detailed in MTDYNA.DOC.

 Response:

 Your problem is caused by the compiler optimizing with intrinsics
 (/Oi). The function you get the unresolved external on is the
 intrinsic version of sin(). LLIBCDLL and all the alternate math
 libraries do not include ANY intrinsic math functions.

 To work around this, you have two options:

 1. Compile with /Oalt. The is the easiest because it requires no code
    changes.

 2. Add the following line to your code for each function that is not
    in LLIBCDLL and you can use /Ox for maximum possible optimization:

       #pragma function({func1} {func2}...{funcN})

    This tells the compiler to use the standard version instead of the
    intrinsic version of these functions.

 For more information on the function pragma, see Page 94 in the
 "Microsoft C Optimizing Compiler: User's Guide."


 732. C and QC Now Allow Large Unsigned Long Constants in Decimal

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 19-APR-1990    ArticleIdent: Q58680

 In versions of Microsoft C earlier than 6.00, and QuickC Versions
 earlier than 2.50, unsigned long constants greater than MAX_LONG (the
 largest signed long) had to be initialized with octal or hexadecimal
 values.

 Microsoft C Version 6.00 and QuickC Version 2.50 allow unsigned long
 variables larger than MAX_LONG to be initialized using decimal
 constants. This is an ANSI-mandated change.


 733. C 6.00 and QuickC 2.50 Offer Additional Support for Bitfields

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 19-APR-1990    ArticleIdent: Q58686

 Microsoft C Version 6.00 and QuickC Version 2.50 have improved support
 for bitfields. To conform to the ANSI-draft standard, the following
 capabilities were added for bitfields:

 1. Bitfields can be signed as well as unsigned.

 2. Bitfields are now allowed in union declarations.


 734. After Increasing Available File Handles, exec Hangs Machine

 Product Version(s): 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist5.00 buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 14-JAN-1991    ArticleIdent: Q58779

 If you have increased the maximum number of file handles and buffers
 available to the system by changing the _file.c and crt0dat.asm
 start-up source files as outlined in the README.DOC file, and then
 write a program that does multiple execs, your machine may hang under
 DOS.

 There is a known incompatibility between changing the start-up source
 code for the optimizing C compilers and exec'ing multiple child
 processes.

 The following sample code demonstrates this problem:

 #define FILES_OPEN 30

 #include <stdio.h>
 #include <conio.h>
 #include <process.h>
 #include <errno.h>
 #include <string.h>

 void main ( void )
 {
     short numfiles, returnval;
     FILE *FilePointer;
     char fname[80];

     for ( numfiles = 0; numfiles < FILES_OPEN; numfiles ++ )
     {
         sprintf ( fname, "file%2d.dat", numfiles ) ;
         printf ( "Opening file #%2d :%s\n", numfiles, fname ) ;

         if ( ( FilePointer = fopen ( fname, "a+" ) ) == NULL )
         {
             printf ( "fopen failed on file #%2d", numfiles ) ;
             exit ( -2 ) ;
         }
     }

     printf ( " Press <esc> to quit, other to continue exec'ing child: \n" ) ;

     if ( ( returnval = getche() ) == 27 )
     {
         printf ( "Quitting...\n" ) ;
         exit ( 1 ) ;
     }

     if ( ( returnval = execlp ( "child.exe", "child.exe", NULL )) == -1 )
     {
         printf ( "Error exec'ing child; ERRNO: %d\n", errno ) ;
     }
 }

 If you make a copy of this program and call it child.c, and change all
 references in the child.c program from child to parent, you will have
 a loop of exec's set up. You can exec the child once, then your
 machine either hangs on the call to exec the first program again or as
 the second program is finishing execution.


 735. Microsoft GRAPHICS.LIB Does Not Support Extended VGA

 Product Version(s): 5.00 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc 2.00 s_quickasm 2.01
 Last Modified: 19-APR-1990    ArticleIdent: Q58799

 Question:

 Is there any way I can set my video mode to 640 x 480 in 256 colors or
 higher resolution?

 Response:

 Microsoft C and QuickC graphics libraries do not support any
 nonstandard BIOS graphics modes or video modes that are not available
 on IBM video subsystems. To set your video mode to a nonstandard mode,
 you can make a direct call to DOS.

 "The Manifest Constants for Screen Mode," a table associated with
 _setvideomode(), shows a table of the video modes available on IBM
 video subsystems. These are the screen modes supported by
 GRAPHICS.LIB. You can find the table on Page 539 in the "Microsoft C
 Run-Time Library Reference," for Versions 5.00 and 5.10. If you have
 QuickC Version 2.00 or QuickC with QuickAssembler Version 2.01, you
 can find the table in the Advisor's online help for _setvideomode().

 Microsoft QuickC Version 2.00 and QuickAssembler Version 2.01 support
 an additional video mode, _ORESCOLOR (640 x 400 in 1 of 16 colors).
 This mode is not supported in the Microsoft C Versions 5.00 and 5.10
 or Microsoft QuickC Versions 1.0x packages.

 To set the video mode to 640 x 480 in 256 colors, use interrupt 10h
 function 00h. This interrupt can also be used to set the video modes
 to other extended VGA modes. The following example demonstrates how to
 set the video modes using the int86() run-time function. Consult your
 video card's user's manual to determine the mode number. For example,
 mode 67 sets the Video Seven FastWrite VGA to 640 x 480 in 256 colors.
 Most VGA cards require 512K memory on the card.

 The graphics library routines supplied with Microsoft C and QuickC
 work properly only if the video mode is from 1 to 19 (plus 64 for
 QuickC Versions 2.00 and 2.01).

 Sample Code
 -----------

 #include <graph.h>
 #include <dos.h>
 #include <stdio.h>
 #include <conio.h>

 void main (void)
 {
    union REGS inregs;

    /* Set to desired video mode */

    inregs.h.ah = 0x00;
    inregs.h.al = { Desired Video Mode }

 {  inregs.h.al = 40;  for Video Seven FastWrite VGA }

    int86 (0x10, &inregs, &inregs);

    /* Get current video mode */

    inregs.h.ah = 0x0f;
    int86 (0x10, &inregs, &outregs);
    printf ("Current video mode : %d\n", outregs.h.al);
    getch();
 }


 736. How to Change the DOS Memory Allocation Strategy

 Product Version(s): 3.x 4.x 5.00 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c s_quickc s_quickasm h_masm o_msdos 1.00 1.01
 Last Modified: 23-FEB-1990    ArticleIdent: Q58919

 When DOS allocates memory for your program, it uses a firstfit
 allocation strategy by default. You can change DOS's default strategy
 to a bestfit, lastfit, or back to firstfit with a call to interrupt 21h
 function 58h.

 A firstfit strategy forces DOS to search from low addresses in memory
 to high addresses, and allocate the first available block of memory
 large enough for the requested allocation.

 A bestfit strategy forces DOS to search all addresses in memory and
 allocate the smallest block still large enough to fill the requested
 allocation.

 A lastfit strategy forces DOS to search from high addresses in memory
 to low addresses, and allocate the first available block of memory
 large enough for the requested allocation.

 The bestfit algorithm is the slowest to execute since all free memory
 is searched, but results in the least memory fragmentation during
 multiple allocations and frees. Conversely, the firstfit and lastfit
 strategies are fastest to execute, but result in a higher degree of
 memory fragmentation.

 Note that changing the allocation strategy only noticeably changes the
 way that a call to _dos_allocmem, halloc, or interrupt 21h function
 48h allocates memory from DOS. The malloc and calloc families of
 routines allocate memory from the memory pool assigned to your program
 by DOS. They are affected by DOS's internal allocation strategy only
 when the free memory pool for your program is empty and DOS is
 required to add new memory to your program's pool.

 Code Samples
 ------------

 The following two functions, written with QuickC 2.00's in-line
 assembly, respectively set and get the DOS allocation strategy:
 #define ALLOCATION_STRATEGY 0x58
 #define GET_STRATEGY        0x00
 #define SET_STRATEGY        0x01

 /********************************************************/
 /* Set_fittype - Set DOS allocation strategy            */
 /* Parameters : strategy_type, defined as:              */
 /*          FIRSTFIT = 0x00                             */
 /*          DEFAULT  = 0x00                             */
 /*          BESTFIT  = 0x01                             */
 /*          LASTFIT  = 0x02                             */
 /* Return Value :                                       */
 /*          -2 = Invalid Allocation strategy            */
 /*          -1 = Invalid Function to Int 21h Func 58h   */
 /*               Should never happen.                   */
 /*           Otherwise, returns newly set strategy      */
 /********************************************************/

 int set_fittype ( unsigned strategy_type )
 {
     int return_value;

     if (( strategy_type < 0 ) || ( strategy_type > 2))
     {
         return ( -2 ) ;
     }
     else
     {
         _asm {
                 mov     ah, ALLOCATION_STRATEGY
                 mov     al, SET_STRATEGY
                 mov     bx, strategy_type
                 int     21h

                 jnc     no_error            ; Branch if no error
                 mov     ax, -1              ; Return -1 on error

            no_error:
                 mov     return_value, ax    ; -1 if error, otherwise
                                             ; returns current strategy
             }
     }
     return ( return_value ) ;
 }

 /********************************************************/
 /* Get_fittype - Returns current allocation strategy.   */
 /* Parameters : None                                    */
 /* Return Value :                                       */
 /*           0 = Firstfit strategy                      */
 /*           1 = Bestfit strategy                       */
 /*           2 = Lastfit strategy                       */
 /********************************************************/

 int get_fittype ( void )
 {
     unsigned return_value;

     _asm {
              mov     ah, ALLOCATION_STRATEGY
              mov     al, GET_STRATEGY
              int     21h

              jnc     no_error            ; Branch if no error
              mov     ax, -1              ; Return -1 on error

          no_error:
              mov     return_value, ax    ; -1 on error, otherwise

                  }

         return ( return_value ) ;
 }

 If your compiler supports in-line assembly, you should use the above
 functions because of their speed since they do not require the C
 overhead.

 If you are using any of our compilers that do not support in-line
 assembly code, such as C 5.00, C 5.10, QuickC 1.00, and QuickC 1.01,
 the above functions can be translated as follows:

 #include <dos.h>  /* as well as the other #includes listed above */

 int set_fittype ( unsigned strategy_type )
 {
     union REGS inregs, outregs;
         int return_value;

         if (( strategy_type < 0 ) || ( strategy_type > 2))
         {
                 return ( -2 ) ;
         }
         else
         {
         inregs.h.ah = ALLOCATION_STRATEGY ;
         inregs.h.al = SET_STRATEGY ;
         inregs.x.bx = strategy_type ;
         int86 ( 0x21, &inregs, &outregs ) ;

         if ( outregs.x.cflag )
             return ( -1 ) ;
         else
             return ( outregs.x.ax ) ;
         }
 }

 int get_fittype ( void )
 {
     union REGS inregs, outregs;
     unsigned return_value;

     inregs.h.ah = ALLOCATION_STRATEGY
     inregs.h.al = GET_STRATEGY

     int86 ( 0x21, &inregs, &outregs ) ;

     if ( outregs.x.cflag )
         return ( -1 ) ;
     else
         return ( outregs.x.ax ) ;

 }


 737. C 5.10 Has a Default Threshold of 32,767 Bytes

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q59255

 Question:

 I am developing a real-time, 3-D graphics application in large model
 that uses a rather large static array of structures. I expand the size
 of my array by one element, and my program runs significantly slower.
 I restore the size of my array to its original value, and the program
 runs at normal speed. What is the cause of this problem?

 Response:

 The C version 5.10 compiler has a default data threshold value of
 32,767 bytes. The size of your static array is probably close to that
 of the default data threshold and when you add another element, it
 puts you over the limit. In that case, your data is moved to a far
 data segment, thus causing the speed hit on your program.

 To work around this problem, you could set /Gt to a value greater than
 the size of your static array, or you could explicitly declare the
 array as being near.

 For more information on the /Gt switch, refer to the "Microsoft C
 Optimizing Compiler User's Guide."


 738. Evaluating Floating-Point Values to Zero

 Product Version(s): 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 17-DEC-1990    ArticleIdent: Q59316

 Comparing small double values to 0 (zero) causes machines with
 coprocessors to hang. Since double values use 64 bits (or 8 bytes) to
 store their values and a coprocessor uses an 80-bit register to hold
 floating point values, there is a 16-bit difference that causes any
 operations on the double values to be inaccurate. In Microsoft C
 version 6.00 and Quick C version 2.50, the long double type is fully
 supported and can be used to exactly match the coprocessor form. In
 that case, the problem goes away.

 Zero is an absolute value and not always the best value to evaluate
 small float values to. The recommended way to evaluate a float value
 is to compare the float with a small value other than 0 (for example,
 0.00001).

 Sample Code
 -----------

 /* The following sample program demonstrates the problem when
  * evaluating a small double value to 0.
  */

 #include <stdio.h>

 double rz = 0.7;

 void main (void)
 {
    int i = 0;

    while (rz != 0.0) {
          rz = rz * rz;
          i++;
    }
    printf ("rz = %lf   i = %d\n", rz, i);
 }

 The recommended way is to replace the while() loop in the above code
 with the following:

       while (rz >= 0.00001) {
           rz = rz * rz;
           i++;
     }


 739. Inaccurate Representation of Large Double Values

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 15-APR-1990    ArticleIdent: Q59407

 Subtracting double values greater than or equal to 1.0E+025 may return
 inaccurate results. This is expected behavior and is due to the
 imprecise nature of floating-point math. Anytime floating-point math
 uses large numbers, there will be rounding/truncation errors and
 errors introduced due to imprecise representation of a result in
 binary format.

 Since double values are only 15-digit precise, simple subtraction of
 two large numbers can give unexpected results. The following sample
 code demonstrates this behavior.

 Double values less than 1.0E+25 may not experience the same problem.

 Sample Code
 -----------

 #include <stdio.h>

 double a = 1E+28, tmp = 9E+28;

 void main (void)
 {

    printf ("a = %le    tmp = %le\n", a, tmp);

    while (tmp >= 1E+25) {
       tmp -= a;
       printf ("a = %le    tmp = %le\n", a, tmp);
    }
 }

 The above sample code produces the following output:

 a = 1.000000e+028    tmp = 9.000000e+028
 a = 1.000000e+028    tmp = 8.000000e+028
 a = 1.000000e+028    tmp = 7.000000e+028
 a = 1.000000e+028    tmp = 6.000000e+028
 a = 1.000000e+028    tmp = 5.000000e+028
 a = 1.000000e+028    tmp = 4.000000e+028
 a = 1.000000e+028    tmp = 3.000000e+028
 a = 1.000000e+028    tmp = 2.000000e+028
 a = 1.000000e+028    tmp = 1.000000e+028
 a = 1.000000e+028    tmp = 1.319414e+013


 740. What Windows SDK Does to the C Run-Time Libraries

 Product Version(s): 5.00 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | w_winsdk
 Last Modified: 11-JUL-1990    ArticleIdent: Q59410

 The Windows SDK does the following to the C run-time libraries:

 1. It looks for all the libraries with xLIBCy.LIB, where x = memory
    model and y = e or a (emulator or alternate math).

 2. It copies xLIBCy.LIB to xLIBCyC.LIB to retain the original C
    library.

 3. It builds the windows libraries using *.bld files from the Windows
    SDK distribution disk. The result is xLIBCyW.LIB libraries.

    The following functions are taken out (-) and added (+) with the
    following libraries:

    a. C 5.00 emulator math libraries:

       -alloca   -amalloc -brk    -brkctl  -calloc   -cfpsig   -chkstk
       -chksum   -crt0    -crt0fp -em3     -emoem    -expand   -fheapchk
       -fheapwal -fmalloc -fmsize -freect  -halloc   -nheapchk -nheapwal
       -nmalloc  -nmsghdr -nmsize -realloc -stdalloc -xheapchk

       +__fpmath  +wfpsig

    b. C 5.10 emulator math libraries:

       -alloca   -amalloc -brkctl -brk     -calloc   -cfpsig   -chkstk
       -chksum   -crt0    -crt0fp -em      -emoem    -expand   -fheapchk
       -fheapwal -fmalloc -fmsize -freect  -halloc   -nheapchk -nheapwal
       -nmalloc  -nmsghdr -nmsize -realloc -stdalloc -xheapchk

       +__fpmath  +wfpsig

    c. C 5.00 or 5.10 alternate math libraries:

       -alloca -amalloc -brk      -brkctl   -calloc   -ccalle   -chkstk
       -chksum -crt0    -crt0fp   -expand   -fheapchk -fheapwal -fmalloc
       -fmsize -freect  -halloc   -nheapchk -nheapwal -nmalloc  -nmsghdr
       -nmsize -realloc -stdalloc -xheapchk

       +wfasig

 4. It copies either xLIBCyC.LIB or xLIBCyW.LIB to xLIBCy.LIB,
    depending on which libraries you want to be used as the primary.
    The resulting libraries are xLIBCy.LIB (primary to be used),
    xLIBCyW.LIB (library for Windows SDK), and xLIBCyC.LIB (library for
    C).

 If compiling with Microsoft C version 6.00 and using the Windows 2.1x
 SDK, use the /Gh switch and link with the libraries from C version
 5.10. In addition, use all the tools that shipped with the Windows
 2.1x SDK, including LINK4.EXE and RC.EXE.


 741. fstat() Gets Different Results Under FAT and HPFS

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 11-JUL-1990    ArticleIdent: Q59437

 The documentation for fstat() in the "Microsoft C Run-Time Library
 Reference," Page 303, states that the same value (time of last
 modification of file) is placed in the fields st_atime, st_ctime, and
 st_mtime.

 This is correct under DOS. However, the OS/2 High Performance File
 System (HPFS) stores different values in each of those fields. The
 documentation is incomplete in this regard.

 The fstat() call checks to see if the operating system returns values
 for various times. If not, fstat() copies the same value into all
 three fields. Otherwise, fstat() returns the values supplied by the
 operating system.

 OS/2 Version 1.20 HPFS maintains all three of these values. A call to
 fstat() then puts the three values in the fields. The FAT file system
 does NOT maintain these three values so fstat() returns the same file
 time in all three variables.


 742. C4071 Can Be Caused by Missing "void" in Function Prototype

 Product Version(s): 5.00 5.10 6.00 | 5.00 5.10 6.00
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 18-APR-1990    ArticleIdent: Q59439

 Function prototypes must have parameter lists. If no arguments are to
 be passed to a function, the parameter list must contain the keyword
 "void". At warning level three (/W3), leaving the "void" out of such a
 prototype parameter list leads to the following warning message in C
 Versions 5.00 and 6.00 and QuickC Versions 2.00, 2.01, 2.50, and 2.51:

    C4071 'name' : no function prototype given

 In C Version 5.10, the following additional warning message occurs:

    C4103 Function definition used as prototype

 The following code demonstrates the problem:

 /* myfunc is not prototyped correctly */

 #include <stdio.h>
 void myfunc();          /* missing void in parameter list */
 void main(void)
 {
   myfunc();             /* myfunc still not prototyped */
 }

 void myfunc()    /* function definition doesn't need void */
 {
   printf("Hello\n");
 }


 743. Errors When Space Exists Between Macro Name and Parameters

 Product Version(s): 4.x 5.00 5.10 | 5.10
 Operating System:   MS-DOS        | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 17-DEC-1990    ArticleIdent: Q59490

 If you put a space between a macro name and the left parenthesis that
 begins the parameter list for a macro, you will receive multiple
 compiler errors because the preprocessor is designed to accept any
 code after the first space after the macro name as the code definition
 for the macro.

 Sample Code
 -----------

 #define incr (x) x+1      /* Change to incr(x) to correct. */
 #include <stdio.h>

 void main ( void )
 {
     int f1, f2;

     f2 = 0 ;

     f1 = incr(f2);

     printf ( "%d %d ", f1, f2 ) ;
 }

 Compiling this program under C Versions 4.x, 5.00, and 5.10, or QuickC
 Version 1.00, 1.01, 2.00, or 2.01, returns the following error
 messages:

    macro.c
    macro.c(10) : error C2065: 'x' : undefined
    macro.c(10) : error C2146: syntax error : missing ';' before
                  identifier 'x'
    macro.c(10) : error C2064: term does not evaluate to a
                  function

 Removing the space between the macro name and the left parenthesis
 eliminates the errors.

 The following error and warning messages are returned by C Version
 6.00 under warning level 2 and above:

    macro.c
    macro.c(10) : error C2065: 'x' : undefined
    macro.c(10) : error C2146: syntax error : missing ';'
                  before identifier 'x'
    macro.c(10) : error C2064: term does not evaluate to a
                  function
    macro.c(10) : warning C4071: 'function through ptr' : no
                  function prototype given


 744. How to Determine the Operating System Mode and Version

 Product Version(s): 4.x 5.00 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 18-APR-1990    ArticleIdent: Q59541

 There are four variables defined by the start-up source code for the
 Microsoft C compilers that can be used to determine the version of the
 operating system the program is running on as well as whether the
 program is running in DOS or OS/2 mode. Those variables are _osmajor,
 _osminor, _osversion, and _osmode.

 The four variables are prototyped in the DOS.H and STDLIB.H header
 files, declared in the CRT0DAT.ASM start-up source file, and defined
 in both CRT0DAT.ASM and STDARGV.ASM files. They are defined as
 follows:

    Variable     Definition
    --------     ----------

    _osmajor     Holds the major operating system version number.

    _osminor     Holds the minor operating system version number.

    _osversion   Holds the complete version number, as follows:
                 the high-order byte contains the minor version
                 number and the low-order byte holds the major
                 version number.

    _osmode      Defined as DOS_MODE or OS2_MODE for DOS or OS/2
                 operating systems. The variable is set to
                 DOS_MODE if you are running OS/2, but in the DOS
                 compatibility box.

 The _osmajor is set to 10 for Versions 1.00, 1.10, and 1.20 of OS/2,
 and 20 for Version 2.00.

 Note that _osmode is not defined for DOS-only versions of the compiler
 (for example, QuickC, C 5.00, etc.).

 Sample Program
 --------------

 The following program prints the version and mode of the operating
 system:

 #include <stdlib.h>
 #include <dos.h>
 #include <stdio.h>

 void main ( void )
 {

    printf ( "_osmajor = %d\n", (int)_osmajor ) ;
    printf ( "_osminor = %d\n", (int)_osminor ) ;
    printf ( "_osversion=%u\n", _osversion ) ;

    if (_osmode == DOS_MODE)
    {
       if ( (int)_osmajor < 10 ) /* We're under DOS */
          printf ("\nDOS version %d.%d\n",
                  (int) _osmajor, (int) _osminor );

       else  /* We're running OS/2 DOS compatibility box */
          printf ("\nOS/2 version %d.%d running"
                  " DOS compatibility \n", ( (int) _osmajor ) / 10,
                  (int) _osminor  ) ;
    }
    else
       printf ("\nOS/2 version %d.%d\n",
                 ((int)_osmajor)/10, (int)_osminor );
 }


 745. Multithreaded Run-Time Libraries Require 40 File Handles

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q59893

 If you are creating an application that uses the multithreaded version
 of the run-time library (LLIBCMT.LIB or CRTLIB.DLL), it is not
 possible to set the file-handle count lower than 40. This is by design
 and may change in a future release of the run-time library.

 The DosSetMaxFH() function allows an application to dynamically set
 the number of file handles a program requires. It takes one parameter
 (the number of handles) and returns success, or one of the following
 two errors:

    ERROR_INVALID_PARAMETER
    ERROR_NOT_ENOUGH_MEMORY

 However, there is a limitation in the function. It will not allow the
 program to reduce the number of file handles, only increase them.

 In the case of an application that is linked with CRTLIB.DLL or
 LLIBCMT.LIB, the library has already set the file-handle count to 40.
 In this case, a call to DosSetMaxFH() with a number less than 40
 returns an ERROR_INVALID_PARAMETER value.


 746. Why Can't a Stand-Alone DLL Use the Emulator Math Library?

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q59895

 Question:

 In MTDYNA.DOC, it states that a stand-alone DLL should use LLIBCDLL,
 and therefore, the alternate math library. In the C Version 6.00
 "Advanced Programming Techniques" manual, it states that the alternate
 math library must be used because of the following:

    For a DLL to use the 80x87 coprocessor of the emulation point
    library, the DLL and all of its client programs must agree on which
    process is going to handle floating-point exceptions and on which
    process is going to handle emulation if the machine does not have a
    coprocessor.

 I don't understand why exception handling and/or task switching causes
 more problems for using an 80x87 in a DLL context than in normal
 applications. The DLL can always find the PID of the client and could
 signal it, register a DosExitList function, or do several other things
 in the case of an exception. Given that the DLL C run-time databases
 could be per-instance data segments, why is there a problem?

 Response:

 The problem with handling 80x87 floating-point exceptions and using
 DLLs is that when we call DosSetVec() to set a handler for 80x87
 exceptions, the handler is set for the entire process. Whoever calls
 DosSetVec() last will get control of all 80x87 exceptions.

 Suppose we are lucky and the DLL calls DosSetVec() last and an
 exception occurs. The DLL has no way of knowing whether the exception
 occurred in the DLL's code or the EXE's code (or perhaps some other
 DLL). Thus, the DLL has no way of knowing what to do. Perhaps the
 exception should be ignored or maybe the process should be terminated.

 Calling DosExitList() is not a solution because the DLL has to decide
 what to do right now. Also, finding out the PID and then signaling the
 process is not very useful because this means that the EXE and all of
 the DLLs in the process must set up special signal handlers to handle
 exceptions. In other words, the EXE and the DLL must all use a special
 library to cooperate when a floating point exception occurs, and that
 is what CDLLOBJS.LIB is for.

 LLIBCDLL.LIB is for writing stand-alone DLLs, that is, DLLs that can
 be called from any EXE. Because LLIBCDLL.LIB uses alternate math, it
 is completely self-contained and doesn't need any special code in the
 EXE.


 747. Clarification of MTDYNA.DOC: Cooperation on Global Data

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q59933

 Question:

 I have read the MTDYNA.DOC file regarding the use of the multithreaded
 libraries with a multithreaded application. However, I am unclear as
 to the exact meaning of the following passage:

    C run-time global data (such as the standard I/O package FILE,
    pointers of buffer I/O, and memory allocated with malloc functions)
    is shared. This means that the program and the associated
    dynamic-link libraries must cooperate on the usage of this data.

 What cooperation is required between the application and the DLLs? Does
 this mean that I should put all the functions that use this global
 data in a single thread and call the functions serially?

 For example, suppose one thread in the DLL calls printf(), and while
 that is executing, the application calls fprintf(). Will the two
 functions use the same global data area to do their respective data
 manipulations? Is it necessary use semaphores around all the functions
 that use each malloc'ed memory pointer or all functions that access
 FILE pointers?

 Response:

 There are really two parts to this answer:

 1. The run-time library takes care of the synchronization of various
    threads that use a particular function. So, in the case of internal
    data a run-time function may need, the data sharing is controlled
    by the library. There is no need for the user of the library to
    worry about that.

 2. The second part has to deal with the global data that the
    application and the DLL share. The passage in MTDYNA.DOC is
    attempting to say that the DLL and the application have to
    cooperate on the creation, using, and termination of the global
    data.

 Take FILE pointers, for instance. If the DLL issues a fcloseall(), all
 file handles that belong to the ENTIRE process will be closed. If the
 application or other DLLs are still using a particular file pointer,
 that has to be coordinated before the fclosealll() is issued.

 Along the same lines, if multiple threads write to the same file
 handle at the same time, all the writes will go out in the order they
 are received by the run time. This is due to the internal
 synchronization of the run time mentioned above and does not require
 any user intervention. However, all the data is written one after
 another in the same file. This may or may not be the desired result.

 The same scenario holds true for the other global run-time data.


 748. Changing Directory Name with rename() May Not Work As Expected

 Product Version(s): 5.00 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 19-APR-1990    ArticleIdent: Q60028

 If you use the rename() function to change a subdirectory name, you
 will discover that some versions of DOS will not allow you to change
 the directory name on another drive if the directory name you want to
 change is the current working directory for that drive. In addition,
 other versions of DOS may return a success value, but you may find
 that the directory name apparently hasn't changed.

 With DOS Versions 3.x without SHARE.EXE, the sample program shown
 below produces the following results:

    C:\>cd olddir
    C:\OLDDIR>d:
    D:>test
    Rename is successful  <--- Output from test program
    D:>c:
    C:\OLDDIR>      <--- The old directory is not renamed

 With DOS Versions 4.x, DOS Versions 3.x with SHARE.EXE loaded, or the
 DOS box in OS/2, the same program returns the following results:

    C:\>cd olddir
    C:\OLDDIR>d:
    D:>test
    Rename fails with errno = 13  <--- Output from test program
    D:>c:
    C:\OLDDIR>            <--- The old directory is not renamed

 Note: The errno code indicates an access violation.

 The following is the sample program:

 #include <io.h>
 #include <stdio.h>

 char szOldName[] = "c:\\olddir";
 char szNewName[] = "c:\\newdir";

 extern int errno;

 void main (void)
 {
    if (0 != rename(szOldName, szNewName)
       printf("Rename fails with errno = %d\n", errno);
    else
       printf("Rename is successful\n");
 }

 There is nothing wrong with the rename() function. It merely maps out
 to the Interrupt 21h, Function 56h (Rename File) call. The problem is
 that the operating system keeps a list in memory of the current
 working directories (CWD) for each drive in its drive table.

 In the case of the example under DOS 3.x, the directory name is
 changed. However, because DOS does not recognize the change, it does
 not update the in-memory table to the new CWD. Therefore, when you
 return from the program, you see the invalid prompt with the old
 directory name. If you type "CD\NEWDIR", the directory name will be
 updated in memory also.

 In the second example, DOS 4.x, DOS 3.x with SHARE.EXE, and the OS/2
 DOS box can't assume that the directory is not in use by another
 process and hence the access violation error.

 The workaround in both cases is to issue a chdir() on the drive where
 the target directory resides to set that drive to the root directory
 [for example, chdir("c:\\");]. In this case, there is no chance of
 getting an access violation (at least not for the above reasons).

 A variant of this workaround is to change to the drive in question and
 issue a getcwd() call to see if changing the directory is even
 necessary.


 749. Initializing Bitfields as Integers in C

 Product Version(s): 4.x 5.00 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 17-JUL-1990    ArticleIdent: Q60252

 Initializing the values of an entire bitfield structure as an integer
 can be done in several ways:

 1. Declare the bitfield structure as part of a union with an integer.
    (This is the preferred method).

 2. Use an integer pointer by setting the pointer to the address of the
    structure and then changing what the pointer points to.

 3. To get a copy of the bitfield into an integer variable, you must
    enforce the bitfield type constraints.

 For examples of these three methods, see below.

 In Microsoft C, bitfields are stored in word-sized blocks with the
 least significant bit representing the first bit of the bitfield. For
 example, the bitfields in bitstruct, defined below in the example,
 are stored as follows:

            <  p4   > <  p3   > < p2> <p1>
         |?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|?|

 Assigning the integer 0x4c to this structure results in the following
 bit pattern:

         |0|0|0|0|0|0|0|0|0|1|0|0|1|1|0|0|

 The bitfields are given the following respective values:

    p1=0 p2=3 p3=2 p4=0

 If the number of bits needed for a bitfield structure exceeds 16,
 words will be added as needed to provide room for the structure with
 no single bitfield crossing a word boundary.

 Note: There is no "standard" for storing bitfields; therefore, any
 program that depends on them being stored in this manner, low to high,
 will not be portable.

 Sample Code
 -----------

 struct strtype
    {
    unsigned p1:2;
    unsigned p2:3;
    unsigned p3:5;
    unsigned p4:5;
    } bitstruct;

 union untype
    {
    struct strtype un_bitstruct;
    unsigned bit_integer;
    } bitunion;

 unsigned *intptr;
 unsigned intgr;

 void main(void)
 {
    /*  Using the bitfield structure only */

       /* Set the pointer to address of bitfield */
    intptr=(unsigned *)&bitstruct;

       /* Change the bitfield */
    *intptr=0x4c;

       /* Get the new value */
    intgr=*(unsigned *)&bitstruct;

    /* Using an union makes this much easier (syntactically) */

       /* Set the pointer */
    intptr=&bitunion.bit_integer;

       /* Change the bitfield */
    bitunion.bit_integer=0x4c;

       /* Get the new value */
    intgr=bitunion.bit_integer;
 }

 Note: If you are using C 6.00 or later or QC 2.50 or later, you could
 use the anonymous union construct that these compilers support. In
 that case, the code would change to:

 struct strtype
    {
    unsigned p1:2;
    unsigned p2:3;
    unsigned p3:5;
    unsigned p4:5;
    } bitstruct;

 union untype
    {
    struct strtype un_bitstruct;
    unsigned bit_integer;
    };                      // Look ma!  No name..

 unsigned *intptr;
 unsigned intgr;

 void main(void)
 {
    /*  Using the bitfield structure only */

       /* Set the pointer to address of bitfield */
    intptr=(unsigned *)&bitstruct;

       /* Change the bitfield */
    *intptr=0x4c;

       /* Get the new value */
    intgr=*(unsigned *)&bitstruct;

    /* Using an union makes this much easier (syntactically) */

       /* Set the pointer */
    intptr=&bit_integer;    // See here...

       /* Change the bitfield */
    bit_integer=0x4c;       // And here...

       /* Get the new value */
    intgr=bit_integer;      // And here...  (Much easier, huh?)
 }


 750. C4061 Long/Short Mismatch in Argument

 Product Version(s): 5.00 5.01 6.00 | 5.00 5.01 6.00
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 18-APR-1990    ArticleIdent: Q60253

 In Microsoft C Versions earlier than Version 6.00, the C4061 warning
 was generated only if the actual and formal arguments to a function
 were a mix of long and int types. Beginning with Microsoft C Version
 6.00, this warning message will be generated if the types are a mix of
 int and char. This is not a fatal error and is generated only to alert
 the programmer that there MAY be a problem.

 The error message is generated for the following sample code at
 warning level 1. If the /Qc option is used (Quick Compile), the
 warning is not generated at any warning level. Also, in QuickC
 Versions 2.00, 2.01, 2.50, and 2.51, a warning is never generated for
 this code.

 Sample Code
 -----------

 #include <stdio.h>

 void foo (char); /* At prototype level argument type is CHAR */
 void main(void);

 void main (void)
 {
    foo (200);   /*  Now passing an INTEGER to a CHAR  */
 }

 void foo (char c) /* Argument correctly declared as CHAR */
 {}


 751. C 6.00 sizeof() Function Returns unsigned Instead of int

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 19-APR-1990    ArticleIdent: Q60332

 To comply with new ANSI specifications, the sizeof() operator in
 Microsoft C Version 6.00 and QuickC Version 2.50 now returns an
 unsigned integer. In C Version 5.10 and QuickC Version 2.00, this
 function returns a signed int.

 The unsigned return value can cause problems in cases using
 -sizeof(type). In the following example, trying to position a file one
 record from the end which worked properly under C Version 5.10, does
 not work properly under C Version 6.00:

    fseek(file,(long)(-sizeof(record)),SEEK_END);

 This now gives a location far beyond the file's end because the
 generated value is no longer sign extended. Since the unary minus (-)
 doesn't change the "signedness" of a variable and the sizeof()
 operator is now a unsigned int, the compiler performs a zero extension
 to convert from an unsigned int to a long. This change in
 representation of the sizeof() operator was done to maintain
 compatibility with the ANSI standard.

 In other words, if "record" above is of type char, instead of
 returning a long value of -1, the following returns the positive value
 of 0x0000ffff or 32767:

    (long)(-sizeof(record))

 One workaround is to cast the sizeof() result to a signed int
 before casting it to a long. For example:

    (long)-(int)sizeof(record)


 752. _bios_serialcom() May Not Work at 9600 and 4800

 Product Version(s): 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 19-APR-1990    ArticleIdent: Q60333

 The function _bios_serialcom() may not work correctly at 4800 or 9600
 baud. This problem is due to the function calling BIOS interrupt 14h.

 Sample Code
 -----------

 /* Transmitting Machine */
 #include <stdio.h>
 #include <conio.h>
 #include <bios.h>

 void main(void)
 {
    unsigned config;

    config = (_COM_CHR8|_COM_STOP1|_COM_NOPARITY|_COM_9600);
    _bios_serialcom(_COM_INIT,0,config);

    while(1)
       _bios_serialcom(_COM_SEND,0,(unsigned)getch());
 }

 /* Receiving Machine */
 #include <stdio.h>
 #include <conio.h>
 #include <bios.h>

 void main(void)
 {
    unsigned config;
    unsigned data;
    config = (_COM_CHR8|_COM_STOP1|_COM_NOPARITY|_COM_9600);
    _bios_serialcom(_COM_INIT,0,config);

    while(1)
       {
       data = 0x0000;
       _bios_serialcom(_COM_RECEIVE,0,data);
       if (data != 0x0000)
          putch((int)data);
       }
 }

 If the sample programs are run on two separate machines connected by a
 null modem (serial cable), 9600 baud communication is not possible. At
 4800 baud, the data is seriously corrupted on the receiving end. The
 results are the same when the roles of the machines in question are
 reversed. However, the function performs well at 300 to 2400 baud.

 Since _bios_serialcom() uses interrupt 14h to do the work, this is a
 limitation of the BIOS and not the function. If you want to establish
 reliable serial communications at a higher baud rate, an interrupt
 service routine (ISR) should be written to handle the I/O. More
 information on this can be found in Article 6, Pages 167-246 of the
 "MS-DOS Encyclopedia."


 753. Operator Missing in C 6.00 A.P.T. Manual's /Oz Example

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-DEC-1990    ArticleIdent: Q60391

 The example for the command-line compiler switch /Oz on Page 18 of
 "Microsoft C Advanced Programming Techniques" is missing a "<" sign in
 a FOR statement. The incorrect line of code in the manual appears as
 follows:

    for( i = 0; i  100; ++i )

 The correct code should read as follows:

    for( i = 0; i <100; ++i )


 754. Apparent Failure of _memavl() Caused by printf() Allocation

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER|
 Last Modified: 15-APR-1990    ArticleIdent: Q60488

 The printf() statement makes a call to malloc() the first time it is
 called within a program. Due to this allocation, _memavl() may seem to
 return an incorrect value in some cases.

 If a call to _memavl() is made within or before the first printf()
 statement in a program, subsequent malloc() calls cannot allocate as
 much memory as _memavl() suggests.

 The workaround is to make the call to printf() before your call to
 _memavl(), or make another call to _memavl() after printf() to
 determine your true maximum allocation.

 The following code demonstrates the problem:

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

 size_t mavl;
 char *ptr;

 void main(void)
 {
 // printf("If included, this line solves the problem.\n");

    printf("memory available=%u \n",mavl=_memavl());

    if ((ptr=(char *)malloc(mavl))==NULL)
      printf("Not as much memory available as we thought!");
 }


 755. cl May Run Out of Memory When Compiling Many Files At Once

 Product Version(s): 6.00 6.00a  | 6.00 6.00a
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 31-JAN-1991    ArticleIdent: Q60491

 Compiling large numbers of files in one compilation pass can cause an
 "Out Of Memory" error. CL.EXE is making memory allocations for each
 file it compiles that isn't being freed until CL.EXE terminates.

 This problem is most frequently encountered when passing wildcards to
 the cl command. For example:

    cl -c *.c

 The best workaround is to use a MAKE file to govern the compilation of
 large programs. Because NMAKE spawns CL.EXE separately for each source
 module, the memory is returned to the operating system between each
 source compilation.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 756. FORTRAN 5.00 and C 6.00 Mixed-Language Considerations

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_fortran
 Last Modified: 17-DEC-1990    ArticleIdent: Q60496

 When doing mixed-language programming with Microsoft FORTRAN Version
 5.00 and C Version 6.00, it is necessary to use the FORTRAN
 C-compatible libraries.

 Also, when linking, the C 6.00 libraries should be placed first on the
 link line followed by the FORTRAN library.

 With C 5.10 and FORTRAN 5.00, it is possible to do mixed-language
 programming using the full libraries in both C and FORTRAN because the
 common routines between the two products are basically the same.
 However, this is not the case with C 6.00 and FORTRAN 5.00. The common
 routines often differ between the products, and the more recent
 versions must be used.

 In the FORTRAN 5.00 Setup program, you are given the option to build
 C-compatible libraries. Because these libraries do not contain the
 common routines, including much of the start-up code mentioned above,
 there is no problem linking them with the C 6.00 libraries. However,
 it is worth noting that these libraries can no longer be considered
 stand-alone FORTRAN libraries. They are only useful in conjunction
 with the C libraries. Finally, the C 6.00 libraries should be placed
 before the FORTRAN libraries on the linker command line.

 This information is also documented in "Advanced Programming
 Techniques," Chapter 12.3.2, Page 285.


 757. C 6.00 SAMPLES.DOC: Note on Graphics Libraries

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | README README.DOC
 Last Modified: 19-APR-1990    ArticleIdent: Q60650

 The following information is taken from the C Version 6.00 SAMPLES.DOC
 file.

 Note on Graphics Libraries
 --------------------------

 GRDEMO and CHRTDEMO require GRAPHICS.LIB. CHRTDEMO also requires
 PGCHART.LIB. SORTDEMO requires GRAPHICS.LIB for DOS or GRTEXTP.LIB for
 OS/2. If you did not request these libraries in your combined library
 files during setup, you will get "unresolved external" linker errors
 when you try to compile the programs.

 If you are using CL, specify the library names on the command line.
 For example, use this command line to compile GRDEMO:

    CL GRDEMO.C MENU.C TURTLE.C GRAPHICS.LIB

 If you are using PWB, you can use the supplied program list (.MAK)
 files. These automatically add the appropriate libraries.


 758. C 6.00 SAMPLES.DOC: Note on Naming Conventions

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | README README.DOC
 Last Modified: 25-APR-1990    ArticleIdent: Q60651

 The following information is taken from the C Version 6.00 SAMPLES.DOC
 file.

 Note on Naming Conventions
 --------------------------

 The example programs use a subset of the naming conventions used in
 OS/2 and Windows include files. In this convention, the first
 character of an identifier is a lowercase letter called a prefix.
 Common prefixes include p (pointer), a (array), i (index), and c
 (count). After the prefix, there may be an additional lowercase tag,
 usually indicating type. Common tags include ch (char), f (flag), sz
 (zero-terminated string) l (long), and x or y (x or y coordinate).
 Following this there may be one or more qualifiers, each beginning
 with an uppercase letter. For example, an identifier called
 achFileName is an array (a) of characters (ch) containing a filename
 (FileName).


 759. Hardware Failure Possible Cause of C1001

 Product Version(s): 5.10 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-APR-1990    ArticleIdent: Q60708

 In some cases, it is possible for hardware failures to generate an
 internal compiler error (C1001). Specifically, either a hard drive or
 drive controller may be the problem.

 The following are some of the signs of a hardware failure causing an
 internal compiler error:

 1. A simple program giving a C1001 at compile time, for example:

       #include <stdio.h>

       void main (void)
       {
           printf ("This is a test...\n") ;
       }

 2. Receiving a C1001 on a line of code that is a simple statement,
    with no optimization on. For example:

       foo = 3 ;   /*  This should NOT cause C1001 */

 3. A program compiling one time, then failing with a C1001 error on
    all subsequent compilations.

 4. A program consistently giving a C1001 error on one specific
    computer, while compiling correctly on another computer.

 5. The problem goes away when a RAM disk is used for the storage of
    temporary files, as pointed to by the TMP environment variable. This
    would not be the case if you had some bad RAM.

 If any of the above is happening to you and you suspect hardware
 problems, take the code to another machine and try it there. If the
 problem does not appear on the second machine, the hardware of the
 original machine may be faulty and need repair.


 760. C4127 Is Generated When Subexpression Evaluates to a Constant

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 21-APR-1990    ArticleIdent: Q60734

 Microsoft C Version 6.00 has a new compiler warning "C4127:
 conditional expression is constant." This warning is designed to
 inform you that the controlling expression of an if statement or while
 loop evaluates to a constant, so the body of the loop is ALWAYS
 executed or NEVER executed.

 The warning may appear in certain expressions that don't seem to be a
 constant, but this is because the compiler will generate this warning
 if ANY subexpression in a larger conditional expression evaluates to a
 constant. The warning is strictly informational and does not
 necessarily indicate any problems in the code.

 In the sample code below, warning C4127 is generated if the code is
 compiled at warning level three or four (/W3 or /W4). Looking at the
 following entire expression

      ( hours >= 0 && hours <= 24 )

 it definitely appears that it is NOT a constant because hours could be
 EITHER in the range 0 (zero) to 24, or out of that range. This
 expression generates warning C4127, however, because the left
 subexpression

       hours >= 0

 ALWAYS evaluates to true because hours is unsigned and an unsigned int
 is ALWAYS greater than or equal to zero. The compiler generates the
 warning to inform you of this situation.

 Note that this warning is generated only by the full optimizing
 compiler because the quick compiler (/qc) does not check for this
 situation.

 Sample Code:

 #include <stdio.h>

 void main(void)
 {
     unsigned hours;

     scanf ( "%ud", &hours );

     if ( hours >= 0 && hours <= 24 )
         printf("Hours OK\n");
     else
         printf("Hours BAD\n");
 }

 Making a simple change, such as replacing the ">=" with a ">",
 eliminates the warning because the left expression could now evaluate
 to either true or false (for example, false if hours = 0; true
 otherwise).


 761. Quick Compiler Incorrectly Zero-Extends Ones Complement

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 s_quickc
 Last Modified: 19-APR-1990    ArticleIdent: Q60747

 The C Version 6.00 quick compiler incorrectly zero-extends ones
 complement operations that result in negative integers, rather than
 sign-extending them. The QuickC (QC) 2.50 compiler works correctly.

 When compiled with the quick compiler, the following sample code
 produces a value of 64512 for l. When compiled with the full
 optimizing compiler, the correct result of -1024 is produced for l.
 This is a problem with QCL, not CL.

 In ANSI C, the constant 1023 is represented as an integer. The
 ones complement of 1023 (-1024) should remain an integer and when
 promoted to a long, this integer should then be sign-extended
 preserving the value. QCL correctly stores 1023 as an integer;
 however, it doesn't sign-extend the ones complement as it should.

 One solution is to typecast the ones complement to an int before
 assigning it to a long [for example, l=(int)~1023].

 Microsoft has confirmed this to be a problem with Version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.

 Sample Code
 -----------

 #include<stdio.h>

 void main(void)
 {
   long l;

   l=~1023;  /* Ones complement not properly extended */

   printf("%ld\n",l);
 }


 762. Storage Types of Integer Constants Changed in C Version 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 19-APR-1990    ArticleIdent: Q60751

 To maintain ANSI compliance, Microsoft C Version 6.00 stores numeric
 constants in a slightly different manner than C Version 5.10.

 The following table summarizes the way constants are now represented
 by the Microsoft C Version 6.00 Compiler:

   Storage Type Is the Smallest of the Following List That
            Can Represent the Constant's Value
 ----------------------------------------------------------

   decimal constant                int
     w/o suffix                    long
     (ex. 123 )                unsigned long*

 ----------------------------------------------------------

   hex or octal constant           int
     w/o suffix                 unsigned
    (ex. 0x122 )                   long
                               unsigned long

 ----------------------------------------------------------

   all constants **              unsigned
   u or U suffix               unsigned long
    (ex. 133u )

 ----------------------------------------------------------

   all constants **                long
   l or L suffix               unsigned long
    (ex. 332l )

 ----------------------------------------------------------

     all constants **
 u or U and l or L suffix      unsigned long
    (ex. 0x111ul )

 ----------------------------------------------------------

 * - Unsigned long was not supported for Standard Decimal Constant
     Representation in Microsoft C Version 5.10 or QuickC 2.00.

 ** - The maximum value for any decimal constant in Microsoft C
      5.10/QuickC 2.00 was 2,147,483,647 regardless of type.

 All constants in C are stored as positive values. A constant preceded
 by a unary minus is considered an expression rather than a negative
 constant. If the type of the constant as defined above is unsigned,
 then the result of the unary minus expression is also considered
 unsigned.

 The exact rules for integer constant storage as taken from the ANSI
 draft dated Dec. 7, 1988, Section 3.1.3.2, are as follows:

    The type of an integer constant is the first of the corresponding
    list in which its value is represented. Unsuffixed decimal: int,
    long int, unsigned long int; unsuffixed octal or hexadecimal: int,
    unsigned int, long int, unsigned long int; suffixed by the letter u
    or U:  unsigned int, unsigned long int; suffixed by the letter l or
    L: long int, unsigned long int; suffixed by both the letters u or U
    and l or L: unsigned long int.


 763. DOSCALLS.LIB Is Not Shipped with C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q60786

 After installing Microsoft C Version 6.00, you may try and compile
 your program and link with DOSCALLS.LIB. This process worked correctly
 with C Version 5.10, but does not work with C Version 6.00. You will
 receive the following error:

    L4051: doscalls.lib : cannot find library.

 It may appear as if something is wrong with your environment. In fact,
 there is no DOSCALLS.LIB supplied with C 6.00. Use OS2.LIB instead.
 OS2.LIB contains all the functionality of DOSCALLS.LIB in addition to
 having Presentation Manager (PM) support.


 764. How to Explicitly Reference Command-Line Tail

 Product Version(s): 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 19-APR-1990    ArticleIdent: Q60869

 The following code allows you to explicitly reference the command-line
 tail. The entire command line with spaces intact is referenced at the
 Disk Transfer Area (DTA) address and printed out as one string.

 Sample Code
 -----------

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

 main()
 {
    int tail_length;
    char cmd_tail(128);

    char far *p;             /* far pointer */
    int i;

    struct SREGS Seg;
    union REGS Reg;

    Reg.h.ah = 0x2F;         /* DOS call:  Get DTA Address   */
    segread(&Seg);
    intdosx(&Reg, &Reg, &Seg);

    FP_SEG(p) = Seg.es;      /* make p point to the DTA */
    FP_OFF(p) = Reg.x.bx;

    tail_length = *p;        /* First byte is length of tailstring */

    printf("tail_length = %d\n", tail_length);

    p++;                     /* Move to first byte */

    for(i = 0; i<tail_length; i++)
       cmd_tail[i] = p[i];

    cmd_tail[tail_length] = '\0';  /* Add NULL to make a string */
    printf("cmd_tail = <%s>\n", cmd_tail);

    return(0);
 }

 Note: The command line is limited to 128 bytes.

    cmdline *.c  abc  def  lab7.pas

 Output using the above command line is as follows:

 tail_length = 24
 cmd_tail = < *.c  abc  def  lab7.pas>

 Note: A more portable way of getting this information is to use the
 argv mechanism built into C. This may be easier because the command
 line would be already partially parsed by the setargv() function.


 765. _ERESNOCOLOR Should Be Typed M/G, Not M/T

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc docerr
 Last Modified:  1-MAY-1990    ArticleIdent: Q60910

 On Page 680 of the "Microsoft C Run-Time Library Reference" (published
 by Microsoft Press) for C version 6.00 and on Page 539 of the
 "Microsoft C 5.1 Optimizing Compiler Run-Time Library Reference,"
 _ERESNOCOLOR is incorrectly listed as type M/T, indicating that this
 mode only supports monochrome text. _ERESNOCOLOR should be typed M/G,
 indicating monochrome graphics. The following code demonstrates that
 graphics can be generated when the video mode is set to _ERESNOCOLOR:

 Code Example
 ------------

  #include <graph.h>
  #include <conio.h>

  void main(void)
  {
   _setvideomode(_ERESNOCOLOR);
   _ellipse(_GFILLINTERIOR, 80, 50, 240, 150);
   getch();
   _setvideomode(_DEFAULTMODE);
  }


 766. -Za and OS2.H Are Incompatible

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q60975

 The -Za compile option, which enforces the ANSI standard, CANNOT be
 used when the include files OS2.H or OS2DEF.H are included.

 This option cannot be used because the Microsoft extensions (near,
 far, cdecl, etc.) do not have the leading underscore (_) in front of
 them indicating that they are non-ANSI extensions.

 To successfully compile with the -Za compiler option, place an
 underscore (_) in front of these extensions.

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


 767. C1001: Internal Compiler Error: regMD.c: 1.100 Line 1017

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-MAY-1990    ArticleIdent: Q61055

 The following sample code generates an internal compiler error when
 compiled with /Ole for optimizations in all memory models:

    prog.c(15) : fatal error C1001: Internal Compiler Error
                     (Compiler file '@(#)regMD.c:1.100', line 1017
                     Contact Microsoft Product Support Services

 Sample Code
 -----------

  1:  void foo (unsigned);
  2:
  3:  /* Either of the following two pragmas are valid workarounds. */
  4:  /* #pragma optimize ("l", off) */
  5:  /* #pragma optimize ("e", off) */
  6:
  7:  void foo (unsigned start)
  8:      {   /* Works if "start" is an "int" instead of "unsigned" */
  9:      int i;
 10:      int end;
 11:
 12:      end = start + 8;       /* Works if "end = start" or if
 13:                                "end" is assigned to a constant */
 14:
 15:       for (i = start; i < end; ++i)
 16:           end++;             /* Works if empty statement or i++ */
 17:      }
 18:
 19:  /* #pragma optimize ("l", on) */
 20:  /* #pragma optimize ("e", on) */

 To work around this problem, disable either the global register
 allocation /Oe or the loop optimization /Ol. There is a conflict with
 both optimizations being enabled at the same time with this particular
 code.

 The following are two additional workarounds:

 1. Use the optimize() pragma to override the compiler's optimization
    switch (as shown in the above program).

    You can disable one of the optimizations before the function that
    contains the offending statement, and then re-enable the
    optimization after the closing curly brace (}) of the function.

    With this method, you gain the optimum performance available for
    your source code.

 2. Use -Ol or -Oe instead of -Ole.

 Microsoft has confirmed this to be a problem with Version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 768. C6 /Gh Switch for Windows 2.x and C 5.10 Library Compatability

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q61057

 The Microsoft C version 6.00 Compiler option /Gh facilitates the use
 of C version 5.10 libraries with version 6.00 by replacing the C 6.00
 internal helper routine names with the earlier C 5.10 helper routine
 names. The /Gh option also allows building Windows Versions 2.x
 applications.

 Note: When using any C 5.10 libraries, the C 5.10 header files should
 also be used.

 Most C 5.10-compatible libraries can be used without using the /Gh
 option. This feature exists only in version 6.00 of the compiler and
 will be phased out in future versions.

 The following are common situations where the /Gh option might be
 used:

 1. Writing Windows 2.x applications because the Window 2.x libraries
    are used in place of the standard run-time libraries and they are
    created from the C 5.10 libraries.

 2. Use of any library where the helper functions have been replaced.

 3. Use of customized run-time libraries.


 769. C 6.00 README: Installation Program Notes

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh
 Last Modified: 23-JAN-1991    ArticleIdent: Q61186

 The following information is taken from the C version 6.00 README.DOC
 file.

 Installation Program Notes
 --------------------------

 If you are already running QuickHelp as a keyboard monitor under OS/2,
 disable it before running SETUP so it can copy new versions of
 QuickHelp and MSHELP.DLL to your hard disk.


 770. C 6.00 README: Differences Between C 5.10 and 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-NOV-1990    ArticleIdent: Q61187

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Differences Between C 5.10 and 6.00
 -----------------------------------

 For a complete discussion of the differences between Microsoft C
 Versions 5.10 and 6.00, see Appendix B of "Advanced Programming
 Techniques."


 771. C 6.00 README: Functions Declared as Float Now Return Float

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-NOV-1990    ArticleIdent: Q61188

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Functions Declared as Float
 ---------------------------

 In Microsoft C 5.10, functions declared as float always return a
 result of type double. In C 6.00, functions declared as float return a
 value of type float for ANSI compliance. This difference will cause
 compatibility problems when linking C 6.00 objects with C 5.10 objects
 and libraries that contain functions that return values of type float.

 To remedy the problem, prototype each function in your C 5.10
 libraries that returns type float as type double in your C 6.00 source
 code. Then compile with C 6.00. For example:

    double func_in_51_lib( float );


 772. C 6.00 README: The sizeof Operator Return Value

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61189

 The sizeof Operator Return Value
 --------------------------------

 To comply with ANSI specifications, the sizeof operator now returns an
 unsigned int rather than an int. This may cause problems in statements
 of the following form:

    -sizeof( expression )

 For example, the following line of code, used to position a file
 pointer one record from the end, no longer works:

    fseek( file, (long)(-sizeof( record )), SEEK_END );

 Because sizeof returns an unsigned int, the record size is zero-
 extended to a long value rather than sign-extended to the appropriate
 signed value.

 To avoid this problem, you can cast the record size to a long before
 you negate it, as follows:

    fseek( file, -((long)sizeof( record )), SEEK_END );


 773. C 6.00 README: Arithmetic Operations on Signed Short Values

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-NOV-1990    ArticleIdent: Q61190

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Arithmetic Operations on Signed Short Values
 --------------------------------------------

 In C 5.10 and Microsoft QuickC(R) 2.00, arithmetic on constants of
 type signed short is done using a signed long value. C 6.00 conforms
 to the ANSI specification by performing arithmetic operations on
 signed shorts and yielding a signed short value.

 This causes overflow in some instances of constant arithmetic, most
 noticeably, multiplication. For example, when interpreted as a signed
 short, 48*1000 results in a value of -15232 rather than 48000.


 774. C 6.00 README: Hexadecimal Constants in Strings

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-NOV-1990    ArticleIdent: Q61191

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Hexadecimal Constants in Strings
 --------------------------------

 Hexadecimal escape sequences in strings now conform to the ANSI
 specification by treating every potential hexadecimal digit following
 the \x as part of the constant. In C 5.10 and QuickC 2.00, hexadecimal
 escape sequences are limited to three characters.

 Typically, you will notice this when using hexadecimal escape
 sequences for length-preceded strings. Consider the following example:

    char TypeArray[] =
        "\x005float\x006double";

 In C 5.10 and QuickC 2.00, TypeArray contains the following bytes:

    <5>float<6>double<0>

 In C 6.00, TypeArray has the following bytes:

    _loatmouble<0>

 This is because in C 6.00, \x005f and \x006d are legal hexadecimal
 sequences that represent the underscore and "m" characters,
 respectively.

 There are two ways to avoid this problem. The simplest is to use
 string concatenation, as follows:

    char TypeArray[] =
        "\x005""float""\x006""double";

 According to the ANSI standard, adjacent string literals are
 concatenated after escape sequences have been calculated.

 A second solution is to use octal, which can never be more than three
 digits. The use of octal requires a small calculation and also
 requires that you pad out the digits with zeros on the left if
 necessary. However, even older, non-ANSI compilers will support this
 solution if portability is a concern.


 775. C 6.00 README: The offsetof Macro

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61192

 The following information is taken from the C Version 6.00 README.DOC
 file.

 The offsetof Macro
 ------------------

 The offsetof macro (defined in STDDEF.H) takes a struct type name and
 member name, and returns a type size_t value giving the offset in
 bytes of the member from the beginning of the struct.

 The expression

    offsetof( type, member_name )

 yields the byte offset of the member from the beginning of the struct.


 776. C 6.00 README: Loop Optimization (/Ol) Option Changed

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-NOV-1990    ArticleIdent: Q61193

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Loop Optimization (/Ol)
 -----------------------

 The loop optimization option (/Ol) in C 6.00 has a different effect
 than in C 5.10. To get the equivalent of the C 5.10 /Ol option in C
 6.00, use /Ole (loop code optimization and global register
 optimization). See Chapter 1 of "Advanced Programming Techniques" and
 online help for further details.


 777. C 6.00 README: CL, LINK Environment Variables Work As Before

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61194

 The following information is taken from the C Version 6.00 README.DOC
 file.

 CL and LINK Environment Variables Work As Before
 ------------------------------------------------

 The CL and LINK environment variables work just as in previous
 versions of Microsoft C. The contents of the environment variable are
 interpreted as a series of command-line options for the associated
 utility. Note, however, that the use of these environment variables
 can cause unpredictable build behavior under the Programmer's
 WorkBench (PWB).


 778. C 6.00 README: .DEF Files Allowed on Command Line

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61195

 The following information is taken from the C Version 6.00 README.DOC
 file.

 .DEF Files Allowed on Command Line
 ----------------------------------

 The CL command line can be used to specify the name of an OS/2 or
 Microsoft Windows(TM) module-definition file to be used by the linker.
 For example,

    CL CLOCK.C CLOCK.DEF

 tells CL to pass the name of the module-definition file "CLOCK.DEF" to
 the linker after compiling.


 779. C 6.00 README: /Gm No Longer Supported

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-SEP-1990    ArticleIdent: Q61196

 The following information is taken from the C Version 6.00 README.DOC
 file.

 /Gm No Longer Supported
 -----------------------

 The /Gm compiler option, as described in the "C Reference" and in
 online help, is no longer supported by C 6.00. The /Gm option placed
 near const items in the CONST segment.


 780. C 6.00 README: Compiler Options Order-Dependant

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61197

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Compiler Options Order-Dependant
 --------------------------------

 When using the /qc and /Zr options together, specify them in the
 following order on the command line:

    /qc /Zr


 781. C 6.00 README: setjmp/longjmp with /Ox, /Oe, /Ol, or /Og

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61198

 The following information is taken from the C Version 6.00 README.DOC file.

 Don't Use setjmp/longjmp with /Ox, /Oe, /Ol, or /Og
 ---------------------------------------------------

 Using the setjmp and longjmp functions with global optimization
 options /Ox, /Oe, /Ol, or /Og can cause incorrect code to be
 generated. To ensure that the compiler generates correct code, either
 compile without these options, or use the optimize pragma to turn off
 /Oe, /Ol, and /Og in functions containing setjmp and longjmp, as
 follows:

    #pragma optimize( "elg",off )

         . . . {function containing setjmp or longjmp}

    #pragma optimize( "",on )


 782. C 6.00 README: New /BATCH Option

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61199

 The following information is taken from the C Version 6.00 README.DOC
 file.

 New /BATCH Option
 -----------------

 /BATCH Option. To disable prompting for library names or other
 information and permit the use of CL in a batch or command file,
 specify the /BATCH option.


 783. C 6.00 README: How to Get Fastest/Smallest Code

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61200

 The following information is taken from the C Version 6.00 README.DOC
 file.

 How to Get Fastest/Smallest Code
 --------------------------------

 To get the fastest possible code, use the following optimization
 settings:

    /Oxaz /Grs

 The /Oz option causes the compiler to perform the most aggressive type
 of loop optimization.

 To get the smallest possible code, use the following settings:

    /Osleazr

 For small code with a greater margin of safety, use

    /Osler


 784. C 6.00 README: Use /Gh to Build Windows 2.x Applications

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61201

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Use /Gh Option to Build Windows 2.x Applications
 ------------------------------------------------

 The /Gh option allows building with Microsoft Windows 2.x libraries.
 This option is not needed for versions of Windows later than 2.x. In
 addition, this feature exists only in C 6.00, and will be phased out
 in future versions of the compiler.


 785. C 6.00 README: _setfont() Return Value Documented Incorrectly

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-AUG-1990    ArticleIdent: Q61202

 The following information is taken from the C Version 6.00 README.DOC
 file.

 _setfont() Return Value Documented Incorrectly
 --------------------------------------------

 The return values for _setfont() as described in online help are
 incorrect. The _setfont() function returns the font index number if
 successful, or a negative number if unsuccessful.


 786. C 6.00 README: fstat() Return Value Improved Under HPFS

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61203

 The following information is taken from the C Version 6.00 README.DOC
 file.

 fstat() Return Value Improved Under OS/2 1.20
 ---------------------------------------------

 The return values for the fstat() function are described incompletely
 in online help. Under DOS or versions of OS/2 prior to 1.20, fstat()
 returns the same value (the modification time) in the st_mtime,
 st_atime, and st_ctime fields, because that is the only value
 maintained by the system.

 However, under OS/2 1.20's High Performance File System, fstat() returns
 the expected values in st_mtime (time the file was last written),
 st_atime (time the file was last accessed for reading or writing), and
 st_ctime (time the file was created).


 787. C 6.00 README: Nested Anonymous Structs/Unions

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61204

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Nested Anonymous Structs/Unions Must Be Completely Specified
 ------------------------------------------------------------

 You cannot use a tag or typedef to add the members of an anonymous
 (nameless) struct or union to another anonymous struct or union.
 Instead, you must give the full definition of the struct to be nested.
 Assume you have the following anonymous struct:

    struct oneTag
    {
        int aMem;
        int bMem;
    };

 The following code fragment shows the incorrect way to include the
 members of this struct in another anonymous struct:

    struct anotherTag
    {
        struct oneTag;       // INCORRECT
        int cMem;
    };

 The correct method is to specify the nested struct fully:

    struct anotherTag
    {
        struct              // CORRECT
        {
            int aMem;
            int bMem;
        };
        cMem;
    };


 788. C 6.00 README: Signal() Function Limited in Multithread Usage

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61205

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Signal() Function Limited in Multithread Usage
 ----------------------------------------------

 The signal() function has limitations when used to build multithreaded
 applications or dynamic-link libraries. Specifically, only
 signal(SIGFPE,...) is supported in a multithreaded environment. To
 trap error or interrupt conditions in this case, use direct calls to
 DOSSETSIGHANDLER or DOSSETVEC.


 789. C 6.00 README: PWB Build Procedure

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61206

 The following information is taken from the C Version 6.00 README.DOC
 file.

 PWB Build Procedure
 -------------------

 When developing programs with PWB, you usually follow these basic
 steps:

 - Edit your source file or files.

 - Use the Build Options command on the Options menu to set initial
   build options.

 - Use the Compiler Options and Link Options commands to adjust
   specific parameters.

 - If you are building a multimodule program, use Set Program List on
   the Make menu to specify the files that will be included in the
   program.

 - Choose Build or Rebuild All from the Make menu to build your
   program.

 For more information, choose "Building and Running Programs" from the
 Programmer's WorkBench contents screen in online help.


 790. C 6.00 README: Building PM Applications in PWB

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61207

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Building Presentation Manager Applications in PWB
 -------------------------------------------------

 The Presentation Manager build options in PWB assume that functions in
 your program use the _loadds attribute in the functions that require
 it and that exported functions are identified with the _export
 keyword.

 If your program does not identify exported and/or _loadds functions in
 the function header, you need to do two things to build the program
 successfully under PWB. First, select the Windows Entry/Exit Codes
 check box in the C Compiler Options dialog box. This is the equivalent
 of specifying /Gw on the command line.

 Second, make sure the exported function names in your .DEF file are
 all in uppercase so that they can be found correctly at link time. You
 can also build the program successfully by disabling the No Ignore
 Case option in the Link Options dialog box, but this is not
 recommended.

 In particular, you will have the problems described here if you use
 PWB to build the example programs in Charles Petzold's book
 "Programming the OS/2 Presentation Manager." Programs built using the
 makefiles provided in the book will run correctly, but programs built
 from within PWB must follow the instructions specified above.


 791. C 6.00 README: Loading PWB Quickly

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61208

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Loading PWB Quickly
 -------------------

 Programmer's WorkBench (PWB) consists of the basic editor and four
 editor extensions that contain the functionality for building,
 linking, online help, and the Source Browser. These editor extensions
 are loaded automatically each time you invoke PWB.

 If you want PWB to load more quickly, you can rename some or all of
 the PWB extensions and then load them only when they are needed.

 For example, you can change the names of all the extension files from
 *.MXT (DOS) or *.PXT (OS2) to *.EXT. Then include the following section in
 your TOOLS.INI file:

    [pwb-ext]
    load:$PATH:pwbhelp.ext      ;Online Help
    load:$PATH:pwbc.ext         ;C compiler
    load:$PATH:pwbrowse.ext     ;Source Browser
    load:$PATH:pwbutils.ext     ;LINK, NMAKE, and CodeView

 To load all the extensions at once, execute the following in PWB:

    arg "ext" initialize

 With the default key assignments, this is

    ALT+A "ext" SHIFT+F8

 To load a single extension -- the help extension, for example -- you
 can use the following:

    arg "load:$PATH:pwbhelp.ext" assign

 With the default key assignment, this translates to

    ALT+A "load:$PATH:pwbhelp.ext" ALT+=

 If you decide to rename the extensions and thus disable the extension
 autoload feature of PWB, you still have the option of starting up PWB
 with all the extensions loaded.

 To do this, define a macro in the PWB section of TOOLS.INI and assign
 it to a key of your choice. The following TOOLS.INI entry creates a
 macro called "extload" and assigns it to the F11 key:

    extload:=arg "ext" initialize
    extload:F11

 Then when you start PWB, you can use the /e option to execute
 "extload" on start up:

    PWB /e extload


 792. C 6.00 README: PWB Starts on Boot Monitor Under OS/2 1.10

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61209

 The following information is taken from the C Version 6.00 README.DOC
 file.

 PWB Starts on Boot Monitor Under OS/2 1.10
 ------------------------------------------

 In OS/2 1.10, starting up PWB on a dual-monitor system will result in
 PWB appearing on the monitor that was active at the time the system
 was booted.

 For example, suppose you have both a color and a monochrome monitor,
 and the color monitor is the active monitor when you boot your
 machine. If you switch to the monochrome monitor and then invoke PWB,
 PWB will appear on the color monitor.

 This problem does not exist under OS/2 1.20.


 793. C 6.00 README: Use Only Alpha Numeric Characters in PWB Build

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61210

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Use Only Alpha Numeric Characters in PWB Build File Extensions
 --------------------------------------------------------------

 To avoid conflict with special characters used by the PWB MAKE
 facility, filenames in a PWB program list or in customized build
 options can only have extensions that contain the following
 characters:

    0-9
    A-Z
    a-z

 No other characters are allowed in a filename extension.


 794. C 6.00 README: PWB Run Command Line Cannot Contain $ or ^

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61211

 The following information is taken from the C Version 6.00 README.DOC
 file.

 PWB Run Command Line Cannot Contain $ or ^
 ------------------------------------------

 The Command Line option on the Run menu in PWB cannot contain
 characters that have special meaning for NMAKE. In particular, you
 should not use the caret (^) or the dollar sign ($) in command lines
 that are passed to your application by PWB.


 795. C 6.00 README: CL Environment Variable w/PWB May Cause Problem

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61212

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Using CL Environment Variable with PWB May Cause Problems
 ---------------------------------------------------------

 The CL environment variable is fully supported in version 6.00 of the
 C compiler. However, when building programs from within PWB, you
 should disable the CL environment variable to avoid interaction with
 PWB build settings.


 796. C 6.00 README: Use Run.Customize to Install Your Editor

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61213

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Use Run.Customize to Install Your Editor into PWB
 -------------------------------------------------

 You can launch the editor of your choice from within the PWB
 integrated environment. For more information, consult the online help
 for the Customize Menu option on the Run menu.


 797. C 6.00 README: PWB: Use %s, Not %S, for Run.Customize Argument

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61214

 The following information is taken from the C Version 6.00 README.DOC
 file.

 PWB: Use %s, Not %S, for Run.Customize Argument
 -----------------------------------------------

 The online help for the Customize Menu option on the Run Menu is
 partially incorrect. It says that when you are adding a command to the
 Run menu you can specify %S in the Argument box to get the name of the
 current file. However, to specify the current file as an argument, you
 must use %s (lowercase s).


 798. C 6.00 README: SHIFT+ALT, SHIFT+CTRL Different in DOS and OS/2

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61215

 The following information is taken from the C Version 6.00 README.DOC
 file.

 SHIFT+ALT, SHIFT+CTRL Different in DOS and OS/2
 -----------------------------------------------

 PWB handles the SHIFT+ALT and SHIFT+CTRL key assignments differently
 depending on whether you are running in DOS or OS/2. In DOS, a key
 sequence beginning with SHIFT+ALT or SHIFT+CTRL only recognizes the
 unshifted value of the third key:

    SHIFT+CTRL+<unshifted_character>
    SHIFT+ALT+<unshifted_character>

 In OS/2, however, this key combination requires the shifted  version
 of the key to work correctly:

    SHIFT+CTRL+<shifted_character>
    SHIFT+ALT+<shifted_character>


 799. C 6.00 README: PWB: Keep System Files Out of Build

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61216

 The following information is taken from the C Version 6.00 README.DOC
 file.

 PWB: Keeping System Files out of Build Dependencies
 ---------------------------------------------------

 For information on how to keep system include files (include file
 names surrounded by angle brackets) out of your list of build
 dependencies, see online help for a description of the Build switch's
 system/no system option.


 800. C 6.00 README: Customizing PWB Program Lists

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61217

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Customizing PWB Program Lists
 -----------------------------

 You can add your own build information to a PWB make file by putting
 the following line at the end of the file:

    # << User_supplied_information >>

 You can then add your own NMAKE description file commands without
 disturbing the information created by PWB's build process.

 For more information, consult the online help for the Make menu's Set
 Program List command.


 801. C 6.00 README: PWB: OS/2 Long Filename Support

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | file name
 Last Modified: 15-AUG-1990    ArticleIdent: Q61218

 The following information is taken from the C Version 6.00 README.DOC
 file.

 OS/2 1.20 LONG FILENAME SUPPORT
 -------------------------------

 OS/2 1.20 long filenames are supported in all PWB file-handling
 functions, with a couple of exceptions. This section defines long
 filenames, summarizes restrictions, and enumerates special cases.

 For additional information on support of long filenames, query on the
 following:

    long and filenames

 Long Filenames
 --------------

 To PWB, a "long filename" is any filename containing the characters

    +=[];^,

 Also included is any filename containing a space, or any filename
 whose base name is longer than eight characters. Long filenames can
 contain more than one period (.) and can have more than three letters
 following the final period.

 However, files that are intended to be used as part of the build
 process have more severe naming restrictions. To be used as part of a
 build, the filename cannot contain spaces or any of the special
 characters listed above.

 In addition, existing rules for specifying an extension apply: the
 extension consists of a period (.) followed by one to three
 alphanumeric characters. To avoid conflict with NMAKE, filename
 extensions should not contain any dollar signs ($).

 Quoted Filenames
 -----------------

 Any filename may be quoted anywhere. Quoting involves ONLY the
 addition of the double-quote character (") at the beginning and end of
 the complete filename, including the path. There is no escape
 character, as quotes themselves are not valid filename characters.
 Some situations may require quoting of long filenames containing
 characters that were previously illegal.

 Filename Length
 ---------------

 Under OS/2 1.20, each portion of a filename is restricted in length to
 256 characters. In PWB and other utilities, the ENTIRE filename length
 is restricted to 200 characters.

 Extensions
 ----------

 For build purposes, filename extensions are recognized as such ONLY if
 they are three characters or fewer in length. Thus "WAIT.C" is
 recognized as having an extension of ".C", while "WAIT.C PROGRAM" is
 treated as if it has no extension.

 Case Preservation
 -----------------

 OS/2 1.20 is case insensitive and case preserving. Thus, "File" "FILE"
 both refer to the same file, but OS/2 will not perform any case
 changes on the filenames created or copied. PWB operates similarly:
 case in filenames is preserved as typed by the user, but matches are
 made without regard to case.

 Exceptions
 ----------

 Help files may not have long filenames. The Helpfiles switch,
 therefore, does not support long filenames.

 What to Quote
 -------------

 You must explicitly quote long filenames in the following situations:

 - Filenames inserted in a "%s" format field that could be filenames.
   For example, if long filenames could be used, the Readonly switch,
   under OS/2, could be set to:

      readonly: attrib -r "%s"

 - Commands to be executed that happen to be long filenames. For
   example, for a program named "Change Attribute", the readonly
   command above might instead be:

      readonly: "Change Attribute" -r "%s"


 802. C 6.00 README: Disabled Keyboard in OS/2 1.10 Release 88300

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61219

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Disabled Keyboard in OS/2 1.10 Release 88300
 --------------------------------------------

 If you are using release 88300 of OS/2 1.10 and running PWB in a
 window, your keyboard may become disabled after choosing Run OS/2
 Command or Execute on the Run menu. If you have this release, contact
 your OS/2 distributor for upgrade information.

 This is not a problem with versions of OS/2 other than 88300, nor does
 it occur when running PWB in a full-screen group.


 803. C 6.00 README: CV: New Statefileread Switch

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61220

 The following information is taken from the C Version 6.00 README.DOC
 file.

 New Statefileread Switch
 ------------------------

 - The Microsoft CodeView(R) debugger now has a TOOLS.INI switch that
   controls whether breakpoints, window configurations, and other
   information is saved and restored from one debugging session to the
   next. This switch, the Statefileread switch, is set to yes if you
   want this information to be preserved, and no if you do not.

 For further information, see "Configuring CodeView" in the CodeView
 online help. Also, see the description of the /TSF start-up option
 below.


 804. C 6.00 README: CV: Debugging Programs w/Code in Include Files

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61221

 The following information is taken from the C Version 6.00 README.DOC
 file.

 CV: Don't Debug Programs with Code in Include Files
 ---------------------------------------------------

 - Do not attempt to debug programs with code in include files if those
   files are included prior to the main function.


 805. C 6.00 README: CodeView Can't Call _fastcall Functions

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_codeview fastcall
 Last Modified: 24-JAN-1991    ArticleIdent: Q61222

 The following information is taken from the C version 6.00 README.DOC
 file.

 CodeView Can't Call _fastcall Functions
 ---------------------------------------

 - When using CodeView to debug programs containing _fastcall
   functions, you cannot call the _fastcall functions from within
   CodeView.


 806. C 6.00 README: Don't Use CTRL+BREAK When Debug History On

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61223

 The following information is taken from the C Version 6.00 README.DOC file.

 Don't Press CTRL+BREAK When Debug History On Under OS/2
 -------------------------------------------------------

 - Pressing CTRL+BREAK to end a debugging session while recording debug
   history in OS/2 can result in a corruption of the files used to
   record debug history. Turn off debug history before ending a
   debugging session with CTRL+BREAK.

   If you do press CTRL+BREAK while debug history is on, do not try to
   reuse the files containing the debug history information (.CVH or
   .CVI files).


 807. C 6.00 README: Graphics and Dual-Monitor Debugging Requirement

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61224

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Graphics and Dual-Monitor Debugging Require New Mouse Driver
 ------------------------------------------------------------

 - When debugging a graphics program or using two-monitor debugging,
   make sure you have the most current version (7.00) of the Microsoft
   Mouse driver installed. If you do not have the most current version,
   or are using a mouse from another manufacturer, you should use the
   /M option (disable mouse support) in the situations referred to
   above.


 808. C 6.00 README: CodeView: New Start-Up Switches

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61225

 The following information is taken from the C Version 6.00 README.DOC
 file.

 CodeView: New Start-Up Switches
 -------------------------------

 /K     Disable keyboard monitor installation (OS/2) or disable hooking
        of the keyboard interrupt (DOS). See online help for further
        details.

 /TSF   Disable or enable the reading of the CodeView state file,
        depending on the setting of the Statefileread switch in
        TOOLS.INI. The CodeView state file restores breakpoints,
        windows, and other parameters from the last debugging session.
        See online help for further details.


 809. C 6.00 README: LINK Error L1116 Text

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61226

 The following information is taken from the C Version 6.00 README.DOC file.

 LINK Error L1116 Text
 ---------------------

 - The text for the LINK error message L1116 should read as follows:

      /EXEPACK only valid for OS/2 and real mode applications.

   In other words, you cannot use the /EXEPACK option when linking
   Windows applications.


 810. C 6.00 README: NMAKE: Avoiding Out-of-Memory Condition w/DOS

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61227

 The following information is taken from the C Version 6.00 README.DOC file.

 NMAKE: Avoiding Out-of-Memory Condition Under DOS
 -------------------------------------------------

 - If you experience difficulties using NMAKE with memory-intensive
   makefiles under DOS, you can use the alternate program NMK.COM. For
   further information about NMK, type NMK /HELP at the operating
   system prompt.


 811. C 6.00 README: LINK/LIB/NMAKE/BIND: OS/2 1.20 Long Filenames

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61228

 The following information is taken from the C Version 6.00 README.DOC
 file.

 LINK/LIB/NMAKE/BIND: OS/2 1.20 Long Filename Restrictions
 ---------------------------------------------------------

 - LINK, LIB, NMAKE, and BIND have two restrictions with regard to
   support of OS/2 1.20 long filenames:

 1. Quoted filenames can be used only once per argument. You can get
    around this limitation by using a response file.

 2. If quotes are necessary, the full filename (including the path)
    must be enclosed in quotation marks.


 812. C 6.00 README: NMAKE: Source Objects in Different Directories

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61229

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Using NMAKE with Source Objects in Different Directories
 --------------------------------------------------------

 - You can define NMAKE inference rules that allow for the placement of
   source files in one directory and object files in another directory.
   The following sample makefile shows how to do this:

   Sample Makefile
   ---------------

       # Define 'source' as the directory for .C files and
       # 'obj' for .OBJ files. The caret (^) is required prior
       # to the last backslash (\) to tell NMAKE to use the
       # character literally, not as the line-continuation
       # character.

       source = d:\src^\
       obj    = d:\obj^\

       # Next, set up an inference rule to compile .C files in
       # the d:\src directory into a .OBJ file and put the
       # .OBJ in the d:\obj directory. Use the compiler option
       # /Fo to give the object the name of the current target
       # ($@).

       {$(source)}.c{$(obj)}.obj :
           $(CC) -c /Fo$@ $<

       $(obj)test.obj : $(src)test.c


 813. C 6.00 README: LINK: The /NOG

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61230

 The following information is taken from the C Version 6.00 README.DOC
 file.

 LINK: The /NOG[ROUPASSOCIATION] Option
 --------------------------------------

 The /NOG option causes the linker to ignore group associations when
 assigning addresses to data and code items. It is provided primarily
 for compatibility with previous versions of the linker (versions 2.02
 and earlier) and early versions of Microsoft language compilers.

 Note: This option should be used only with assembly-language programs.


 814. C 6.00 README: CV: Blank Screen Debugging Under Earlier OS/2

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61231

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Blank Screen While Debugging Under OS/2 1.20
 --------------------------------------------

 If your screen group goes blank after returning from debugging, check
 to see if the following conditions are true:

 - You are running CodeView under OS/2 1.20

 - You are using the two-monitor option (/2)

 If all of the above conditions are true, take the following steps to
 determine if you need to upgrade your version of OS/2:

 1. Type "syslevel" at an OS/2 command prompt. This identifies the
    version of OS/2 you have installed.

    Note: Identifying the version alone does not indicate a problem.
    The conditions above must be present before an upgrade is required.

 2. If the syslevel command returns the value "xr04043" and you have
    experienced the difficulties described above, contact your OS/2
    distributor for an upgrade.


 815. C 6.00 README: CV Extended Memory Option with Northgate

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61232

 The following information is taken from the C Version 6.00 README.DOC
 file.

 CodeView Extended Memory Option with Video Seven VGA 16
 -------------------------------------------------------

 To use the CodeView extended memory option (/X) on a Northgate(TM)
 computer with the Video Seven Vega(TM) 16-bit VGA video adapter, you
 must run the Northgate program NORMAL.COM before starting CodeView.

 Northgate is a registered trademark of Northgate Computer Systems, a
 division of ABL Corporation. Vega is a trademark of Video Seven, Inc.


 816. C 6.00 README: Getting Help on Start-Up Error Messages

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh
 Last Modified: 23-JAN-1991    ArticleIdent: Q61233

 The following information is taken from the C version 6.00 README.DOC
 file.

 Getting Help on Start-Up Error Messages
 ---------------------------------------

 Sometimes a program in the C 6.00 Professional Development System may
 encounter an error condition on start-up that prevents the program
 from running.

 To find out more about the resulting error message, you can use the
 online help system. Access online help by using the stand-alone
 utility QuickHelp, or by using the Help menu in the Programmer's
 WorkBench (PWB).

 To find out about an error message using QuickHelp, at the operating
 system prompt type

    QH cxxxx

 where <c> is the error's alphabetic prefix and <xxxx> is the
 four-digit error number.

 To find out more about how to view errors from within PWB, choose
 "Errors Help" from the Microsoft Advisor Contents screen in PWB. (The
 Microsoft Advisor Contents screen appears when you choose "Contents"
 from the Help menu in PWB.)


 817. C 6.00 README: Getting Help on Files in the Packing List

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh
 Last Modified: 23-JAN-1991    ArticleIdent: Q61234

 The following information is taken from the C version 6.00 README.DOC
 file.

 Getting Help on Files Listed in the Packing List
 ------------------------------------------------

 You can use the QuickHelp program to get help on any of the executable
 files listed in the file PACKING.LST. Simply type QH followed by the
 name of executable file. For example, to view the on-line help file
 for NMAKE, type

    QH NMAKE.EXE

 at the operating-system prompt.


 818. C 6.00 README: Using a Large Number of Help Files

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61235

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Using a Large Number of Help Files
 ----------------------------------

 If the help files for OS/2 and several different languages are loaded
 onto your system, you may receive a message that you have too many
 help files open.

 You can get around this problem by concatenating some of the help
 files. Most applications that display help allow up to 19 open
 physical help files. However, the number of logical (that is,
 concatenated) help files allowed is usually much larger.

 To concatenate help files, use the DOS or OS/2 COPY command with the
 /B (binary) option. For example, to concatenate LINK.HLP and UTILS.HLP
 into a single help file called COMBO.HLP, use the following command:

    COPY LINK.HLP /B + UTILS.HLP /B COMBO.HLP /B

 The order in which you concatenate the files determines the order in
 which the files are searched for help information.

 As a final step, be sure to delete the original help files, or move
 them to a directory that is not listed in your HELPFILES environment
 variable.


 819. C 6.00 README: Increasing the Maximum Number of Open Files

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61236

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Increasing the Maximum Number of Open Files
 -------------------------------------------

 C 6.00 allows you to increase the maximum number of files that may be
 open for I/O (the default number is 20). To use this feature, you must
 be running either OS/2 or DOS version 3.30 or later. Use the
 procedures described in the remainder of this section to increase the
 maximum number of open files.

 Increasing File Handles
 -----------------------

 To increase the number of file handles, edit the start-up source file
 CRT0DAT.ASM, which is provided in this release. Change the line

    _NFILE_ = 20

 so that _NFILE_ is set to the desired maximum. For example, to
 increase the maximum number of available file handles to 40, change
 the line as shown here:

    _NFILE_ = 40

 Note: Increasing the number of file handles allows you to use
 low-level I/O functions, such as open and read, with more files.
 However, it does not affect the number of stream-level I/O files (that
 is, the number of FILE * streams).

 Increasing Streams
 ------------------

 To increase the number of streams, edit the source file _FILE.C.
 Change the line

    #define _NFILE_ 20

 to set _NFILE_ to the desired maximum. For example, to allow a maximum
 of 40 streams, change the line as shown here:

    #define _NFILE_ 40

 Increasing the number of streams allows you to use stream-level I/O
 functions, such as fopen and fread, with more files.

 Note: The number of low-level file handles must be greater than or
 equal to the number of stream-level files. Thus, if you increase the
 value of _NFILE_ in the module _FILE.C, you must also increase the
 value of _NFILE_ in the module CRT0DAT.ASM.

 Increasing the System Limit
 ---------------------------

 To use more than 20 files at a time, you must increase the file limit
 imposed on your process by the operating system.

 To increase the system-wide limit, increase the number of files
 available on your system as a whole by editing your system
 configuration file (CONFIG.SYS). For example, to allow 100 open files
 at a time on your system, put this statement in the configuration
 file:

    FILES=120

 To increase the process-by-process limit, you must also increase the
 number of files the operating system makes available to your
 particular process. To do this, edit CRT0DAT.ASM and enable the
 commented-out code that is preceded by the appropriate description.

 In the DOS version of CRT0DAT.ASM, for example, the commented-out code
 appears as shown here:

    ;       mov     ah,67h
    ;       mov     bx,_NFILE_
    ;       callos

 In the OS/2 version of CRT0DAT.ASM, the code appears as a call to
 DOSSETMAXFH. Under OS/2, you must also enable the "extrn
 DOSSETMAXFH:far" declaration that appears near the beginning of the
 file.

 In either case, remove the semicolon (;) comment characters.

 Note: Under OS/2, you must take into account the fact that each
 process has the potential to "own" open files. When planning how many
 open files to allow on a system-wide basis, take this into account.

 Using the Modified Start-Up Files
 ---------------------------------

 After you modify CRT0DAT.ASM and/or _FILE.C, assemble or compile the
 file(s). The start-up MAKEFILE contains sample command lines to
 perform these jobs. Note that the object files will differ for OS/2
 and DOS.

 To use the new object files, either explicitly link your program with
 the new CRT0DAT.OBJ and _FILE.OBJ file(s), or replace the CRT0DAT.OBJ
 and _FILE.OBJ object(s) in the appropriate model of the C run-time
 library.


 820. C 6.00 README: Multithread (MT) and Dynamic-Link Library (DLL)

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61237

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Multithread (MT) and Dynamic-Link Library (DLL) Libraries
 ---------------------------------------------------------

 By default, the C 6.00 MT and DLL libraries support 40 file handles
 and streams instead of 20, which is the single thread library default.

 To increase the number of file handles (low-level I/O), simply issue a
 DOSSETMAXFH call from within your program. This increases the open
 file limit for the calling process.

 To increase the allowable number of open streams, first make sure that
 the number of file handles is greater than or equal to the number of
 streams you want. Then rebuild module _FILE.C with the desired _NFILE
 setting (as described under the single thread description). Since the
 MT and DLL libraries are large model, be sure to compile _FILE.C with
 the /AL switch.


 821. C 6.00 README: 43-Line Mode with DOS 4.01 ANSI.SYS

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 24-JAN-1991    ArticleIdent: Q61238

 The following information is taken from the C version 6.00 README.DOC
 file.

 43-Line Mode with DOS 4.01 ANSI.SYS
 -----------------------------------

 You may experience problems trying to switch CodeView or the
 Programmer's WorkBench (PWB) to 43-line mode if you are using DOS 4.01
 and ANSI.SYS.

 To use Codeview or PWB in 43-line mode in this situation, switch to
 43-line mode using the MODE command (MODE CO80,43) before you invoke
 the program.

 This problem also affects the graphics functions _settextrows and
 _setvideomoderows. Under DOS 4.01 with ANSI.SYS installed, using these
 functions to set 43-line mode may cause unexpected behavior.

 At the moment, the only known solution is to remove ANSI.SYS from your
 CONFIG.SYS file and reboot your machine.


 822. C 6.00 README: Notes on "C Reference"

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-APR-1990    ArticleIdent: Q61239

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Notes on "C Reference"
 ----------------------

    Page    Note
    ----    ----

    5       CL (Compiler) /Bx Options
            -------------------------

            The complete syntax of the /B1, /B2, and /B3 options is as
            follows:

               /B1 [drive:path]C1L
               /B2 [drive:path]C2L
               /B3 [drive:path]C3L

            See online help for further information.

    7       CL (Compiler) /ML Option
            ------------------------

            The third sentence should read: "The /ML option is
            functionally equivalent to /ALw /FPa /G2 /D_MT; however,
            you must specify /ML rather than the expanded equivalent."

    8       CL (Compiler) /MT Option
            ------------------------

            The second sentence should read: "The /MT option is
            functionally equivalent to /ALw /FPi /G2 /D_MT; however,
            you must specify /MT rather than the expanded equivalent."

    34      NAME Statement
            --------------

            The syntax for the NAME statement in a LINK module-
            definition file is as follows:

               NAME [appname] [apptype] [NEWFILES]

            The optional attribute NEWFILES specifies that the
            application supports long filenames and extended file
            attributes under OS/2 1.2.

            The linker also supports LONGNAMES as a synonym for
            NEWFILES, although LONGNAMES is now considered obsolete.

    347     The _strtold Function
            ---------------------

            The _strtold function is not an ANSI function.


 823. C 6.00 README: C 6.00 and the ANSI C Specification

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61240

 The following information is taken from the C Version 6.00 README.DOC
 file.

 C 6.00 and the ANSI C Specification
 -----------------------------------

 The online help for the __STDC__ macro implies that C 6.00 is fully
 ANSI C compatible. While C 6.00 has many ANSI-related enhancements, it
 is not strictly accurate to say that the compiler is fully ANSI
 compatible.

 For complete information on Microsoft C 6.00 ANSI compatibility, see
 Appendix B of "Advanced Programming Techniques."


 824. C 6.00 README: "Advanced Programming Techniques" Notes

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr fastcall
 Last Modified: 24-JAN-1991    ArticleIdent: Q61241

 The following information is taken from the C version 6.00 README.DOC
 file.

 "Advanced Programming Techniques" Notes
 ---------------------------------------

    Page    Note
    ----    ----

    36      The Tiny Memory Model
            ---------------------

            In the third paragraph, the reference to CRTCOM.OBJ should
            be to CRTCOM.LIB.

    38      Specifying a Memory Model
            -------------------------

            At the bottom of the page, the reference to CRTCOM.OBJ
            should be to CRTCOM.LIB.

    99      Preparing for Incremental Linking: The /INCREMENTAL Option
            ----------------------------------------------------------

            The first sentence of the second paragraph in this section
            should read: "The /INCREMENTAL (/INC) option prepares a
            .EXE file for incremental linking."

    124     PWB's extmake Syntax
            --------------------

            The Programmer's WorkBench extmake switch referred to in
            this section is now called the build switch. However, the
            syntax for getting information about fully qualified
            filenames is still valid.

            For further information, see the help topic "build."

    348     Calling the OS/2 API
            --------------------

            The second paragraph on Page 349 should read: "Most OS/2
            API functions return 0 if the operation is successful. They
            return an error code if the operation fails. The exception
            to this is Presentation Manager APIs, which return 0 if the
            operation fails. If you are programming under the
            Presentation Manager, use the WinGetLastError function to
            determine the nature of an API function call error."

    352     Family API Functions
            --------------------

            The functions VioGetBuf and VioShowBuf should not be
            included in the list of OS/2 1.10 Family API functions.

    430     The _fastcall Attribute (/Gr Option)
            ------------------------------------

            The list of argument types and their potential register
            assignments should note that far pointers are passed on the
            stack.

    456     Default Date and Time
            ---------------------

            References in this section to the predefined date and time
            macros should be to __DATE__ and __TIME__, rather than
            _DATE_ and _TIME_.


 825. C 6.00 README: Patching MOUCALLS.DLL (OS/2 1.10 Only)

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61242

 The following information is taken from the C Version 6.00 README.DOC
 file.

 Patching MOUCALLS.DLL (OS/2 1.10 Only)
 --------------------------------------

 The dynamic-link library, MOUCALLS.DLL, handles OS/2 API functions
 that process mouse messages. Some versions of MOUCALLS.DLL shipped
 with OS/2 1.10 cause a general protection fault when running such
 applications as the Programmer's WorkBench (PWB). This section
 describes how to patch MOUCALLS.DLL to correct the error.

 Identifying the Problem
 -----------------------

 When a general protection fault occurs under OS/2, the system displays
 the location of the fault. If the fault occurs with CS equal to 20F,
 follow the procedure outlined in the next section to patch
 MOUCALLS.DLL.

 Patching MOUCALLS.DLL
 ---------------------

 Because OS/2 1.10 with the Presentation Manager uses MOUCALLS.DLL, you
 cannot directly alter the file. Instead you must modify a copy of the
 file as shown:

  1. Create a directory on your boot disk called C:\NEWMOU.

  2. Copy your C:\CONFIG.SYS file to C:\CONFIG.MOU.

  3. Edit your C:\CONFIG.SYS file. There is a line in it that begins
     with LIBPATH. Add the directory C:\NEWMOU as the first directory
     in the line. So, if the LIBPATH line originally looks like

       LIBPATH=C:\OS2;C:\LANMAN

    change it to

       LIBPATH=C:\NEWMOU;C:\OS2;C:\LANMAN

  4. Locate the file MOUCALLS.DLL on your hard drive. It is probably in
     the OS2 directory of your boot drive. If not, it is certainly in
     one of the directories listed in the LIBPATH line you just edited.

     Copy MOUCALLS.DLL to the C:\NEWMOU directory.

  5. Reboot your computer.

  6. After the system has come back up, change directories to the
     C:\OS2 directory, or wherever the original MOUCALLS.DLL resides.

  7. Run the following command:

        PATCH MOUCALLS.DLL

     The PATCH program prompts you for the offset location to be patched.
     Type the following offset:

        1432

     Then change the hexadecimal value of the byte at that location from
     1A to 1C.

     Note that there should be a program called PATCH.EXE on your path.
     It will make the appropriate change to the MOUCALLS.DLL file.

  8. Copy C:\CONFIG.MOU back over C:\CONFIG.SYS and delete
     C:\CONFIG.MOU.

  9. Reboot your computer.

 10. After the system has come back up, delete the files in C:\NEWMOU
     and remove the directory.


 826. C 6.00 README: HIMEM Documentation

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61243

 The following information is taken from the C Version 6.00 README.DOC
 file.

 HIMEM DOCUMENTATION
 -------------------

 Description
 -----------

 HIMEM.SYS is an extended memory manager provided so that CodeView can
 take advantage of all your computer's available memory when running
 under DOS on an 80286 or 80386 machine with expanded memory.

 Usage
 -----

    DEVICE=[d:][path]HIMEM.SYS [options]

 The most common way to use HIMEM.SYS is to include the following line
 in your CONFIG.SYS file:

    DEVICE=HIMEM.SYS

 The following options are also available:

    /HMAMIN=h
    /NUMHANDLES=n

 The /HMAMIN option allows controlled access to high memory by
 specifying (in <h>) the minimum amount of memory a terminate-and-
 stay-resident (TSR) program can use in high memory.

 The /NUMHANDLES option sets (in <n>) the maximum number of extended
 memory block handles that can be used at any given time.


 827. C 6.00 README: RAMDRIVE Documentation

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61244

 The following information is taken from the C Version 6.00 README.DOC
 file.

 RAMDRIVE DOCUMENTATION
 ----------------------

 Description
 -----------

 RAMDRIVE.SYS is an installable device driver that lets you use a
 portion of your computer's memory as if it were a hard disk.

 Usage
 -----

    DEVICE=[d:][path]RAMDRIVE.SYS [disksize][sectorsize][entries][memtype]

 <disksize> specifies the disk size in kilobytes (K). The default is
 64K, and the minimum is 16K.

 <sectorsize> specifies the sector size in bytes. The default size is
 512 bytes. The following values are allowed: 128, 256, 512, and 1024.

 <entries> specifies the number of entries allowed in the root
 directory. The default value is 64; the minimum, 4; the maximum, 1024.

 <memtype> specifies what kind of memory you want RAMDRIVE to use. The
 following options are available:

 - The /e option lets you use any installed memory above one megabyte
   as a RAM disk. This option cannot be used with the /a option.

 - The /a option lets you use memory on an expanded memory board that
   is compatible with the Lotus/Intel/Microsoft Expanded Memory
   specification. This option cannot be used with the /e option.

 - If you omit the <memtype> option altogether, RAMDRIVE attempts to
   set up a virtual drive in conventional memory.


 828. C 6.00 README: SMARTDRV Documentation

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-APR-1990    ArticleIdent: Q61245

 The following information is taken from the C Version 6.00 README.DOC
 file.

 SMARTDRV DOCUMENTATION
 ----------------------

 Description
 -----------

 SMARTDRV.SYS is a disk-caching program for computers that have a hard
 disk and extended or expanded memory. For SMARTDRV to operate
 correctly, the current version of HIMEM must be installed.

 Usage
 -----

    DEVICE=[d:][path]SMARTDRV.SYS [size][/a]

 <size> is the amount of memory you want SMARTDRV to have. The default
 is 256K of extended memory or all of expanded memory.

 The /a switch is used when you have expanded memory or an expanded
 memory emulator. If you omit this switch, SMARTDRV uses extended
 memory.


 829. argv

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61262

 If you use argv[0] in a program you have written, you may notice that
 the string pointed to by argv[0] is different depending upon what
 operating system/environment you are under. To access the full path
 name of the program, use the global variable _pgmptr, which always
 points to the full path, regardless of the environment you are in.
 (For more information, query on the word _pgmptr.)

 Under MS-DOS versions 3.x and later, argv[0] points to a string that
 contains the complete path of the program being run. Under MS-DOS
 versions 2.x, argv[0] contains the program name only. Under OS/2,
 argv[0] generally points to a string that reflects exactly what was
 entered to execute the program. The following are some exceptions to
 the OS/2 rule:

 1. OS/2 EXE linked with /PM:PM --

       argv[0] points to complete path of program.

 2. OS/2 EXE under CodeView --

       argv[0] points to complete path of program.

 These variations are not attributable to the C version 6.00 run-time
 functions; they merely reflect what is passed to the program at run
 time by the operating system.


 830. CL: Error Output Not Redirected in Certain Cases

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00
 Last Modified: 11-JUL-1990    ArticleIdent: Q61304

 When using the C 6.00 CL command-line compiler under DOS with the
 following options

    /B1 C1L.EXE /Zi

 the output is not redirected properly (using the DOS stdout redirect
 ">").

 The following code example reproduces the problem:

 void main(void)
 {
   int i
 }

 Compile using the following command line (assuming you save the above
 in a file called FOO.C):

    cl /B1 C1L.EXE /Zi foo.c > foo.out

 The above program contains an error at Line 3 (no semicolon), and the
 following error should be generated and sent to the file BUG.OUT:

    foo.c(4) : error C2059: syntax error : '}'

 This error text never appears in the file FOO.OUT.

 This problem can be worked around by omitting the /Zi option from the
 command line, or omitting /B1 C1L.EXE.

 Microsoft has confirmed this to be a problem in C version 6.00. We
 researching this problem and will post new information here as it
 becomes available.


 831. Warning C4018: signed/unsigned Mismatch Not in QuickHelp

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 23-JAN-1991    ArticleIdent: Q61305

 Compiler warning C4018 is not documented in the online help files that
 come with the Microsoft C version 6.00 compiler. C4018 is a warning
 message that is new to C 6.00, and it is generated at warning level 3
 or 4 when the compiler finds code comparing a signed and an unsigned
 data type.

 Code Example
 ------------

 The following code generates C4018 at warning level 3 or 4:

 unsigned int u = 2;
 int i = 1;

 void main ( void )
 {
     if ( i == u )    // Warning is generated on this line.
         i = 0;
 }


 832. Browse Options Unavailable Under Strange Circumstances

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | hang stop halt
 Last Modified: 11-JUL-1990    ArticleIdent: Q61306

 Under certain circumstances, the Browse options within the Programmer's
 WorkBench (PWB) may be unavailable. You can take all the steps
 outlined in the documentation required to generate a Browse Database,
 but the Browse options may be still grayed out. Two possible solutions
 are deleting the make file and letting the PWB regenerate it, or
 deleting the CURRENT.STS file and resetting all the options for the
 editor.

 The most likely cause is an invalid CURRENT.STS file. This file can be
 found in the INIT directory or the current working directory.
 CURRENT.STS is used to save the PWB settings from session to session.
 If this file is in a form that is not acceptable to the PWB, strange
 results may occur during use of the PWB.

 One instance in which CURRENT.STS might become corrupt is in the case
 of a system crash from within the PWB during a compile.

 To determine if a corrupt CURRENT.STS is the cause of the problem,
 take the following steps:

 1. Invoke the PWB with the /DS switch to force it to ignore the
    CURRENT.STS file.

    Note: This will reset all switches within the environment that
    were previously recorded by CURRENT.STS.

 2. Take the normal steps required for preparing a Browse database.
    (Set a program list, mark Generate Browse Information under the
    Browse options menu, and rebuild the project.)

 Browse information should now be available. If disabling the
 CURRENT.STS does remedy the situation, the only permanent solution is
 to delete the CURRENT.STS file that is causing the problem.

 Note: Since deleting the CURRENT.STS file will result in the loss of
 all environment settings, it is advisable to note any important
 settings you may have set up before deleting the file.


 833. /Fs Does Not Locate Error When #line Directive Is Specified

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 11-JUL-1990    ArticleIdent: Q61308

 When the #line preprocessor directive is used with a filename label,
 /Fs generates a source listing with the correct error count but fails
 to correctly locate the errors in the listing file.

 Sample Code
 -----------

 #include <stdio.h>
 #line 1 "hello"

 void main()
 {
    intt x; /* the error is here */

    printf("hello");
 }

 Below is the normal source listing generated by the compiler:

  Line#    Source Line          Microsoft C Compiler Version 6.00

       1
       2 #include <stdio.h>
       3
       4 void main()
       5 {
       6    intt x; /* the error is here */
 ***** test.c(6) : error C2065: 'intt' : undefined
 ***** test.c(6) : error C2146: syntax error : missing ';' before ...
 ***** test.c(6) : error C2065: 'x' : undefined
       7
       8    printf("hello");
       9 }

 3 errors detected

 When compiled with a #line directive and a filename label, the source
 listing fails to indicate the error, only the number of errors. For
 example:

  Line#    Source Line          Microsoft C Compiler Version 6.00

       1 #include <stdio.h>
       2
       3 #line 1 "foobar"
       4
       5 void main()
       6 {
       7
       8 intt x; /* error is here */
       9
      10    printf("hello");
      11 }

 3 errors detected

 If the filename label ("foobar" in this case) is not specified, the
 source listing contains the error messages, but they are not in the
 correct place. For example:

  Line#    Source Line          Microsoft C Compiler Version 6.00

       1
       2 #include <stdio.h>
       3 #line 1
       4
 ***** test.c(4) : error C2065: 'intt' : undefined
 ***** test.c(4) : error C2146: syntax error : missing ';' before ...
 ***** test.c(4) : error C2065: 'x' : undefined
       5 void main()
       6 {
       7    intt x; /* the error is here */
       8
       9    printf("hello");
      10 }

 3 errors detected

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 834. /Ot May Generate Incorrect Code with Nested Conditionals

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61310

 When using the default optimization of -Ot with nested conditional
 expressions, the compiler may generate incorrect code if the
 conditionals are the same expression.

 The following code sample demonstrates the problem:

 #include <stdio.h>

 void main (void)
 {
    int i;

    for ( i = 0; i < 5; i++)
       if (i < 5)
          printf ("%d\n", i);
 }

 Output
 ------

    Actual  Expected
    ------  --------

      1       0
      2       1
      3       2
      4       3
              4

 Below are some suggested workarounds:

 1. Change "i < 5" in the above for loop, or change "i < 5" in the
    above if statement to "i <= 4".

 2. Use -Od to disable optimization when compiling.

 3. Use the #pragma optimization ("t", off/on) statement to
    disable/enable the default -Ot optimization before and after the
    function.

 4. Use a combination of optimizations (for example, -Ox, -Olt, etc.).

 The problem is with the default -Ot optimization, in particular; when
 used by itself, the optimizer will generate incorrect code.

 In the above code sample, the compiler does not generate the
 instruction for the first comparison in the for loop (as shown below).
 This causes the instruction pointer to jump to location $FC176 the
 first time through the loop.

 The end result is the same as if "i" went from 1 to 4 instead of from
 0 to 4.
          .
          .
          mov   WORD PTR [bp-2], 0
 $F166:
          cmp   WORD PTR [bp-2], 5 ;<- This "cmp" is missing
          jge   $FC167

          push  WORD PTR [bp-2]
          mov   ax, OFFSET DGROUP:$SG170
          push  ax
          call  _printf
          add   sp,4
 $FC176:
          inc   WORD PTR [bp-2]
          cmp   WORD PTR [bp-2], 5
          jl    $F166
          .
          .

 Microsoft has confirmed this to be a problem with C version 6.00 We
 are researching this problem and will post new information here as it
 becomes available.


 835. Internal Compiler Error: '@(#)regMD.c:1.100', Line 3074

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 11-JUL-1990    ArticleIdent: Q61312

 The program example below generates the following C1001: error when
 compiled with only the following individual optimizations:

    /Oa /Oc /Oi /On /Op /Or /Os /Ot /Ow /Oz

    foo.c(24) : fatal error C1001: Internal Compiler Error
          (compiler file '@(#)regMD.c:1.100', line 3074)
          Contact Microsoft Product Support Services

 Code Example
 ------------

 typedef struct
 {
    short cursize;      /* The current size of this buffer. */
    short nextscan;     /* The offset of the next scan entry.*/
 } struct1;

 typedef struct
 {
    short len;          /* Buffer entry length */
 } struct2;

 void main(void)
 {
    char far *cfptr1;
    char far *cfptr2;
    struct1 far *s1ptr;
    struct2 far *s2ptr;
    short    lenToMove;

    s1ptr = (struct1 far *) cfptr1;
    cfptr2 = (char far *) s2ptr + s2ptr->len;
    lenToMove = s1ptr->cursize - (short)((long)cfptr2 - (long)cfptr1);

    if ((cfptr1 + s1ptr->nextscan) >= cfptr2) // Line 24
    s1ptr->nextscan -= s2ptr->len;
 }

 If only the above optimizations are used to compile the program, the
 internal compiler error (ICE) will occur. However, if ONE option from
 the following list is added, the ICE will not occur:

  /Od /Oe /Og /Ol /Ox

 In addition, the following are several other workarounds that can be
 applied to the code itself:

 1. Use temporary variables to hold the intermediate results before the
    "if" statement.

 2. Make a function call between any of the assignment statements.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 836. malloc() Is Slower in Large and Compact Models

 Product Version(s): 5.00 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61313

 In LARGE and COMPACT models, it should be expected that malloc will be
 slower since it must use far pointer calls. It may be possible to
 improve malloc's performance by adjusting the _amblksiz variable to an
 appropriate size.

 The _amblksiz variable can be used to control the amount of memory
 space in the heap used by C for dynamic memory allocation. This
 variable is declared in the include file MALLOC.H.

 The first time your program calls one of the dynamic memory allocation
 functions (such as calloc or malloc), it asks the operating system for
 an initial amount of heap space that is typically much larger than the
 amount of memory requested by calloc or malloc. This amount is
 indicated by _amblksiz, whose default value is 8K (8192 bytes).
 Subsequent memory allocations are allotted from this 8K of memory,
 resulting in fewer calls to the operating system when many relatively
 small items are being allocated. C calls the operating system again
 only if the amount of memory used by dynamic memory allocations
 exceeds the currently allocated space.

 If the requested size in your C program is greater than _amblksiz,
 multiple blocks, each of size _amblksiz, are allocated until the
 request is satisfied. Since the amount of heap space allocated is more
 than the amount requested, subsequent allocations can cause
 fragmentation of heap space. You can control this fragmentation by
 using _amblksiz to change the default memory chunk to whatever value
 you like, as in the following example:

    _amblksiz = 2000;

 Since the heap allocator always rounds the DOS request to the nearest
 power of 2 greater than or equal to _amblksiz, the preceding statement
 causes the heap allocator to reserve memory in the heap in multiples
 of 2K (2048 bytes).

 Note that adjusting the value of _amblksiz affects both near- and
 far-heap allocation. Adjusting this value has no effect on halloc or
 _nmalloc in any memory model.


 837. The Limit of Macro Expansion

 Product Version(s): 5.00 5.10 6.00| 5.10 6.00
 Operating System:   MS-DOS        | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61314

 The limit of a preprocessor macro expansion can be no more than 6K
 when it is FULLY expanded. Similarly, actual arguments plus FULLY
 expanded actual arguments are not allowed to exceed 6K during a single
 macro expansion. Note that this is not the same as saying that the
 macro DEFINITIONS must be 6K or less.The 6K limitation was chosen
 because the buffer used for expansion is dynamically allocated and 6K
 seemed to be a reasonable limit for most real programs.

 Additionally, there is a nesting DEPTH limit of 64 on macros in
 C1.EXE, and 256 in C1L.EXE. This may be noticed only if you are
 writing macros for some relocatable indexing scheme, such as in the
 following example:

 #define INCOME 1;
 #define EXPENSE (INCOME+1)
 #define GINCOME (EXPENSE+1)
 #define TAXES (GINCOME+1)
 #define NINCOME (TAXES+1)
 ...etc...

 Version 6.00 of the Microsoft C Compiler has greater capacity than
 version 5.10. The version 5.00 compiler does not have a limit on the
 length of a macro, but the algorithm used does not support the # and
 ## operators according to ANSI standards.

 Note: If you run out of heap space during the first phase of
 compilation with code containing deeply nested macros, preprocessing
 the file before you compile it may alleviate the problem.


 838. Mixing Prototype Styles Generates C2059 Syntax Error in C 6.00

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61315

 If parameter list declarations are used with type list declarations in
 a prototype, Microsoft C version 6.00 will generate a syntax error.

 Code Example
 ------------

 void foo(int x, float);     // Error C2059: Syntax Error ')'
 void main(void)
 {
    int x=1, y=2;
    foo(x, y);
 }
 void foo(int a, int b)
 {
 }

 The following are suggested workarounds:

 1. Prototype with a parameter list. For example:

       void foo(int x, float y);

 2. Prototype with a type list. For example:

       void foo(int, float);

 Since ANSI does allow mixing declarators and abstract declarators in
 the same prototype, this error message is incorrect.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 839. C 6.00 Installation Defaults to x87 Libraries Under OS/2 2.00

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q61316

 Due to the built-in coprocessor emulation in OS/2 2.00, the Microsoft
 C version 6.00 Setup program behaves as if there is a coprocessor
 present, and defaults accordingly.

 Since C 6.00 Setup will determine that a coprocessor is installed, the
 coprocessor libraries will be installed by default. If these are not
 wanted or other libraries are to be installed, be sure to choose the
 Setup options appropriately.


 840. C 6.00 Install Program May Create Empty Directories

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q61327

 During installation, the Microsoft C version 6.00 Setup program may
 create some empty directories because the program creates the entire
 directory tree for all possible files. If, at a later date, you chose
 to copy only one file from the installation disks (Setup/Copy), the
 directory structure already will be in place. If you feel that the
 extra subdirectories are unnecessary, you may delete them.


 841. Why C 6.00 Doesn't Contain DOS Versions of C2L and C3L

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 13-JUN-1990    ArticleIdent: Q61328

 The alternate second and third passes of the Microsoft C version 6.00
 compiler have a much larger pass size (the amount of memory taken up
 in code and overhead for a pass of the compiler) than their
 small-model counterparts.

 This larger pass size negates any net memory gain under DOS that is
 made in not restricting data to DGROUP. Because of this fact, the
 alternate second and third passes of the compiler for DOS were not
 shipped with the Microsoft C version 6.00 package.

 The compiler message "Out of Near Heap Space" may be encountered in
 pass two of the CL.EXE compiler when compiling moderate to large size
 modules under DOS. The solution for this problem is to either reduce
 the number of symbols in your module, reduce the size of the module,
 or switch to the OS/2 operating system where there are alternate
 second and third pass compilers to handle this situation.


 842. C 6.00 Command-Line Options /Li and /Gi Documented Incorrectly

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-MAY-1990    ArticleIdent: Q61470

 The following command-line switches are documented incorrectly on
 Pages 6 and 7 of the "Microsoft C Reference" for the C compiler
 version 6.00, as well as in the C 6.00 online help:

 1. The /Gi switch that reads /Gi should read /Gi[mdtfile].

 2. The /Li switch that reads /Li[number] should read /Li.

 The /Gi switch takes an optional mdtfile argument, which specifies the
 name of the file to contain the incremental compilation information.
 If mdtfile is unspecified, /Gi defaults to <basename>.MDT.

 The /Li switch does not take an optional argument. In the presence of
 an argument (for example, /Li60) the compiler will generate an
 "unknown switch" warning and ignore it.


 843. Unresolved External __CImin Caused by /Gh /Os Compile Options

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q61558

 If you use the min() macro to compare two floating-point numbers and
 compile with /Gh (generate old helper function names) and /Os
 (optimize for size), the function name "__CImin" is generated by the
 compiler. Unfortunately, there is no function by this name in any of
 the C version 5.10 or 6.00 libraries.

 Code Example
 ------------

 // Compile with /Gh /Os

 #include <stdio.h>
 #include <stdlib.h>

 #define TESTVAL 5.0

 void main (int argc, char ** argv)
 {
    double dValue;

    if (argc > 1)
    {
       dValue = atof (argv[1]);
       printf ("The lesser of %f and %f is %f\n",
               dValue,
               TESTVAL,
               min (dValue, TESTVAL));
    }
    exit (0);
 }

 As a workaround, compile without /Os optimization.

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 844. Assembler Options Passed to C Compiler If /MA Contains Space

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | s_pwb
 Last Modified: 29-MAY-1990    ArticleIdent: Q61602

 Options can be passed from the C compiler to MASM in the Options.C
 Compiler.Other Options field by using the /MA switch. However, if the
 option has a space between the /MA and the actual option, the option
 will be passed to the compiler instead of the assembler. For the
 switch to be passed to the assembler, there cannot be a space in the
 option

 For example, "/MA DEBUG" does not work; "/MADEBUG" does work properly.


 845. TEXT.C Can Cause a Protection Violation Under OS/2

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61603

 If the example file TEXT.C (obtained from the C Compiler version 6.00
 online help) is compiled using the large memory model and the OS/2
 protected mode libraries, the following operating system error may
 occur:

    SYS1943: A program caused a protection violation.

 To reproduce this problem, cut the example program out of the online
 help and save it to a file named TEXT.C. Then compile with the
 following command line:

    cl /AL /Zp text.c grtextp.lib

 Upon invoking TEXT.EXE, the SYS1943 message will be displayed and the
 program will exit.

 Due to a problem with the _outtext() function, compiling this program
 in large memory model produces the protection violation.

 As a workaround, if you compile the program with the small memory
 model (/AS), the program will run properly.

 Microsoft has confirmed this to be a problem with the C Compiler
 version 6.00. We are researching this problem and will post new
 information here as it becomes available.


 846. _setvideomoderows() with _VRES2COLOR or _VRES16COLOR Modes

 Product Version(s): 5.00 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 29-MAY-1990    ArticleIdent: Q61606

 When using _VRES2COLOR or _VRES16COLOR as a parameter for the function
 _setvideomode(), it is important to note that these modes only support
 30 and 60 lines. Therefore, when a call to _setvideomoderows() is
 made, the expected value returned should be either decimal 30 or 60.

 Problems relating to 30- and 60-line support occur most commonly when
 setting the text position using the _settextposition() routine. For
 example, if you set text to the center of the screen, you will notice
 that the text seems to be printed four lines above the center.


 847. Specific Status of Process ID and CWAIT

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 29-MAY-1990    ArticleIdent: Q61609

 Question:

 I spawned a child process under OS/2 using the following code:

      pid = spawnve(P_NOWAITO,...parameter list...)
           if (pid != -1)
                status = cwait(&termstat, pid, WAIT_CHILD);

 Why does CWAIT always return status==-1 and with errno set to ECHILD
 even though the child runs successfully?

 Response:

 If not NULL, <termstat> points to a buffer that will contain a
 termination-status word and return code for the child process. The
 status word indicates whether the child terminated normally by calling
 the OS/2 DosExit function.

 When errno is set to ECHILD it is defined as follows:

    ECHILD   No child process.

             A wait was attempted by a thread that has no child
             processes, or whose child process had the no-wait option
             specified.

 In this case, the garbage value for TERMSTAT was generated by using
 P_NOWAITO rather than P_NOWAIT. In other words, the original spawn()
 call made the cwait() call fail. We document P_NOWAIT and P_NOWAITO as
 follows:

    P_NOWAIT Continues to execute parent process concurrently with child
             process.

    P_NOWAITO Continues to execute parent process and ignores wait and
              cwait calls against child process.


 848. Behavior of /Oa and /Ow Safer in C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q61610

 The detection of common aliasing practices has been improved in the
 Microsoft C version 6.00 code generator. The primary difference is
 that the compiler now tries to detect when the address of a variable
 has been taken and then to protect against aliasing corruption of that
 variable even when the /Oa option is selected. If no options are
 selected that invoke the global optimizer (/Oe, /Og, /Ol), the
 optimizer depends on the preprocessor marking all variables that have
 had their address taken (&).

 With global optimization, the optimizer itself does the necessary data
 flow analysis to determine if an address has been taken. This makes
 /Oa safer when used in conjunction with global optimization because it
 can detect addresses being taken even in the absence of the address-of
 operator (&).

 Aliasing is defined as being when more than one expression refers to a
 single memory location, as in the following example:

 int x,*p,a[3];

 void main(void)
 {
    p=&x; // Now *p and x are aliases to the same memory location.

    x=5;  // There are now two ways to assign values to that memory.
    *p=4;

    a[2]=myfunc(p);
  // Passing aliases to functions can cause problems when using /Oa.

    p=a;
  // Arrays also can be aliased; now *p and a[0] are common aliases.
 }

 Common aliasing problems can occur when the compiler causes one of
 these aliases to be stored in a register to speed up code execution.
 If both aliases subsequently are used to change the same memory
 location, one may change the register value and the other the actual
 in-memory value. Furthermore, when the register variable is finally
 unloaded, its value will overwrite whatever changes may have been made
 to memory.

 There are two places where variables stored in registers can become
 corrupted through aliasing problems. One place is across function
 calls where functions are assumed to not corrupt the value. The other
 place is by assignments through pointer variables. The following
 paragraphs and table summarize the susceptibility of different types
 of data to the above mentioned corruption:

 Local Variables
 ---------------

 Because of their restricted scope, local variables are assumed by the
 compiler to be safe from aliasing problems. Therefore, locals are
 prime candidates for register storage and if for some reason aliasing
 occurs, they are prone to common aliasing problems both over function
 calls and through pointer assignment.

 Global Variables
 ----------------

 Because of their extensive scope, global variables can often
 accumulate multiple aliases. Therefore, the code generator causes them
 to be unloaded from registers before function calls to preserve their
 value. However, globals are still prone to aliasing problems through
 pointer assignment with /Oa and/or /Ow.

 *p
 --

 *p represents a pointer variable accessed primarily to change its
 associated memory location. *p as a variable can be stored in a
 register, and therefore, can be affected by common aliasing problems.
 It is protected under default optimizations by the code generator.
 Under /Ow, it is protected across function calls but not from
 assignment through another pointer (for example, a *x). Under /Oa, *p
 is not protected as a separate symbol at all.

 Address Taken
 -------------

 If a variable's address has been taken, the C code generator will
 protect it from common aliasing pitfalls in all but one case involving
 the /Oa switch. If a local variable's address is taken and passed to a
 function, the local variable's value can then be changed within the
 function through an alias without protection from common aliasing
 problems.

 The following two further limitations apply to the above rule:

 1. If global optimization is not invoked, the code generator does not
    always recognize if an address is taken without the use of the
    address-of operator (&). This is only an issue for arrays because
    they are the only object whose address can be taken without the
    operator. What this means is that given - int *p,a[4]; p=&a[0] is
    compatible with /Oa, but p=a is not protected.

 2. The checking is done only on a procedure-by-procedure basis, so if
    the address of a global is taken outside of the current procedure,
    it won't be detected.

 The following interference table summarizes the effects of the code
 generator in the various circumstances described above:

    Var Type   Effect of Function Call   Effect of Assign Thru Pointer
    --------   -----------------------   -----------------------------

               /O    /Ow   /Oa           /O   /Ow   /Oa
    local       N     N     N             N    N     N
    global      Y     Y     Y             Y    N     N
    *p          Y     Y     N             Y    N     N
    addr-taken  Y     Y     N             Y    Y     Y

    N - Variable in register not protected from common aliasing problems.
    Y - Variable unloaded from registers to memory (protected).

 For more information see the "Microsoft C Advanced Programming
 Techniques" manual, Pages 13-15.


 849. /Lp, /Lr, and /Lc Functions Are Documented Incorrectly

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 29-MAY-1990    ArticleIdent: Q61613

 In Section 14.2.1, "The Link Mode Options /Lp, /Lr, and /Lc," on Page
 353 of the "Microsoft C Advanced Programming Techniques" manual, it
 incorrectly states the following:

    When you use the /Lx options, you instruct the compiler to override
    the default library name in the object module's library search
    record and to substitute the mode-specific combined library name.

 The correct function of the /Lx options is to simply change the
 library options that CL sends to the linker.

 For instance, if you call CL.EXE with /Lr, the following link options
 will be passed to the linker:

    /NOD:xLIBCE.LIB xLIBCER.LIB

 Note that "x" is a letter indicating the memory model. The /Lx options
 have no effect on the compiler portion of the CL program.


 850. CL.EXE Command-Line Switches Are Order Dependent

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q61616

 With the Microsoft C version 6.00 compiler, command-line switches are
 order dependent. For instance, the -Zr switch, which checks for null
 pointers and out-of-range far pointers, must appear AFTER the -qc
 switch. The option -Zr can be used only with the -qc (quick compile)
 option. Therefore, the following is the correct method:

    cl -qc -Zr

 The following is the incorrect method:

    cl -Zr -qc

 Also, if two options are for the same feature, the last option
 specified on the command-line will be used. Finally, CL environment
 variables are added to the beginning of the command line, which may
 alter the order of certain switches. The following are three examples:

 1. CL /Ox /Od foo.c

 2. CL /Od /Ox foo.c

 3. set CL=/Od
    CL /Ox foo.c

 Example 1 will disable optimizations, and Example 2 and 3 will enable
 optimizations.


 851. Changes in OS/2 Multithreaded and DLL Support in C 6.00

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  9-MAY-1990    ArticleIdent: Q61664

 Described below are several changes that have been made in Microsoft C
 version 6.00 to further support the writing of multithread (MT)
 applications and dynamic link libraries (DLLs) for OS/2:

 1. There is now only one set of include files with C 6.00 (as opposed
    to the separate standard and multithreaded include files in C
    5.10). The multithreaded versions have been merged with the
    standard includes and are differentiated internally via "ifdef"
    statements. If you define _MT in your program (#define _MT) or on
    the the compile command-line (/D_MT), then the multithreaded
    includes will be used, otherwise the standard includes are
    utilized.

 2. All of the DLL libraries are multithreaded in C 6.00. Previously, a
    DLL statically linked with the C DLL run-time library LLIBCDLL.LIB
    could only be single-threaded; multithreaded DLLs required that
    they be linked with a DLL version of the C run-time library
    (CRTLIB.DLL). In C 6.00, LLIBCDLL.LIB is multithreaded, which
    allows statically linked multithreaded DLLs to contain C run-time
    code.

 3. The C 6.00 compiler now provides three new switches, /MT, /MD, and
    /ML, to simplify the building of multithreaded programs and dynamic
    link libraries. These switches lessen the number of other
    command-line options that must be used and automatically specify
    the correct library to be used.

    The list below shows the new switches, followed by the options the
    new switches are roughly equivalent to and the default library
    names that the switches specify must be written into the object
    modules. These new switches MUST be used in order to use the
    specified libraries because the switches are NOT specifically equal
    to the expanded option lists shown.

       Switches                         Equivalent Options
       --------                         ------------------

       /MT - /ALw /FPi /G2 /D_MT        Library name - LLIBCMT.LIB
       /ML - /ALw /FPa /G2 /D_MT        Library name - LLIBCDLL.LIB
       /MD - /ALw /FPi /G2 /DDLL /D_MT  No default library name - uses
                                        DLL version of C run-time
                                        library (for example,
                                        CRTLIB.DLL).

 These switches are documented further on Pages 355-356 of "Microsoft C
 Advanced Programming Techniques" and in the online help. Note that in
 most of the C 6.00 documentation, the symbolic constant _MT is
 improperly referred to as MT (missing the leading underscore).


 852. Internal Compiler Error '@(#)regMD.c:1.100' Line 3837

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61620

 The following sample code produces an internal compiler error when
 compiled with /Oie (intrinsic AND global register allocation) options
 under large and compact memory models:

    prog.c(17) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)regMD.c:1.00', line 3837)
                 Contact Microsoft Product Support Services

 Sample Code
 -----------

 unsigned x[4];
 int *y;
 int z;

 void f1(void)
 {
 }

 // #pragma function(memcpy)  This is one workaround.
 // #pragma optimize("e", off)  This is another.
 // #pragma optimize("i", off)  This is a third.

 void f2(void)
 {
    int i;

    for(i=0;i<4;i++)
       if(i<x[1])
          memcpy(&z,&(y[i]),2);
 }
 // #pragma intrinsic(memcpy) Turn intrinsics back on.
 // #pragma optimize("e", on) Turn global register allocation back on.
 // #pragma optimize("i", on) Turn intrinsics back on.

 Placing the #pragma function(memcpy) in the code causes the compiler
 to generate a function call to memcpy rather than to make it
 intrinsic. Using the optimize pragma turns off the offending
 optimization for that section of code. Since both /Oi and /Oe are
 needed to cause the error, either pragma will work around the problem.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 853. Internal Compiler Error '@(#)newcode.c:1.87' Line 551

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q61621

 The following sample code produces an internal compiler error when
 compiled with /Oct (Default Optimization) option under large and
 compact memory models:

    prog.c(18) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)newcode.c:1.87', line 551)
                 Contact Microsoft Product Support Services

 Sample Code
 -----------

 struct AREASTR
 {
    int *getnum;
    int **ypos, **xpos, **varnum;
 };

 struct AREASTR *z;

 // #pragma optimize("ct",off) Disabling optimizations for this function
 //                            will work around problem.

 // #pragma optimize("gct",on) Adding global optimization will also work
 //                            around problem.
 sample_func()
 {
    int i,k,no;
    int count, tx, ty, tnum;

    if (k<= z->getnum[no] && z->varnum[no][k] == 1)
    {
       tnum = z->varnum[no][count];
       //compiler crashes here
       tx = z->xpos[no][count];
       ty = z->ypos[no][count];

       z->varnum[no][count] = z->varnum[no][k];
       z->xpos[no][count] = z->xpos[no][k];
       z->ypos[no][count] = z->ypos[no][k];

       z->varnum[no][k] = tnum;
       z->xpos[no][k] = tx;
       z->ypos[no][k] = ty;
    }
 }

 /* #pragma optimize("ct",on)  enable time optimizations  */

 Placing the #pragma optimize("ct",off) in the code causes the compiler
 to disable default optimizations, thus working around the problem.

 If optimizations are really needed then they may be turned back on
 with the #pragma optimize("ct",on).

 Also, instead of turning off optimizations for the function you may
 add global optimizations (/Og) to the default optimizations to work
 around the problem.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 854. Graphics Functions Available for OS/2 Protected Mode

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q61813

 The following is a compilation of the types of graphics functions
 available under OS/2 with the Microsoft C Optimizing Compiler versions
 5.10 and 6.00.

 C 5.10
 ------

 The graphics library provided with the Microsoft C version 5.10
 Optimizing Compiler does not support OS/2 protected mode. These
 graphic functions are written strictly for real mode.

 On the Update Page 25 of the "Microsoft C 5.1 Update" section of the
 "Microsoft C Optimizing Compiler: User's Guide" (Section 7.2.1), there
 is a list of functions supported in real mode only. All of the
 graphics functions also should be listed.

 C 6.00
 ------

 The graphics library provided with the Microsoft C Optimizing Compiler
 version 6.00 supports text-oriented graphics in a separate library
 file named GRTEXTP.LIB.

 A list of the available text graphics functions for OS/2 are listed in
 appendix Section B.2.12 on Page 431 of the "Microsoft C Advanced
 Programming Techniques" manual for version 6.0.

 All of the standard graphics routines listed in the manuals are
 available under DOS. The above restrictions apply only to programs
 compiled for use with OS/2 protected mode.

 Extended graphics support for OS/2 can be accomplished by using the
 OS/2 presentation manager (PM) library functions using Microsoft C
 version 5.10 or 6.00. The OS/2 PM libraries are included with the
 Presentation Manager Toolkit version 1.10 or 1.20, as well as with the
 OS/2 Software Development Kit version 2.00.


 855. DosDevIOCtl() Category 5 Subfunction 66H Fails with C 6.00 API

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q61872

 The DOS version of DosDevIOCtl() Category 5 Subfunction 66H, found in
 the API.LIB shipped with Microsoft C version 6.00, fails in native
 DOS. The failure consists of returning an invalid printer status byte,
 regardless of the printer's current status.

 The DosDevIOCtl() function is used to determine printer status.
 Although the function seems to work correctly when used from either
 OS/2 or the DOS compatibility box of OS/2, it fails when run from
 native DOS. When called, this function sets the value pointed to by
 its first parameter to a status byte whose bits have the following
 significance.

    Bit(s)  Significance (if set)
    ------  ---------------------

    0       Timed Out
    1-2     Reserved
    3       I/O error
    4       Printer selected
    5       Out of paper
    6       Acknowledge
    7       Printer not busy

 The failure of this function results in a status byte value of 2 being
 returned from the function regardless of the printer's status. This is
 particularly bad because 2 is not even a valid return value for this
 function. If the Microsoft C version 5.10 API.LIB is used, the
 function works correctly, returning a status of 144 if the printer is
 ready and 24 if the printer is off line. The only known workaround is
 to use the earlier version of the library for this function call.

 To reproduce the problem, create a bound version of the following
 program using the C 6.00 API.LIB and run it on a computer physically
 connected to a printer under native DOS:

 Sample Code
 -----------

 #define INCL_DOSDEVICES
 #define INCL_DOSFILEMGR
 #include<os2.h>
 #include<stdio.h>

 void main(void)
 {
  int handle;
  unsigned char pfstat,x=0;
  unsigned short actiontaken;
  unsigned short p;

  p=DosOpen("lpt1",&handle,&actiontaken,0l,0,0x0001,0x0041,0l);
  p=DosDevIOCtl(&pfstat,&x,0x0066,0x0005,handle);

  printf("pfstat=%d \n",(int)pfstat);

 }

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching the problem and will post new information
 here as it becomes available.


 856. Internal Compiler Error: C1001, regMD.c, Line 1017

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 13-JUN-1990    ArticleIdent: Q61918

 The code sample shown below generates the following internal compiler
 error when compiled with /Oe in either small or medium memory model:

    foo2.c(16) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)regMD.c:1.100', line 1017)
                    Contact Microsoft Product Support Services

 Sample Code
 -----------

 #include <dos.h>
 #include <malloc.h>

 typedef struct {
    unsigned    offset ;
    unsigned    usize ;
 } struct1 ;

 void foo (unsigned handle, struct1 *pdata)
 {
    unsigned char far *buffer ;
    unsigned numbytes ;

    FP_OFF (buffer) = pdata->offset = (unsigned) malloc (pdata->usize) ;

    _dos_read (handle, buffer, (unsigned) pdata->usize, &numbytes) ;
 }

 There are three workarounds possible for this specific problem:

 1. Do not compile with the /Oe switch.

 2. Use the optimize pragma to disable the /Oe optimization for this
    particular routine. Above the routine foo, add the following line:

       #pragma optimize ("e", off)

    After the closing curly bracket of foo, you can turn the optimization
    back on with the following:

       #pragma optimize ("e", on)

 3. Use a temporary variable for the return value of malloc, as
    follows:

       unsigned offset ;

       offset = (unsigned) malloc (pdata->usize) ;
       FP_OFF (buffer) = pdata->offset = offset ;

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 857. Changes to malloc() and the Rover Pointer Behavior in C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 11-JUL-1990    ArticleIdent: Q61969

 Many changes and additions have been made in C version 6.00 concerning
 the heap and heap management. The heap code is completely rewritten
 and, in addition to the new based heap capabilities and new heap
 minimization routines, the malloc() function has undergone several
 important changes. These changes include new malloc() rover pointer
 behavior in the near heap and a different malloc() allocation scheme
 in the far heap.

 The internal data layout for the heap is basically the same in C 6.00
 as it is in C 5.10, but all code and control structures are new. In
 the near heap, the malloc() rover pointer is now reset after each
 allocation, so freed memory is always allocated first if enough is
 available to meet a new request. In C 5.10, the rover pointer only
 moves forward, so freed memory is used only after the pointer wraps
 around to the beginning of the heap after it reaches the end of the
 current memory block.

 The near heap (in DGROUP) is where programs are usually limited in
 space, so it is considered a viable trade-off to change the rover
 logic to conserve space, rather than maximize speed. For the far and
 based heaps, we still do not reset the rover pointer, since resetting
 it there would take considerably more code than in the near heap,
 resulting in bigger programs and slower execution speed.

 A change concerning the far heap is that an attempt is no longer made
 to allocate space on the near heap when far memory is not available.
 In C 5.10, if the far heap does not have enough free memory to satisfy
 a memory request, then the near heap is checked to see if it could
 satisfy the request. In C 6.00, the near heap is not checked, so a
 null pointer is now returned if far memory is not available, even
 though enough near memory may be free.


 858. Internal Compiler Error: @(#)regMD.c:1.100, Line 4634

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61972

 The sample code shown below generates the following internal compiler
 error when compiled with the /Ole optimization switch in Compact and
 Large memory models:

    foo.c(22) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.100', line 4634)
                Contact Microsoft Product Support Services

 Sample Code
 -----------

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

 void main ()
 {
    char *s1,*s2;
    int  len;
    char c;
    int j;

    s1 = malloc(sizeof(char *));
    s2 = malloc(sizeof(char *));

    s1 = "this is junk1";
    s2 = "this is junk2";
    len = 10;

    for(j=0; j<len; j++){
       c = s1[j];
       s1[j]=s2[j];
       s2[j] = c;     // This line causes error
       }

    printf (" Done swapping memory ");
 }

 The following are two suggested workarounds:

 1. Use the #pragma optimize("le", off) statement at the beginning of
    the module to disable optimization and the #pragma optimize("", on)
    statement after the module to reenable optimization.

 2. Make "c" a pointer to a character. For example, instead of

       char c;

    use the following:

       char *c = " ";

    Also, change the assignment from

       c = s1[j];

    to the following:

       c[0] = s1[j];


 859. Internal Compiler Error: gencode.c, Line 437

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q61973

 The sample code shown below generates the following internal compiler
 error when compiled with the /qc compiler option, in all memory
 models:

    foo.c(10) : fatal error C1001: Internal Compiler Error
                (compiler file 'gencode.c', line 437)
                Contact Microsoft Product Support Services

 Sample Code
 -----------

 #include <stdio.h>
 #include <stddef.h>

 void main (void)
 {
    char   *p1, *p2;
    double temp;

    p1 = p2 = NULL;

    temp = 1 + (double)(p2-p1);  // This line causes the error
 }

 The following is a suggested workaround:

 Simplify the expression by assigning (p2-p1) to a temporary variable.
 For example:

    ptrdiff_t c;

    c = p2-p1;
    temp = 1 + (double)c;

 Note: The error message shown above also occurs when casting "a" to a
 float.


 860. Odd Size Structures > 10 Bytes Passed Incorrectly If Packed

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61975

 If you declare a structure of odd length greater than 10 and pass that
 structure by value, the Microsoft C version 6.00 compiler will pass a
 correct size for the structure, but will pad the size of the structure
 by an extra byte in the receiving function. The next byte on the stack
 after the structure will be overwritten with a null padding character.

 The best workaround for this problem is to manually pad the structure
 to an even size.

 The sample code shown below declares an 11-byte structure and passes
 that as well as a character to a function. Note that the character
 following the structure is overwritten with a null character.

 Remove the comment from the struct ODDSTRUCT definition to add in a
 char pad and recompile to demonstrate the workaround for the problem.

 Sample Code
 -----------

 // Compile with /Zp

 #include <stdio.h>
 #include <string.h>

 struct ODDSTRUCT
    {
    char string[11];
   // char pad ;          /* Remove comments to pad structure. */
    }   oddstruct;

 void catchastruct ( struct ODDSTRUCT , char ) ;

 void main ( void )
 {
    strcpy ( oddstruct.string, "0123456789" ) ;
    printf ("Msg = %s\n", oddstruct.string ) ;
    catchastruct ( oddstruct , '!' );
 }

 void catchastruct ( struct ODDSTRUCT oddstruct, char trashme )
 {
    printf ( "Msg = %s\ntrashme=%c(char) or %x(hex)\n",
             oddstruct.string , trashme, trashme ) ;
 }

 The following is the output of this code:

 Msg = 0123456789
 Msg = 0123456789
 trashme= (char) or 0(hex)


 861. -Gi with Certain Optimizations Creates No .MDT File

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-MAY-1990    ArticleIdent: Q61976

 The compile option -Gi (incremental compile) normally produces two
 files, a module-description table (.MDT) and an incremental link table
 (.ILK). However, with -Ol (loop optimization) and either -Os (optimize
 for space) or -Ot (optimize for speed) turned on, the -Gi option fails
 to produce the .MDT file. Note that the -Ox option behaves similarly
 because it includes -Ol and -Ot.

 This behavior is by design and is due to code generation differences,
 which the .MDT file cannot track from compilation to compilation.


 862. C1001: Internal Compiler Error: '@(#)regMD.c:1.100', Line 4634

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q62072

 The sample program show below, when compiled for compact or large
 memory model, produces the following error under default
 optimizations:

    fatal error C1001: Internal Compiler Error
        (compiler file '@(#)regMD.c:1.100', line 4634)
        Contact Microsoft Product Support Services

 Sample Program
 --------------

 #include<stdio.h>

 typedef struct window
 {
     int *fld;
     int f_cursor, l_cursor;
 } WINDOW;

 void test(int,int);

 void foo(WINDOW *w)
 {
  test(w->fld[w->f_cursor],w->fld[w->f_cursor+1]-w->fld[w->f_cursor]);
 }

 Microsoft has confirmed this to be a problem with Microsoft C version
 6.00. We are researching this problem and will post new information
 here as it becomes available.

 The following are several possible workarounds:

 1. Enable global register allocation during compilation (/Oe).

 2. Disable optimizations globally (/Od).

 3. Disable optimizations locally with #pragma("",off).

 4. Simplify the function call through the use of temporary variables.


 863. Line Continuation Evaluated Before Inline Comment in C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 13-JUN-1990    ArticleIdent: Q62097

 To maintain ANSI compliance, Microsoft C version 6.00 and QuickC
 versions 2.00 and later evaluate line continuation characters "\"
 before inline comment tokens "//". This is a change from the behavior
 of C version 5.10, which ignored continuation characters within
 inline comments.

 Section 2.1.1.2 of the ANSI Draft proposal dated December 7, 1988
 states the order in which source code translation is to take place.
 The second and third steps are paraphrased below.

    2. Each instance of a new-line character and an immediately
    preceding backslash character is deleted, splicing physical source
    lines to form logical source lines. ...

    3. The source file is decomposed into preprocessing tokens and
    sequences of white-space characters ... Each comment is replaced by
    one space character.

 As this indicates, the line concatenation should be performed before
 any and all evaluation of preprocessing tokens and comments. The
 change in interpretation can cause problems with programs that depend
 on the C 5.10 interpretation. The problem usually manifests itself in
 sections of code being ignored. This can be seen in the following
 program, which behaves differently under the different compilers.

 Code Example
 ------------

 #include<stdio.h>

 #define INT1 1          //    In-line Comment    \
 #define INT2 2    //  This line is ignored under C6.00   \

 void main(void)
 {
    printf("%d %d \n",INT1,INT2);
 }



 864. L2025: B$VWINI, B$GRPRST, Symbols Multiply Defined

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified: 21-JAN-1991    ArticleIdent: Q62178

 When building programs with C version 6.00 using graphics functions
 and the TXTONLY.OBJ file (to decrease the size of the executable
 file), in certain cases the linker will return an L2025 for two
 symbols.

 The symbols B$VWINI and B$GRPRST are multiply defined in a program
 with a call to _clearscreen. The link statement does include /NOE,
 which is necessary to successfully link with the TXTONLY.OBJ file.

 The following sample code produces the errors:

 #include <graph.h>

 void main (void)
 {
    _clearscreen (_GCLEARSCREEN) ;
 }

 The program still functions correctly (it clears the screen).

 Microsoft has confirmed this to be a problem in C version 6.00. This
 problem was corrected in C version 6.00a.


 865. NOGRAPH.OBJ Listed in Online Help Is Actually TXTONLY.OBJ

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-NOV-1990    ArticleIdent: Q62179

 In C version 6.00, an object file is sent out with the package to help
 decrease the size of executable files by about 8K to 10K. The online
 help states that the name of the object file is NOGRAPH.OBJ; in fact,
 the name of the file is TXTONLY.OBJ.

 To get any information on what this object file does, you can type "qh
 NOGRAPH.OBJ" (without the quotation marks). This will bring up
 QuickHelp with the information on this particular file.

 The help states that NOGRAPH.OBJ is used to reduce the size of an
 executable that uses only the text-mode functions from GRAPHICS.LIB.

 The actual filename is TXTONLY.OBJ.


 866. Internal Compiler Error: @(#)main.c:1.176, Line 807

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q62180

 The following code generates an internal compiler error:

 1. void main (void)
 2. {
 3.    _asm
 4.    {
 5.       fscale
 6.    foo:
 7.       fprem
 8.    }
 9. }

 Although this code is not overly useful, this is the minimum required
 to reproduce the error. The following command-line options were used:

    cl /Od /c /W4 foo.c

 The sample code produces the following output:

 Microsoft (R) C Optimizing Compiler Version 6.00
 Copyright (c) Microsoft Corp 1984-1990. All rights reserved.

 foo.c
 foo.c(9) : warning C4102: 'foo' : unreferenced label
 foo.c(6) : fatal error C1001: Internal Compiler Error
            (compiler file '@(#)main.c:1.176', line 807)
            Contact Microsoft Product Support Services

 As a workaround, the optimize pragma can be used to turn off all
 optimizations, as follows:

  1. #pragma optimize ("", off)
  2.
  3. void main (void)
  4. {
  5.    _asm
  6.    {
  7.       fscale
  8.    foo:
  9.       fprem
 10.    }
 11. }

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 867. C4058 Error with /qc Compile Option

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 17-JUL-1990    ArticleIdent: Q62182

 The C4058 warning message can be generated in error if the /qc switch
 (quick compile) is used. If the warning disappears after the /qc
 switch is removed, the warning can be ignored.

 Sample Code
 -----------

  1. #include <math.h>
  2.
  3. void main (void) ;
  4.
  5. void main (void)
  6. {
  7.    double a ;
  8.
  9.    a = cos (3.2) ;
 10.    a = sin (2.2) ;
 11.    a = atan (5.0) ;
 12. }

 Compile with the following options:

    cl /c /qc /W4 /Alfw fpburgr.c

 The following warning is given on the three assignment statements that
 reference "a":

    Warning C4058: address of automatic (local) variable taken, DS != SS

 The /Alfw switch (used in multithreaded programs, dynamic link
 libraries, and Windows programming), instructs the compiler to assume
 DS != SS with DS fixed. Typically, this warning will come about when a
 program de-references a near pointer that is automatic (local). In this
 case, the warning is invalid.

 The following are two different ways of working around the problem:

 1. Compile with /Alfu. This assumes that DS != SS, and causes DS to be
    reloaded upon function entry.

 2. Turn off the /qc compile option.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 868. C2404 Error with /qc Compile Option and fidiv Instruction

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm buglist6.00
 Last Modified: 29-MAY-1990    ArticleIdent: Q62183

 When the following program is compiled with the quick compiler option
 (/qc), with C version 6.00 or with QuickC versions 2.50 and 2.51, the
 compiler will return error C2404.

 Sample Code
 -----------

 1. void main (void)
 2. {
 3.    int foo = 3 ;
 4.
 5.    _asm fidiv   foo
 6. }

 The compiler responds with the following error:

    fpburgr.c(5) : error C2404: 'ST' : illegal register in 'operand 3'

 Currently, the only workaround is to not use the /qc option with C
 6.00. There is no known workaround for QuickC.

 Microsoft has confirmed this to be a problem with C version 6.00 and
 QuickC versions 2.50 and 2.51. We are researching this problem and
 will post new information here as it becomes available.


 869. L2025: __fltin with Mixed-Language FORTRAN 5.00 and C 6.00

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a h_fortran
 Last Modified: 19-JAN-1991    ArticleIdent: Q62184

 Question:

 Why do I get an L2025 multiply-defined symbol error when I link
 together a FORTRAN version 5.00 and a C version 6.00 program? The
 symbol is __fltin.

 Sample Code
 -----------

 C   FORTRAN MODULE
       INTERFACE TO SUBROUTINE FOO [C, ALIAS:'_foo'] (N)
       INTEGER*2 N
       END
 C   Force a read of a double
       READ(*,*)DXL
       CALL FOO (3)
       END

 // C Module

 void foo (int x)
 {
    double j = 3.0 ;
 }

 The following are the build options:

    fl /AL /c /FPi fortran.for
    cl /AL /c /FPi c.c
    link /nod /noe fortran c, foo.exe,,llibce llibfore ;

 The FORTRAN library (llibfore) was created with C compatibility, and
 llibce is a C version 6.00 library.

 The linker responds with the following message:

    llibfore.lib(\mrt\c\cfin.ASM) : error L2025: __fltin : symbol
    defined more than once

    There were 2 errors detected

 Under DOS, this does not appear to affect the executable in any way.

 Under OS/2, the resulting executable gives SYS0192 when you attempt to
 run it, telling you that there was an error during link time and the
 operating system refuses to run the program.

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 870. _fastcall Register Argument Has Incorrect Value

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fastcall
 Last Modified: 15-NOV-1990    ArticleIdent: Q62305

 In the case below, the Microsoft C 6.00 compiler will generate
 incorrect code for enregistering the arguments of a function declared
 with the _fastcall attribute.

 The following code provides an example of this behavior:

 Sample Code
 -----------

 #include <stddef.h>

 void init_windows( void );

 void _fastcall wxxopen( short   up_r,
                         short   up_c,
                         short   lo_r,
                         short   lo_c,
                         char    *title,
                         short   ctrl,
                         short   dth,
                         short   wth,
                         short   wc,
                         short   fch );

 void init_windows()
 {
     wxxopen( 00, 00, 02, 79, NULL, 10, 0, 0, 0, 32 );
     wxxopen( 04, 01, 11, 78, NULL, 10, 0, 0, 0, 32 );
     wxxopen( 22, 00, 24, 79, NULL, 10, 0, 0, 0, 32 );
 }

 The incorrectly generated code is for the third call to wxxopen().
 Rather than 0 (zero) being placed into the DX register for the second
 argument, a copy of the AX register, which contains 22, is moved into
 DX. This can be clearly seen in the following code lifted from the
 .COD file generated for the above source.

 Sample Code
 -----------

 ;|***     wxxopen( 22, 00, 24, 79, NULL, 10, 0, 0, 0, 32 );
 ; Line 22
         *** 000041      b8 4f 00        mov     ax,79
         *** 000044      50              push    ax
         *** 000045      2b c0           sub     ax,ax
         *** 000047      50              push    ax
         *** 000048      b8 0a 00        mov     ax,10
         *** 00004b      50              push    ax
         *** 00004c      2b c0           sub     ax,ax
         *** 00004e      50              push    ax
         *** 00004f      50              push    ax
         *** 000050      50              push    ax
         *** 000051      56              push    si
         *** 000052      b8 16 00        mov     ax,22
         *** 000055      8b d0           mov     dx,ax
         *** 000057      bb 18 00        mov     bx,24
         *** 00005a      e8 00 00        call    @wxxopen

 The conditions for the error to occur appear to be very narrowly
 defined. The argument being placed into DX must be a constant 0
 (zero). The compiler must be in such a state that it considers the AX
 register to contain 0 (zero) from a previous operation. This is apparently
 the state after the SUB AX, AX instruction above. Regrettably, the AX
 register has since been used to hold the first enregistered argument.

 It is difficult to convince the compiler to reach this state. The
 sequence of three calls to wxxopen() with the specified arguments has
 been found to reliably produce the error on the third call.

 Microsoft has confirmed this to be a problem with C 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 871. C1001: Internal Compiler Error: '../grammar.c', Line 140

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-JUL-1990    ArticleIdent: Q62306

 The code below, when compiled with Microsoft C 6.00 for the compact or
 large memory models, produces the following error:

    test.c(13) : fatal error C1001: Internal Compiler Error
                 (compiler file '../grammar.c', line 140)
                 Contact Microsoft Product Support Services

 Sample Code
 -----------

 #include <string.h>
 #pragma intrinsic( strcmp )         /* Intrinsic form of strcmp */

 char    *s1 = "Standard input",     /* s1 and s2 must be    */
         *s2 = "Standard output";    /* initialized to fail. */

 void main()
 {
     register int i;                 /* i must be register */

     if( strcmp( s1, s2 ) == 0 );

     for( i = 0; i < 5; ++i );
 }

 To work around this problem, one of several solutions may be used:

 1. Use the nonintrinsic form of strcpy.

 2. Do not specify i as a register variable.

 3. If appropriate, use a memory model with near data pointers.

 Microsoft has confirmed this to be a problem in C 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 872. Internal Compiler Error '@(#)p3symtab.c:1.39', Line 450

 Product Version(s): 6.00 5.10 | 6.00 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist6.00 buglist5.10
 Last Modified: 22-JUN-1990    ArticleIdent: Q62307

 The code below, when compiled with Microsoft C 6.00 with default
 options, produces the following error message:

    fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)p3symtab.c:1.39', line 450)
                       Contact Microsoft Product Support Services

 Microsoft C 5.10 produces the following error message:

    fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)p3symtab.c:1.32', line 358)
                       Contact Microsoft Technical Support

 Sample Code
 -----------

     static void _export child( void );

     void main( void )
     {
         child();
     }

     static void _export child( void )
     {
     }

 Microsoft has confirmed this to be a problem with C versions 5.10 and
 6.00. We are researching this problem and will post new information
 here as it becomes available.


 873. Internal Compiler Error '@(#)newcode.c:1.87', Line 697

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 22-JUN-1990    ArticleIdent: Q62308

 The code below, when compiled with Microsoft C 6.00 with default
 options, produces the following error message:

    test.c(1008) : fatal error C1001: Internal Compiler Error
                   (compiler file '@(#)newcode.c:1.87', line 697)
                   Contact Microsoft Product Support Services

 Sample Code
 -----------

     void foo( void )
     {
         _asm
         {
             Top:

                 nop         /* 1000 NOPs in the _asm block */
                 nop
                 nop

                 /* 997 more */

                 loop Top
         }
     }

 An out-of-range branch instruction is causing the error.

 The quick compiler, which may be invoked with the -qc switch on the CL
 command line, correctly generates this error:

    test.c(1008) : error C2427: 'Top' : jump referencing label
                                        is out of range

 Microsoft has confirmed this to be a problem with C 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 874. Internal Compiler Error '@(#)regMD.c:1.100', Line 3074

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 22-JUN-1990    ArticleIdent: Q62309

 The code below, when compiled with Microsoft C 6.00, produces the
 following error message:

    test.c(8) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.100', line 3074)
                Contact Microsoft Product Support Services

 Sample Code
 ------ ----

 void test ( long Addr1, long Addr2 )
 {
     /* This expression compiles. */
     if( ((Addr1 & 0x0FFF0000) - (Addr2 & 0x0FFFF0000)) >= 0 );

     /* Removing parens around Addr1 & 0x0FFF0000 causes ICE */
     if( (Addr1 & 0x0FFF0000 - (Addr2 & 0x0FFFF0000)) >= 0 );
 }

 The error may be worked around, as seen in the sample code, by placing
 parentheses around the subexpression involving Addr.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 875. Internal Compiler Error '@(#)newcode.c:1.87', Line 604

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 22-JUN-1990    ArticleIdent: Q62310

 The code below, when compiled by Microsoft C 6.00 with default
 optimizations for the compact or large memory models, produces the
 following error message:

    fatal error C1001: Internal Compiler Error
                (compiler file '@(#)newcode.c:1.87', line 604)
                Contact Microsoft Product Support Services

 Sample Code
 -----------

 typedef unsigned long   ULONG;

 typedef struct
 {
     ULONG   a;
 }   A;

 typedef struct
 {
     A       b;
 }   B;

 B   far *c;

 void test( void )
 {
     //  Making two separate assignments is OK
     //
     ULONG   ok_1 = (c->b.a);
     ULONG   ok_2 = (ULONG)c + ok_1;

     // But performing the same computation in one
     // assignment causes an internal compiler error.
     //
     ULONG   bomb = (ULONG)c + (c->b.a);
 }

 The error may be worked around by splitting the assignment into two
 separate operations, as seen in the sample code.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 876. Internal Compiler Error '@(#)regMD.c:1.100', Line 4634

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q62329

 The two code samples below will produce the following internal
 compiler error when the code is compiled using the compact or large
 memory model:

    fatal error C1001: Internal Compiler Error
    (compiler file '@(#)regMD.c:1.100', line 4634)
    Contact Microsoft Product Support Services

 This error can occur with various optimizations. In general, compiling
 with /Od (no optimization) or /Ox (maximum save optimization) will
 work correctly. In the following examples, there are various
 "failsafe" optimizations that can cause the error to go away. If one
 of these optimizations is used on a compile line that would otherwise
 cause the internal compiler error, the error will not appear.

  1. /** Code Sample1 **/
  2.
  3. struct str
  4. {
  5.    int *a;
  6.    int b;
  7. };
  8.
  9. void foo(struct str * w)
 10. {
 11.    dog( w->a[(*w).b], w->a[w->b+1] & w->a[w->b]);
 12. }

 In this example, using any combination that doesn't include /Oe will
 result in the above error. As soon as /Oe is included, the error
 doesn't occur. For example:

    cl /c /AL /Oacgilnprstwz  foo.c    << Fails with error.

    cl /c /AL /Oacgilnprstwze foo.c    << Works correctly, no error.
    cl /c /AL /Oanprswzx      foo.c    << Also works correctly.

 In the second working compile line, remember that /Ox includes /Oe
 (actually /Ox = /Ocegilt /Gs).

  1. /** Code Sample2 **/
  2.
  3. struct cat{
  4.    int x;
  5.    int y;
  6.    int dog[7];
  7. };
  8.
  9. void g(struct cat foo[0][1])
 10. {
 11.    int a=0;
 12.    int b=0;
 13.    unsigned int  c=0;
 14.
 15.    char buf[1];
 16.
 17.    if(0);
 18.
 19.    buf[0] = foo[a][b].x << 1 + foo[a][b].y;
 20.    buf[0] = c + foo[a][b].x;
 21. }

 In the above example, using /Oe will correct the problem. However, /Ol
 and /Og will also work correctly. Again, any combination of the other
 optimizations will result in the above error until one of the
 "failsafe" optimizations are used.

 If you want to change the code in the program, the following are some
 code sequences that seem to cause the error:

 1. Global struct

 2. Structure passed to function

 3. Complex dereference of structure member

 Usually, modifying the code to change this sequence will cause the
 error to go away. For instance, in Example 2, any of the following
 changes will eliminate the error:

 1. Change dog[7] to dog [6] and declare a dummy int to pad the
    structure.

 2. Change "c" from an unsigned int to int.

 3. Change the order of the code or use a temporary variable in the
    assignment statement.


 877. C4047 Incorrectly Generated on Void Pointer Assignment

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 22-JUN-1990    ArticleIdent: Q62422

 The code below, when compiled with Microsoft C 6.00 at warning level 1
 or higher, incorrectly produces the following error message:

    test.c(15) : warning C4047: '=' : different levels of indirection

 Sample Code
 -----------

 #include <stdlib.h>

 typedef void (*PFV)( void );    /* ptr to func returning void */
 typedef int  (*PFI)( void );    /* ptr to func returning int */

 void test( void )
 {
     PFV     *pPFV;      /* ptr to ptr to func returning void */
     PFI     *pPFI;      /* ptr to ptr to func returning int */

     /* This assignment is made correctly with no warnings. */
     pPFI = malloc( 10 * sizeof( *pPFI ) );

     /* This assignment generates a warning C4047. */
     pPFV = malloc( 10 * sizeof( *pPFV ) );
 }

 According to the ANSI C standard (Section 3.2.2.3) "A pointer to void
 may be converted to or from a pointer to any incomplete or object
 type." In this case, the assignment is to a pointer to a pointer,
 which is a pointer to an object type. So, this warning is being
 incorrectly generated for the assignment. As can be seen from the
 sample code, the same assignment does not cause an error for a pointer
 to pointer to function returning int.

 Microsoft C 5.10 compiles this code correctly, without generating any
 warning diagnostics.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 878. Information on RAMDRIVE.SYS and Error Messages

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | err msg
 Last Modified: 15-AUG-1990    ArticleIdent: Q62545

 The following information is taken from the Windows/286 and /386
 version 2.11 RAMDRIVE.TXT document:

 Using RAMDrive with Windows
 ---------------------------

 First, follow the installation instructions provided by your extended
 memory board manufacturer. Next, copy the file RAMDRIVE.SYS from the
 Utilities 2 disk to your fixed disk. Then, add the following command
 line to your CONFIG.SYS file:

    device=[drive:][path]RAMDRIVE.SYS [bbbb] [ssss] [dddd] [/E or /U]

 Note that either /E or /U may be specified, but not both. If you do
 not specify one of these two, then RAMDrive will use system memory for
 RAMDrives. It is almost always a bad idea to use conventional memory
 for a RAMDrive, as it will significantly reduce the performance of
 Windows. Running RAMDrive in extended (/E) memory, or on an AT&T 6300
 Plus (/U), is much preferred. The following is an explanation of the
 parameters:

 Note: Information in a RAMDrive is lost when you reboot or restart
 your computer.

    [bbbb]  The first numeric argument, if present, is the amount of
            memory in kilobytes to be used as your RAMDrive. If no
            numeric arguments are specified, then the default value is
            64K. The minimum amount of memory needed is 16K; the
            maximum amount of memory possible is 4096K.

    [ssss]  The second numeric argument, if present, is the sector size
            in bytes. If a second numeric argument is not specified,
            the default is 512 bytes. The four possible values are 128,
            256, 512, and 1024 bytes.

            Note: With IBM PC-DOS or Olivetti DOS the maximum value
            allowed is 512 bytes. With MS-DOS 1024 bytes is the maximum
            value.

            Values are rounded up to the nearest sector size boundary.

    [dddd]  The third numeric argument, if present, is the number of
            root directory entries. If no third numeric argument is
            specified, then the default is 64. The minimum number of
            entries needed is 2; the maximum number allowed is 1024.

            Note: If there is too little memory to create the number of
            root directory entries specified, then RAMDrive attempts to
            create a RAMDrive with fewer root directory entries.

    /E      Specifies that extended memory is to be used for the
            RAMDrive.

    /U      Specifies that some or all of the 384K of upper extended
            memory on the AT&T 6300 PLUS motherboard is to be used as
            an extra RAMDrive. You may only specify this parameter with
            an AT&T 6300 PLUS.

            Note: There is 1K of RAMDrive overhead. Only 383K is
            available for RAMDrives. This overhead is constant; it does
            not depend on the number of RAMDrives installed.

 Error Messages
 --------------

     Message:  RAMDrive: Computer must be PC-AT, or PC-AT compatible

 Explanation:  There is no extended memory available on your PC-AT or
               compatible for RAMDrives.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Remove the /E parameter. Try installing RAMDrive in
               system memory.

 ---------------------------------------------------------------------

     Message:  RAMDrive: No extended memory available

 Explanation:  Your computer has no memory available for RAMDrives.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Free some extended memory or obtain more memory.

 ---------------------------------------------------------------------

     Message:  RAMDrive: Insufficient memory

 Explanation:  Your computer has some memory available, but not enough
               to set up a RAMDrive.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Free some extended memory or obtain more memory.

 ---------------------------------------------------------------------

     Message:  RAMDrive: Invalid parameter

 Explanation:  The parameters you specified in your CONFIG.SYS entry
               for RAMDRIVE.SYS are not correct.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Check to see if you specified too many parameters if one
               of your numeric parameters is not valid, if you
               specified conflicting switches (i.e., only one of /E or
               /U may be specified), or if you specified too many
               switches. Change the RAMDRIVE.SYS command line in your
               CONFIG.SYS file to conform to the usage described above.

 ---------------------------------------------------------------------

     Message:  RAMDrive: Incorrect DOS version

 Explanation:  RAMDrive requires DOS 2.x or DOS 3.x. Windows 2.10
               requires DOS 3.00 or higher.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Upgrade to DOS 3.0 or higher.

 ---------------------------------------------------------------------

     Message:  RAMDrive: I/O error accessing drive memory

 Explanation:  During the set up of the RAMDrive, an error was detected
               in the memory being accessed for RAMDrive.

      Result:  RAMDRIVE.SYS was not installed.

    Solution:  Run the memory test for the memory on which you were
               attempting to install a RAMDrive.

 ---------------------------------------------------------------------

 Other Messages
 --------------

     Message:  Microsoft RAMDrive version Y.YY virtual disk [drive:]

 Explanation:  RAMDrive Header message. Y.YY is the version of
               RAMDrive; [drive:] is the DOS drive letter assigned to
               this RAMDrive.

               Note: On DOS 2.x the "virtual disk d:" part of this
               message will not be printed.

 ---------------------------------------------------------------------

     Message:  Disk size: x k
               Sector size: x bytes
               Allocation unit: x sectors
               Directory entries: x

 Explanation:  This message tells how many kilobytes of memory were
               assigned to the RAMDrive, how many bytes there are in a
               sector, how many sectors there are in an allocation
               unit, and how many root directory entries there are
               (including the volume label).


 879. M6101 on PG Scatter Charts with Autoscaling Off

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc buglist6.00 buglist6.00a
 Last Modified: 21-JAN-1991    ArticleIdent: Q62627

 If you turn autoscaling off in any Presentation Graphics scatter
 chart, you will receive a run-time error M6101 -- invalid math
 operation -- when the _pg_chartscatter() run-time function is called.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and buglist2.51).
 We are researching this problem and will post new information here as
 it becomes available.

 Sample Code
 -----------

 The following code is from the SCAT.C sample program, which is the
 sample program found in the online help for the _pg_chartscatter and
 _pg_chartscatterms routines. Note the added lines, which turn off
 autoscaling. Compile the program, then link with the GRAPHICS.LIB and
 PGCHART.LIB files. Running the application will duplicate the M6101
 run-time error.

 /* SCAT.C illustrates presentation graphics scatter chart functions
  * including:
  *    _pg_chartscatter   _pg_chartscatterms
  */

 #include <conio.h>
 #include <graph.h>
 #include <string.h>
 #include <stdlib.h>
 #include <pgchart.h>

 #define ITEMS  5
 #define SERIES 2
 float _far people[SERIES][ITEMS]  = { { 235.F, 423.F, 596.F, 729.F,
                                                   963.F },
                              { 285.F, 392.F, 634.F, 801.F, 895.F }
                                                                  };
 float _far profits[SERIES][ITEMS] = { { 0.9F,  2.3F,  5.4F,  8.0F,
                                                              9.3F  },
                                { 4.2F,  3.4F,  3.6F,  2.9F,  2.7F  }
                                                                    };
 char  _far *companies[SERIES] = { "Goodstuff,Inc.", "Badjunk & Co." };

 void main()
 {
         chartenv env;

         if( !_setvideomode( _MAXRESMODE ) ) /* Find a valid graphics
                                                                mode */
                 exit( 1 );
         _pg_initchart();                 /* Initialize chart system */

         /* Show single-series scatter chart. */
         _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
         strcpy( env.maintitle.title, "Goodstuff, Inc." );
         strcpy( env.xaxis.axistitle.title, "Employees" );
         strcpy( env.yaxis.axistitle.title, "Profitability" );

 /****** Note : Turn one of these two to '0' or off, or uncomment
         this section to cause problem.                          */

 /*        env.xaxis.autoscale=1;   */
 /*        env.yaxis.autoscale=0;   */

 /********************************************************************/

         _pg_chartscatter( &env, people[0], profits[0], ITEMS );
         getch();
         _clearscreen( _GCLEARSCREEN );

         /* Show multiseries scatter chart. */
         _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
         strcpy( env.xaxis.axistitle.title, "Employees" );
         strcpy( env.yaxis.axistitle.title, "Profitability" );
         _pg_chartscatterms( &env, (float _far *)people,
              (float _far *)profits, SERIES, ITEMS, ITEMS, companies );
         getch();

         _setvideomode( _DEFAULTMODE );
 }


 880. C1001: Internal Compiler Error: '../grammar.c', Line 140

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q62664

 The following sample code generates an internal compiler error
 in the file grammar.c on Line 140 when compiled with optimizations
 disabled (/Od), with global register optimization (/Oe), or with
 loop optimization (/Ol). It will occur only under compact or large
 model.

 Sample Code
 -----------

 // #pragma optimize ( "t", on )  // Uncomment this to fix ICE

 #define TOTAL_LEGS 12
 #define TOTAL_PAGES 2

 #include <memory.h>

 struct leg {
     int fix_index;
     char id[6];
     double latitude, longitude;
     } ;

 struct page {
     int index;
     double x2, x3, y2, y3 ;
     } ;

 struct leg trip_legs [ TOTAL_PAGES ] [ TOTAL_PAGES + 1 ] ;
 struct page pages [ TOTAL_PAGES ] ;

 int current_page;         // OR Initialize this to make ICE disappear

 void delete_wp1 ( int index ) ;

 void delete_wp1 ( int index )
 {
    current_page = 1;
    if ( index > 0 )
    {                      // ICE occurs on following line
       pages[current_page].x2 =
            trip_legs [current_page] [index -1].longitude;

       pages[current_page].y2 =
            trip_legs[current_page][index - 1].latitude;
    }
 }

 Compiling the above code with

    cl /c /Od /AL test.c

 returns the following error message:

    ice.c
    ice.c(38) : fatal error C1001: Internal Compiler Error
                    (compiler file '../grammar.c', line 140)
                    Contact Microsoft Product Support Services

 The following are valid workarounds for this internal compiler error:

 1. Compile with a memory model other than large or compact.

 2. Compile with default optimizations (/Ot).

 3. Uncomment the pragmas to optimize for time.

 4. Initialize the current_page variable.

 5. Compile with the /qc option to run the QuickC Compiler.


 881. Bad Code Generated for Difference Between Huge Pointers

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 13-JUN-1990    ArticleIdent: Q62912

 The following code demonstrates a case in which the C Compiler version
 6.00 generates incorrect results when calculating the difference
 between two huge pointers.

 Note that the pointer must address an array element inside of a
 structure for this problem to occur. Changing the types of the array
 elements, etc., does not solve the problem.

 Sample Code
 -----------

 #include <stdio.h>

 struct s_type {
             int ary[2]; /* Note: MUST point to array element inside
                                                      struct */
             int l;
        } s, *sptr;

 int * lptr1;
 long long2;

 void main ( void )
 {
     sptr = &s;
     printf ( " &(sptr->ary[1]) is at %p\n", &(sptr->ary[1]) ) ;

     lptr1 = & ( sptr -> ary[1] ) ;
     printf ( "lptr1 is at %p\n\n", lptr1 ) ;

     long2 =  lptr1 - &(sptr->ary[1]) ;  /* This should be 0 */
     printf ( "difference is %ld bytes\n", long2 ) ;

 }

 Compile the above program with the following:

    cl /AH /W4 /Od test.c

 When you run the program, the first two addresses should be the same
 because they are pointing to the same location. The third printf()
 should return 0 (zero) bytes. However, under a huge model, you will
 get an incorrect return value.

 One workaround is to use the quick compiler (/qc option), as follows:

    cl /qc /AH /W4 /Od test.c

 This will generate the correct code.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 882. Using C Compiler /Gs Switch in PM Environment

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER | SR# G900501-110 P_PRESMAN O_OS2SDK
 Last Modified: 15-AUG-1990    ArticleIdent: Q62926

 The following information describes stack checking and the use of the
 Microsoft C Compiler /Gs switch.

 To address stack checking and the /Gs compile switch, we must first
 build a model that describes why and where stack checking occurs.

 This article assumes a basic knowledge of OS/2 multitasking,
 processes, and threads. Processes are essentially a unit of ownership
 under OS/2. As the loader reads a program (an .EXE file) into memory,
 it builds an LDT (Local Descriptor Table) with entries that point to
 all the memory allocated for the process. At a minimum, a process will
 have two memory segments, a code segment and a data segment. The data
 segment has three major areas including a heap, a stack, and static
 areas, respectively:

    Physical Memory Areas   Virtual Memory

      Data Segment              LDT
    +-----------------+     +---------+
    |   heap area     |   -<|         | <=-  DS: SS:
    +-----------------+  |  +---------+
    |  stack area     |  |  |         |
    +-----------------+  |  +---------+
    | static area     |  |  |         |
    +-----------------+<-   +---------+
                            |         |
                            +---------|
                          -<|         | <=-  CS:
                         |  +---------+
        Code Segment     |  |         |
    +-----------------+  |  +---------+
    |                 |  |  |         |
    +-----------------+<-   +---------+

 On the other hand, "execution" requires a processor, state
 information, status, priority, and a stack area for arguments,
 parameters, and addresses. The stack area produced by the loader is
 used by thread 1 of the process.

 Depending on the application's dependency on C library routines, the
 programmer may choose to either use DosCreateThread() or _beginthread
 to create threads. The API calls used to create and terminate threads
 are DosCreateThread() and DosExit(EXIT_THREAD, 0), whereas the C
 run-time calls are _beginthead and _endthread.

 Under OS/2 version 1.20 and the C Compiler version 5.10, we present
 three alternative areas that may be used as stack areas for threads
 (allocated segments, heap, and static). The stack parameter in either
 call should point to the stack area to be used by the new thread. This
 new stack area can be allocated by doing the following:

    Method 1: You can use the DosAllocSeg() function to create a new
              segment in memory, and a new LDT entry, and allows the 286
              to monitor faults when the thread exceeds the stack area.

    Method 2: You can use the malloc(...) C function to extend the
              processes heap area, which results in the creation of an
              allocation area that the new thread will use as it's stack
              area. This new area is within the same memory segment as
              the area used by thread 1.

    Method 3: You can use a global array. A variable declaration such as
              static CHAR area[4096]; creates a 4K area in the static
              area of the process's data segment that may be used by the
              new thread for it's execution. This area is also within the
              same memory segment as the area used by thread 1.

 It is important to understand where these allocations are placed in
 memory before considering stack checking (/Gs). Looking at each
 method, they appear to the process as described below:

      **Method 1                LDT
    +-----------------+
    | New Seg from    |
    | DosAllocSeg()   |
    +-----------------+<-
                         |  +---------+
      Data Segment        -<|         | New LDT Entry (Method 1)
    +-----------------+     +---------+
    |   heap area     |   -<|         | <=-  DS: SS:
    | **Method 2      |  |  +---------+
    +-----------------+  |  |         |
    |  stack area     |  |  +---------+
    +-----------------+  |  |         |
    | static area     |  |  +---------+
    | **Method 3      |  |  |         |
    +-----------------+<-   +---------+
                          -<|         | <=-  CS:
                         |  +---------+
        Code Segment     |  |         |
    +-----------------+  |  +---------+
    |                 |  |  |         |
    +-----------------+<-   +---------+

 The address (pointer to the new area) is specified by the pbThrdStack
 parameter in either the DosCreateThread() or _beginthread call. See
 the documentation on these functions for details as to where the
 pointer should actually point within the allocation and remember that
 stacks grow down in memory towards lower addresses.

 Finally, we address stack checking and the /Gs switch used in the C
 Compiler. Stack checking is a protective mechanism built into ALL
 computer languages to ensure that during a thread's execution, as
 values are added and removed from the stack area (using PUSH and POP
 instructions respectively), the thread does not accidentally exceed the
 stack area and destroy other data.

 In the C Compiler version 5.10 and other languages, the default stack
 checking algorithm has historically only needed to watch one area and
 one execution element. Consequently, the stack checking problem
 arises. The basic assumption is that attempts to add and remove data
 from the stack area using PUSH and POP instructions will only occur in
 the stack area setup for thread 1 in the process's data segment.

 Under OS/2, there will typically be multiple threads and multiple
 stack areas, and the basic assumption for the stack is no longer
 valid. Also, SS != DS in most DLLs (Dynamic Linked Libraries) since
 the data segment is changed as the DLL is entered. Once the initial
 assumption is broken, the C Compiler stack checking will start
 reporting false stack overflow errors.

 Consequently, you should use the /Gs switch to turn off stack
 checking. Without stack checking, the C Compiler will not include the
 algorithm depicted above. The code generated in the compile step will
 be smaller and faster. It is up to the programmer to ensure that the
 stack area for the new thread is large enough to accommodate all the
 PUSH and POP operations.

 As an additional note, even in the single-threaded case where stack
 checking can work, the output will be lost in a Presentation Manager
 (PM) application since standard output is redirected to null. It can be
 recovered by redirecting output with ">" or "|" on the command line.

 And finally, ALL the above problems do not occur when using the C
 Compiler version 6.00 and OS/2 version 2.00 because the programmer
 does NOT have to allocate stack areas. OS/2 version 2.00 will do it
 automatically and if a process or thread ever exceeds the stack area,
 OS/2 version 2.00 will expand it on the fly.


 883. Operands Reversed in C 6.00 Divide Operation

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q63053

 Under certain situations, the Microsoft C version 6.00 compiler can
 generate code that causes the denominator in a division operation to
 be divided by the numerator instead of the other way around.

 The following code, compiled under default optimizations with
 Microsoft C version 6.00, demonstrates the problem and causes the
 following error:

    run-time error M6103: Math
    - floating-point error: divide by 0

 The problem apparently occur only when the denominator contains both a
 double value and a function parameter, and the numerator is a global
 float. Also, the next statement apparently must contain an expression
 utilizing the result of the operation. This prerequisites to the
 problem seem to indicate that the problem is directly tied to
 optimizations removing common subexpressions.

 In the example below, the denominator in the first assignment
 statement in set_adc() is divided by the numerator. Therefore, instead
 of receiving 26.0/2.56 cast to an int, i gets a value of 0, or
 2.56/26.0 cast to an int.

 The following are several possible workarounds to the problem:

 1. Disable optimizations.

 2. Declare the numerator locally or as a double instead of a float.

 3. Use a global float variable in the denominator instead of parameter.

 4. Don't use a double value in the denominator.

 5. Cast the denominator as a float before division.

 6. Break up assignment statements with a function call.

 7. Use the /qc compiler option.

 Code Example
 ------------

 float f1;
 float f2=26.0f;   // Works if f2 is declared locally or as double.

 void set_adc(float width)
 {
 // Works if width declared as local variable instead of parameter.
    int i;
    i=(int)(f2/(2.56*width));
       // Works if used with float constant 2.56f.
       // Works if denominator cast as float.
       // Works if broken up with function call
       //      such as printf("hello");.
    f1=f2/i;
 }

 void main(void)
 {
    set_adc(1.0f);
 }

 The section of mixed source and assembly below shows the assembly
 instructions generated by default optimizations. The troublesome
 instruction [FDIVP  ST(1),ST] is at offset 0023.

 Following the logic below, width is pushed onto the coprocessor
 stack, ST. Then it is multiplied by 2.56. Then _f2 is pushed onto the
 coprocessor stack, ST making the above result ST(1). Finally, the
 FDIVP instruction takes ST(1), the denominator, and divides it by ST,
 _f2 - the numerator.

 The rest is to be expected, __ftol is called to convert the float to
 an integer. The result, 0, is moved from the AX register into the
 local variable i. Then i is pushed onto the coprocessor stack, ST,
 and then the FDIVR instruction divides _f2 by this value causing the
 divide by 0 error.

 8:          i=(int)(f2/(2.56*width));
 9:          f1=f2/i;
 0047:0014 9B             WAIT
 0047:0015 D94604         FLD       DWord Ptr [width]
 0047:0018 9B             WAIT
 0047:0019 DC0EB802       FMUL      QWord Ptr [__fpinit+e (02B8)]
 0047:001D 9B             WAIT
 0047:001E D9064200       FLD       DWord Ptr [_f2 (0042)]
 0047:0022 9B             WAIT
 0047:0023 DEF9           FDIVP     ST(1),ST                  ; wrong
 0047:0025 E8001B         CALL      __ftol (1B28)
 0047:0028 8946FE         MOV       Word Ptr [i],AX
 0047:002B 9B             WAIT
 0047:002C DF46FE         FILD      Word Ptr [i]
 0047:002F 9B             WAIT
 0047:0030 D83E4200       FDIVR     DWord Ptr [_f2 (0042)]
 0047:0034 9B             WAIT
 0047:0035 D91ED004       FSTP      DWord Ptr [_f1 (04D0)]
 0047:0039 90             NOP
 0047:003A 9B             WAIT

 The following code generated with disabled optimizations shows the
 correct method of doing this. Width is pushed onto the coprocessor
 stack, ST. Width is then multiplied by 2.56 with the result stored in
 ST. The FDIVR instruction then divides _f2 by the above value, and
 after conversion, i equals 10 as it is supposed to.

 8:          i=(int)(f2/(2.56*width));
 0047:0016 9B             WAIT
 0047:0017 D94604         FLD       DWord Ptr [width]
 0047:001A 9B             WAIT
 0047:001B DC0EB802       FMUL      QWord Ptr [__fpinit+e (02B8)]
 0047:001F 9B             WAIT
 0047:0020 D83E4200       FDIVR     DWord Ptr [_f2 (0042)]   ; right
 0047:0024 E8091B         CALL      __ftol (1B30)
 0047:0027 8946FE         MOV       Word Ptr [i],AX
 9:          f1=f2/i;
 0047:002A 9B             WAIT
 0047:002B D9064200       FLD       DWord Ptr [_f2 (0042)]
 0047:002F 9B             WAIT
 0047:0030 DE76FE         FIDIV     Word Ptr [i]
 0047:0033 9B             WAIT
 0047:0034 D91ED004       FSTP      DWord Ptr [_f1 (04D0)]
 0047:0038 90             NOP
 0047:0039 9B             WAIT


 884. C1001: Internal Compiler Error: '../grammar.c', Line 140

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q62701

 The sample program shown below, when compiled for compact or large
 memory model, will produce the following error under default
 optimizations:

    foo.c(14) : fatal error C1001: Internal Compiler Error
                (compiler file '../grammar.c', line 140)
                Contact Microsoft Product Support Services

 Sample Program
 --------------

 #include <malloc.h>

 int a[2];

 void test(void)
 {
    int b;
    char *c;

    c=(char *)malloc(100);

    b=*(int*)(c+a[0])+*(int *)(c+a[1]);
 }

 The following are several possible workarounds:

 1. Enable global register allocation during compilation. (/Oe)

 2. Disable optimizations globally. (/Od)

 3. Disable optimizations locally with #pragma. ("",off)

 4. Simplify the expression through the use of temporary variables.

 Microsoft has confirmed this to be a problem with Microsoft C version
 6.00. We will post new information here here as it becomes available.


 885. Use of K&R Style Function Definitions May Generate Bad Code

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q62703

 The following code should print out "ABCDEF". However, if compiled
 with default optimizations it prints out "ACEGIK" in small model and
 "  TLr" in large model. This is corrected by turning off optimizations or
 converting the program to the ANSI style.

 Sample Code
 -----------

 #define NULL ((char *) 0)

 int var;
 int *my_prog_var_table[] = {&var,&var,&var,&var,&var,&var,NULL};
 char my_prog_suffix_table[] = "ABCDEFGHIJKLMNOP";

 main()
 {
    printf("Program should print \"ABCDEF\"\n");
    my_prog_init_files(my_prog_var_table,my_prog_suffix_table);
    printf("\n");
 }

 // #pragma optimize("tc",off) //Will Fix

 my_prog_init_files(vars, suffix)
 int *vars[];
 char suffix[];
 {
    int i;
    for (i = 0; vars[i]; i++)
    {
    my_prog_init_file(vars[i], suffix[i])
    }
 }

 // #pragma optimize("tc",on) //Will Fix

 my_prog_init_file(var, suffix)
 int *var;
 char suffix;
 {
    printf("%c", suffix);
 }


 886. Case Lost in Complex Switch Statement in C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q63054

 Under certain circumstances, a case may be lost in a complex switch
 statement under default optimizations with Microsoft C version 6.00.

 The following code demonstrates the problem by losing track of case
 30. To work around the problem, disable optimizations or add /Os via
 the command-line switches or through the use of the optimize pragma.

 Sample Code
 -----------

 #include <stdio.h>

 int cm_lockup( void ) ;

 int main( void )
 {
    int j;

    switch( 30 )
    {
       case 7:
       case 43:
           j = 1;

       case 8:
           ++j;

       case 35:
           ++j;

       case 137:
           break;

       case 33:
       case 39:
           j = 3;
           break;

       case 30:           // this case is missed
           j = 4;
           break;

       case 12:
           j = 5;
           break;

       case 11:
       case 32:
           j = 6;
           break;

       case 10:
           j = 7;
           break;

       case 2:
           j = 8;
           break;

       case 37:
           j = 9;
           break;

       case 6:
           j = 10;
           break;

       case 13:
           break;

       case 44:
           j = 11;
           break;

       case 41:
           j = 12;
           break;

       case 42:
           j = 13;
           break;

       default:
           cm_lockup();
           break;
    }
    return j;
 }

 int cm_lockup( )
 {
    printf( "bad" );
    return 1;
 }

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 887. qsort() Compare Routine Must Have Equal Case Under C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 25-JUL-1990    ArticleIdent: Q63055

 When writing a compare routine for use with the qsort() function
 provided in Microsoft C version 6.00, provision must be made to return
 0 (zero) if the two elements passed to the routine are identical. This
 is necessary even if it is that all elements of the array passed to
 qsort are different.

 The documentation on qsort() given in the online help specifies that
 the compare routine should return 0 in the case of equality. However,
 under earlier versions of Microsoft C, a routine will work without
 this equality clause provided no two elements of the array are equal.

 Under Microsoft C version 6.00, the qsort() function will actually
 pass the same address as both parameters to the compare routine during
 the execution of its sorting algorithm. If 0 (zero) is not returned in
 this case, it will cause qsort() to try and rearrange the two array
 elements that were passed. Since both elements were the same address,
 qsort() breaks down at this point causing spurious and often
 disastrous consequences. The following code, which compiles and runs
 correctly under Microsoft C version 5.10, demonstrates the
 differences.

 Sample Code
 -----------

 #include<stdio.h>
 #include<stdlib.h>
 #include<search.h>

 int arname[10]={ 10,9,8,7,6,5,4,3,2,1 };

 void main(void)
 {
     qsort(arname,10,sizeof(int),cmpr);
     printf("%d - %d",arname[0],arname[9]);
 }

 int cmpr(int *p,int *q)
 {
     if (*p<*q) return(-1);
     else return(1);
 }


 888. Fatal Error C1043 When Compiling with C1L.EXE

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q63056

 The following compiler command line under Microsoft C version 6.00
 will cause a fatal error C1043:

    cl /B1 C1L /Zi /Fs hello.c

 The following error message is produced when any program is compiled
 under DOS with the above command line with no further explanation of
 the error message:

    hello.c
    fatal error C1043:

 Removal of any of the above command-line switches will eliminate the
 error message, which does not occur under OS/2.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 889. Function Prototype with Undefined Structure Causes Error

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q63058

 A function prototype, which is defined using an undeclared structure
 in C version 6.00, will give the following error message:

    error C2079: 'Formal' uses undefined struct/union '<union name>'

 In C 5.10, the same program (assuming the structure is defined
 sometime before the function itself is defined) will compile without
 any errors or warnings.

 Sample Code
 -----------

 #include "stdio.h"

 // prototype

 void ItFunc(struct s);

 // the struct itself

 struct s
 {
    int x;
    int y;
 };

 void ItFunc(xstruct)
 struct s xstruct;
 {
   printf("in the function\n");
 }

 For this code to compile correctly in C 6.00, the structure definition
 should appear before the function prototype.

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


 890. Internal Compiler Error: '@(#)newcode.c:1.87', Line 604

 Product Version(s): 6.00   |  6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q63060

 The code example shown below generates the following error message:

    fatal error C1001: Internal Compiler Error
          (compiler file '@(#)newcode.c:1.87', line 604)
          Contact Microsoft Product Support Services

 Code Example
 ------------

 #define OFFSET 2
 #define NEXTFP(nextfp,fp) \
      nextfp = (long) fp & 0xffff0000;\
      nextfp = nextfp + * fp + *(fp+1) * 0x100;

 static unsigned char * stk_bottom;
 static long first_fp;

 void main (void)
 {}

 void chkstkinit()
 {
    unsigned char stk_top;
    static long nextfp;
    static unsigned char *fp;

    stk_top = 0xaa;
    fp = &stk_top + OFFSET;
    NEXTFP(nextfp, fp);
    stk_bottom = (unsigned char *)nextfp;   // The error occurs here
    first_fp = *stk_bottom + *(stk_bottom +1) * 0x100;

    return;
 }

 This error was only observed in the large (/AL) or huge (/AH) memory
 model. Compiling using the /Od option or the #pragma optimize("",off)
 statement eliminates the error.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 891. C 6.00 STARTUP.DOC Requests Wrong MASM Version

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-JUL-1990    ArticleIdent: Q63321

 The Microsoft C version 6.00 STARTUP.DOC, under the "C Runtime Library
 Startup Sources" section, states that in order to build the start-up
 object files, MASM version 5.00 or later is required. However, when
 using MASM 5.00, the following error

    A2009: symbol not defined: @F

 is produced. To work around this problem, two lines in CRT0DAT.ASM
 must be changed. Lines 701 and 703, which involve a jump to @F, should
 be changed as demonstrated below.

 Code Example
 ------------

 Line 701:      jne    @F           (jump forward to @F)
 should read    jne    FOO          (where foo is any symbol
                                     other than @F)

 Line 703:      @@:
 should read    FOO:

 This problem does not occur when MASM version 5.10 or later is used.


 892. C 5.00/5.10 and 6.00 Regard Right Arrow Character (1Ah) as EOF

 Product Version(s): 5.00 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q63322

 In Microsoft C versions 5.10 and 6.00, the right arrow character (1Ah)
 is read as an end-of-file (EOF) character, even if it occurs nested
 within a character string.

 The unexpected EOF can be avoided by inserting an escape sequence
 within the string to replace the right arrow character. Use the
 following

    printf("Hello""\x1a""world.");

 instead of:

    printf("Hello(right arrow character)world");

 Using the proper format forces the compiler to recognize the hex 1A as
 an escape sequence, instead of an EOF. If the escape sequence is not
 separated from the rest of the string, it may be read as a different
 hex value, since characters will appear directly after it. In addition
 to hex values, an octal value may be used.


 893. Forward Slashes Appear in Paths of Some Error Messages

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 15-AUG-1990    ArticleIdent: Q63550

 Some errors generated by the Microsoft C Optimizing Compiler version
 6.00, as well as the QuickC Compiler versions 2.50 and 2.51, are
 displayed with forward slashes in the place of backward slashes in the
 error messages.

 The following is an example of this type of error message:

    e:/c600/include\malloc.h(79): error C2086: '_bcalloc':
        redefinition

 Note the forward slashes in "/c600/" and the backward slash in
 "\malloc.h".

 The forward slashes in these error messages are normal and do not
 cause any problems with the compiler. This behavior is intended.


 894. R6000 -- Stack Overflow at Compile Time with C Compiler

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  9-NOV-1990    ArticleIdent: Q66429

 The code sample below produces the following run-time error on
 compilation under the small and medium memory models with only the
 following individual optimizations:

    /Oa /Oc /Oi /On /Op /Or /Os /Ot /Ow /Oz

 Run-Time Error
 --------------

    run-time error R6000
    - stack overflow

 If only the above optimizations, including the defaults, are used to
 compile the program, the run-time error will occur. However, if one of
 the following optimizations is added, the run-time error will not
 occur:

    /Od /Oe /Og /Ol /Ox

 In addition, the following are two additional workarounds that can be
 applied to the code itself:

 1. Do not use the register storage class for the structure pointer.

 2. Use an if-else statement instead of the ternary operator.

 Sample Code
 -----------

 void main(void)
 {
         struct foo {
                    int i;
                    };
         int n;

         struct foo *goo;
         register struct foo *moo;

         moo=goo;
         n = moo->i ? moo->i :10000;
 }

 Microsoft has confirmed this to be a problem in the C compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.


 895. Resolving C Compiler LINKer Response File Error

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | O_OS2SDK
 Last Modified: 15-AUG-1990    ArticleIdent: Q63634

 Question:

 After reinstalling OS/2 on my machine, I now receive the following
 error whenever I try to compile and link any of my Microsoft C Compiler
 version 6.00 programs:

    error:  unable to open response file ""

 Response:

 OS/2 contains an earlier version of LINK.EXE, and this version of
 LINK.EXE may actually be executing instead of the version of the
 LINKer provided with Microsoft C Compiler version 6.00.

 One solution to this problem may be to modify your path so that the
 "C600\binb" subdirectory containing LINK.EXE comes before your OS/2
 subdirectory.

 Another solution is to rename the LINK.EXE program in the OS/2
 subdirectory to something similar to LINK.EX@. Either of these actions
 will ensure that the proper version of LINK.EXE is executed.


 896. Error D2030 May Hide Other Errors

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q63660

 When compiling the example code shown below with C6.00 under OS/2
 version 1.20, the compiler issues the following error messages at the
 command line:

    x.c(2) : error C2065: 'UNDEFINED_CONST' : undefined
    x.c(2) : error C2057: expected constant expression
    Command line error D2030 : INTERNAL COMPILER ERROR in 'P1'
                    Contact Microsoft Product Support

 Programmer's WorkBench (PWB) only issues the following message:

    Command line error D2030 : INTERNAL COMPILER ERROR in 'P1'
                    Contact Microsoft Product Support

 This is also the only error message issued if you compile from the
 command line and redirect the output.

 Turning off or on any optimizations makes no difference. Defining the
 the undefined constant causes the error to disappear.

 This error is indicating that the first pass of the compiler ("P1") is
 getting a GP fault. Since the pass is GP faulting, the error message
 output doesn't get flushed from the buffer and the extra error
 messages are lost.

 In general, if you receive a D2030 error, other error messages may
 have been lost. Ways to find the problem include using different
 optimizations and memory models, using the "-qc" option, and breaking
 your code into smaller pieces until you find the problem code.

 Code Example
 ------------

 typedef int FOO ;
 void funcA( int array[ UNDEFINED_CONST ] ) ;
 void funcB( void ) ;


 897. C1001: Internal Compiler Error: '../grammar.c', Line 140

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1990    ArticleIdent: Q64021

 The code below, when compiled with Microsoft C 6.00, produces the
 following error message:

    fatal error C1001: Internal Compiler Error
     (compiler file '../grammar.c', line 140)
     Contact Microsoft Product Support Services

 Sample Code
 -----------

 struct x
 {
    int a;
    int *b;
    double **c;
 };

 typedef struct x TEST;

 void function (TEST *pTEST)
 {
    double xx = 0;
    int i,j;

    for (i=0;i<pTEST->a;i++)

       for(j=0;j<pTEST->b[i];j++)

          if (pTEST->c[i][j]>xx)        // Fails here...

             pTEST->b[i]=j;
 }

 Compiling this code with one of the following options will produce
 the internal compiler error mentioned above:

    /Ot /Oi /Oit

 The following are some possible solutions:

 1. Use /Oe, /Ol, /Ox, /Oet, or /Olt when compiling.

 2. Put the typedef and struct x definitions together.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 898. MS-DOS 3.20 Patch Is Missing from C Version 6.00

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 25-JUL-1990    ArticleIdent: Q64029

 The file PATCH320.DOC, which is supplied with the Microsoft C Compiler
 version 6.00, outlines the steps required to patch IBM-DOS version
 3.20 and incorrectly states that there is information about how to
 patch MS-DOS version 3.20 in the README.DOC.

 However, the README.DOC file does not contain information about a
 MS-DOS patch, and the patch files are not included on the C 6.00
 distribution disks.

 The MS-DOS version 3.20 patches are available with the Microsoft C
 Compiler version 5.10, on the Compiler Disk 1, as well as with the
 Microsoft QuickC Compiler version 2.50, on the Setup Disk. The patch
 file is PATCH87.EXE, and the instructions are contained in
 PATCH87.DOC.

 If you have MS-DOS version 3.20 and do not have a copy of the patch
 files, please call Microsoft Product Support Services and a technician
 will send a copy of the files.

 The IBM-DOS version 3.20 patch files are included with the Microsoft C
 Compiler version 6.00.
 `


 899. Internal Compiler Error: '@(#)newcode.c:1.87', Line 604

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q64030

 If sample code below is compiled in large or compact memory model with
 any optimizations except /Od, /Oa, or /Ow, the compiler will fail with
 the following error message:

    fatal error C1001: Internal Compiler Error
     (compiler file '@(#)newcode.c:1.87', line 604)
     Contact Microsoft Product Support Services

 If the code is compiled with /Oa or /Ow, the following error message
 will be generated:

    fatal error C1001: Internal Compiler Error
     (compiler file '@(#)regMD.c:1.100', line 1017)
     Contact Microsoft Product Support Services

 Sample Code
 -----------

 #include <ctype.h>
 #define OFFSET 2
 #define NEXTFP(nextfp,fp) \
         nextfp = (long) fp & 0xffff0000;\
         nextfp = nextfp + * fp + *(fp+1) * 0x100;

 static unsigned char * stk_bottom;
 static long first_fp;

 void main (void) {}

 void chkstkinit()
 {
    unsigned char stk_top;
    static long nextfp;
    static unsigned char *fp;

    stk_top = 0xaa;
    fp = &stk_top + OFFSET;
    NEXTFP(nextfp, fp);
    stk_bottom = (unsigned char *)nextfp;   // Error on This line
    first_fp = *stk_bottom + *(stk_bottom +1) * 0x100;

    return;
 }

 Since these errors occur if any optimization is turned on, compiling
 with the /Od optimization switch or using the new optimize pragma to
 turn off all optimizations is the easiest solution.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 900. NMAKE Predefined Macro $(@D) Has Same Value As $@

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 31-AUG-1990    ArticleIdent: Q64032

 On Page 114 of the "Microsoft C Advanced Programming Techniques"
 version 6.0 manual, it states that an example value of $@ is
 "C:\SOURCE\PROG\SORT.OBJ". The macro $(@D) is listed as having a
 sample value of "C:\SOURCE\PROG". In reality, both macros give the
 value of the full path, filename, and extension, or
 "C:\SOURCE\PROG\SORT.OBJ".

 This problem can be reproduced by creating a simple test MAKE file.
 The following is an example:

 Foo :  c:\autoexec.bat
    echo $(@D)

 Running NMAKE with this file gives the following result:

    echo c:\config.sys
 c:\config.sys


 901. D2030 Caused by Undefined Identifier in Parameter List

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64033

 Using an undefined symbol in a function or function prototype's
 parameter list can cause the internal compiler error D2030 in
 Microsoft C version 6.00 under OS/2.

 The code below produces the following errors under default
 optimizations with Microsoft C version 6.00 under OS/2.

    error C2065: 'maxfields' : undefined
    error C2057: expected constant expression

    Command line error D2030 : INTERNAL COMPILER ERROR in 'P1'
                    Contact Microsoft Product Support Services

 If output is redirected to a file or a pseudofile, such as the compile
 window in the Programmer's WorkBench (PWB), only the internal compiler error
 will be displayed.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.

 Sample Code
 -----------

 void foo (char retstring[maxfields]);

 void main(void){}


 902. /Zp Default Values with and without Specifying the Switch

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 31-AUG-1990    ArticleIdent: Q64163

 When specifying the /Zp switch with either version 5.10 or 6.00 of the
 Microsoft C Optimizing Compiler, it should be observed that the
 default functionality when using the /Zp switch without a numeric
 argument is equivalent to /Zp1 (that is, structure members will be
 packed on one-byte boundaries).

 Additionally, if the /Zp switch is not specified, the structure
 members will be packed on two-byte boundaries (that is, the equivalent
 of using /Zp2).


 903. Use Supplied Batch Files to Recompile Start-Up Code

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S900710-95
 Last Modified: 16-AUG-1990    ArticleIdent: Q64874

 If you recompile _file.c to increase your file streams, you will
 encounter the following warning:

    L4051 llibce.lib : cannot find library

 If you specify /AL and /FPi87 on your compile line and build
 LLIBC7.LIB, the warning will still occur.

 This error occurs because, when you recompile _file.c, you must use
 the /Zl option. This option removes the default library search records
 from the object file. If this option is not used, the default library
 will be searched for, rather than the library you specify.

 The best way to modify the start-up code is to use the provided
 STARTUP.BAT or STARTUP.CMD files. Documentation for the use of these
 files may be found in STARTUP.DOC.


 904. L1089 Caused by Wrong Linker in OS/2

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | S_LINK
 Last Modified: 31-JUL-1990    ArticleIdent: Q64180

 Linker fatal error L1089, "Cannot open response file," can be caused
 by trying to use the OS/2 system linker with Microsoft C version 6.00.

 This problem can be demonstrated by placing the directory with the
 OS/2 linker in your path before your \C600\BINB directory and then
 attempting to compile and link with the cl compiler, for example:

    cl foo.c

 The simplest workaround is to place the \C600 directories before the
 OS/2 directories in your path.


 905. _getlogcoord() Now _getviewcoord() in Microsoft C 6.00

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 31-JUL-1990    ArticleIdent: Q64181

 The _getlogcoord() function from Microsoft C version 5.10's graphics
 library was replaced by the _getviewcoord() function in version 6.00.

 The _getviewcoord() family of functions adds additional functionality
 to the original routine supporting window coordinate translation, in
 addition to the standard logical coordinate translation. This is one
 reason the name was changed between versions.


 906. The C 6.00 Graphics Library Supports Only One Video Page

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 30-AUG-1990    ArticleIdent: Q64434

 Currently, there is only one video page allowed in VGA modes with the
 Microsoft C graphics functions. This is by program design and may
 change to allow for more video pages in a future version of the
 compiler.


 907. mktime() Function Does Not Flag Invalid Dates Before 1970

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc buglist6.00 buglist2.50 buglist2.51
 Last Modified: 31-AUG-1990    ArticleIdent: Q64436

 The mktime() function is documented as returning a -1 if the date in
 the tm structure was before 1980. Actually, a -1 is returned if the
 date is between 1970 and 1980. If the date is earlier than 1970, an
 invalid date is returned.

 Sample Code
 -----------

 /* The following code reproduces this behavior. */

 #include <time.h>
 #include <stdio.h>
 #include <sys\types.h>
 #include <sys\timeb.h>
 #include <string.h>

 void main()
 {
    int c;
    struct tm vartime = {0, 0, 6, 16, 7, 0, 0, 0, 1};

    for (c = 81; c > 65; c--)
    {
       vartime.tm_year = c;
       printf("Year = %d.\n", c);
       if (mktime(&vartime) != (time_t) (-1))
          printf("Time entered is: %s\n\n", asctime(&vartime));
    }
 }

 Microsoft has confirmed this to be a problem in C version 6.00 and in
 QuickC versions 2.50 and 2.51. We are researching this problem and
 will post new information here as it becomes available.


 908. A.P.T. Omits /NOI Requirement for Linking with C Run-Time DLL

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 19-JAN-1991    ArticleIdent: Q64437

 On Page 412 of the "Advanced Programming Techniques" manual that
 shipped with C version 6.00 and 6.00a, there are examples of compile
 and link lines for building a program that calls a DLL version of the
 C run-time library. The LINK command-line fails to include the /NOI
 option, which is necessary for the program to load properly.

 The linker can resolve calls to the run-time DLL without /NOI because
 the import library contains the function names needed, but then the
 linker will write out the function names to the .EXE with the wrong
 case. For example, if a program calls printf() and it is linked
 without /NOI, it will have _PRINTF written to the .EXE. The loader
 will then look for _PRINTF in the DLL, while the actual function in
 the DLL is _printf.

 As a result, everything seems to compile and link correctly, but when
 you try to run the program, you will get a SYS2070 error: The system
 could not demand load the application segment.

 If you build from within the Programmer's WorkBench (PWB), the /NOI is
 inserted automatically and everything works correctly.


 909. Internal Compiler Error: '@(#)newcode.c:1.87', Line 604

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64440

 If the sample code below is compiled in large or compact memory model
 with any optimizations except /Od, /Oa, or /Ow, the compiler will fail
 with the following error message:

    fatal error C1001: Internal Compiler Error
     (compiler file '@(#)newcode.c:1.87', line 604)
     Contact Microsoft Product Support Services

 If compiled with /Oa or /Ow, the following error message will be
 generated:

    fatal error C1001: Internal Compiler Error
     (compiler file '@(#)regMD.c:1.100', line 1017)
     Contact Microsoft Product Support Services

 Sample Code
 -----------

 #include <ctype.h>
 #define OFFSET 2
 #define NEXTFP(nextfp,fp) \
         nextfp = (long) fp & 0xffff0000;\
         nextfp = nextfp + * fp + *(fp+1) * 0x100;

 static unsigned char * stk_bottom;
 static long first_fp;

 void main (void) {}

 void chkstkinit()
 {
    unsigned char stk_top;
    static long nextfp;
    static unsigned char *fp;

    stk_top = 0xaa;
    fp = &stk_top + OFFSET;
    NEXTFP(nextfp, fp);
    stk_bottom = (unsigned char *)nextfp;   // Error on this line
    first_fp = *stk_bottom + *(stk_bottom +1) * 0x100;

    return;
 }

 Since these errors occur if any optimization is turned on, compiling
 with the /Od optimization switch or using the new optimize pragma to
 turn off all optimizations is the easiest solution.


 910. Heap Management and Why malloc() May GP Fault in OS/2

 Product Version(s): 5.10 6.00
 Operating System:   OS/2
 Flags: ENDUSER | GPF
 Last Modified:  9-NOV-1990    ArticleIdent: Q64521

 On rare occasions, a protection violation may occur under OS/2 while
 a program is executing the code for the Microsoft C run-time library
 function malloc(). This type of problem can usually be traced to a
 situation where a program makes repeated calls to malloc() and at some
 point between calls something overwrites its bounds in the dynamically
 allocated memory. If this happens and the internal data structures in
 the heap are corrupted, the next call to malloc() will inadvertently
 try to allocate memory that may not really be available, resulting in
 the protection violation.

 The malloc() function gives you memory in the size you request, but
 malloc() gets the memory from the operating system (OS) in "blocks".
 This block size is determined by the value of _amblksize, which is 8K
 by default. Therefore, if you request 100 bytes on your first malloc()
 call, malloc() will actually get 8K from the operating system to
 satisfy your request. If the next request can be satisfied from the
 remainder of the 8K block, then it will be. If not, then malloc()
 requests the number of new 8K blocks needed from the OS to satisfy the
 new request.

 The result is that you always get memory from the OS in 8K multiples,
 but the internal malloc() suballocation routines divide it up for the
 program's specific requests. The heap, itself, is essentially this
 group of 8K blocks that contain memory that can be used and freed by
 your program. As you do more and more malloc() calls, the heap grows.
 When a segment boundary limits further expansion, a new segment is
 added to the heap.

 The heap is structured with a 12-byte header at the beginning of the
 segment and then there is a two-byte header at each new allocation.
 These headers contain a two-byte number that is the size of the
 allocated amount. If the last bit is a 0 (zero), then the memory is
 being used -- if the last bit is a 1, then the memory has been freed
 and is available.

 Because of this scheme, all allocations must be in even-byte amounts.
 Requests for odd amounts are satisfied with an even number of bytes of
 memory. Odd values are used only to show availability. The top end of
 the current heap segment also contains a header with a flag (FFFE),
 which indicates the end of the heap segment.

 As an example, assume three calls to malloc() are made for 2K, 3K, and
 2K bytes. The heap would then appear as follows:

                ______________
                |    FFFE    | 8K
                |------------|
                |    1002    |
                |  remaining |
                |    bytes   |
                |------------|
 Rover -------> |    3EDH    | <--- Next allocation header
                |------------|        (odd = available)
                |     2K     |
                | allocation |
                |------------|
                |    800H    | <--- Allocated memory header #3
                |------------|        (even = in use)
                |            |
                |     3K     |
                | allocation |
                |------------|
                |    C00H    | <--- Allocated memory header #2
                |------------|        (even = in use)
                |     2K     |
                | allocation |
                |------------|
                |    800H    | <--- Allocated memory header #1
                |------------|        (even = in use)
                |   HEADER   |
                |____________| <--- Heap segment header

 The rover (shown in the diagram above) is a pointer that always points
 to the header of the next new allocation area or to the header of the
 last freed heap area, if a segment was just freed. Either way, the
 rover is always pointing to an available memory area in the heap.

 When you request more memory, the header at the rover is checked
 first. If that current header does not show enough space, then the
 rover advances to the next header and another check is done. If the
 space is in use or not big enough, then the rover continues to the
 next. If the rover reaches the top of the segment, it wraps around to
 the bottom. The rover knows where the next header is each time by
 looking at the current header and moving that many bytes ahead (less 1
 if that amount is odd). If the current header shows FFFE, the rover
 knows to wrap around to the bottom.

 If the rover finally works its way back to its starting point, it
 means that no currently free section of the heap is big enough to
 satisfy the request, so an attempt is then made to grow the segment.
 If that is not possible, then a new segment is added to the heap.

 To continue the example, assume that you have the above scenario and
 the heap is as shown. Let's also assume that you now want 5K of
 memory. If all is well, the search (as described in the preceding
 paragraphs) will take place, but no block will be found in the current
 heap that is large enough. Therefore, the heap will be grown with
 another 8K block from the OS and the actual heap allocation will be
 made right where the rover is currently pointing. The program will
 behave as expected.

 On the other hand, let's assume that before asking for more memory, a
 pointer used to deal with data in the second allocated memory section
 inadvertently goes out of range and happens to cause the "allocated
 memory header #3" to be written over. Let's also assume that this
 overwrite causes the value at "allocated memory header #3" (when
 interpreted as an integer) to become an odd number larger than 5K (for
 example, 8AC1h):

                      .
                      .
                      .
                |     2K     |
                | allocation |
                |------------|
 This value --> |   8AC1H    | <--- Allocated memory header #3
 is now garbage |------------|        (now odd = available)
                |            |
                |     3K     |
                | allocation |
                |------------|
                |    C00H    | <--- Allocated memory header #2
                      .
                      .
                      .

 Then, assuming that we try to malloc() our desired 5K, the header at
 the rover will be checked first. Since 3EDh is not large enough, the
 rover jumps to the next header at the top of the heap. The FFFE header
 signals that the rover should wrap to the bottom of the heap segment.
 It gets to the bottom and the first header says the memory is in use.
 It goes to the second header and this, too, is unavailable.

 Now, the critical part happens. The rover goes up the correct number
 of bytes to read the third header, but the value there is 8AC1h. This
 is odd (= available) and greater than 5K, so malloc() thinks it has
 found its spot. Before returning, malloc() counts off the 5K bytes and
 tries to write the new header for the next allocation. Of course this
 is out of the range of memory that has already been allocated to us by
 the OS, so you get a protection violation when it tries to write.

 There are many other possible scenarios, but the result is essentially
 the same. If you corrupt the heap inadvertently, you're likely to
 crash with a protection violation. Under DOS, you'll end up trashing a
 lot of memory. To resolve this problem, you must look for places in
 the allocated data where you could be going out-of-range.

 There are a number of heap-checking functions available for
 identifying problems in the heap (for example, _heapchk, _heapwalk,
 etc.). If you are suffering from malloc() or heap problems, then a
 good debugging plan to check the heap with these functions before each
 new malloc() call, until the heap-damaging area of the code is
 isolated.


 911. _outtext() Corrupts String in C 6.00 Large and Compact Models

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 s_quickc
 Last Modified: 31-AUG-1990    ArticleIdent: Q64561

 In Microsoft C version 6.00 large and compact memory models,
 _outtext() can corrupt the string of characters passed to it in
 certain circumstances. It does this by inserting a NULL character into
 the string.

 The following program demonstrates the problem. Before the second
 _outtext() call, the buffer is a full 2999 bytes; after the call, it
 is considerably smaller, signifying that the NULL has been inserted
 into the buffer.

 Sample Program
 --------------

 #include<stdio.h>
 #include<graph.h>
 #include<memory.h>
 #include<string.h>
 #include<conio.h>
 #include<process.h>

 char buffer[3000];

 void main(void)
 {
    memset(buffer,'A',3000);
    buffer[2999]='\0';
    printf("%d",strlen(buffer));
    _settextrows(_MAXTEXTROWS);
    _outtext((char far *)buffer);  // Looks good so far.

    getch();
    printf("%d",strlen(buffer));   // String still not corrupted.

    getch();
    _outtext((char far *)buffer);  // NULL inserted in buffer!
    printf("%d",strlen(buffer));   // Notice smaller string length.
 }

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 912. Command Line Error D2030: INTERNAL COMPILER ERROR IN 'QC'

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64563

 The program below when compiled under OS/2 with the /qc switch will
 issue the following error:

    Command line error D2030 : INTERNAL COMPILER ERROR in 'QC'
                    Contact Microsoft Product Support Services

 The error gives no line number indicating which line within the source
 code is causing the problem.

 Sample Code
 -----------

 1: double d = +.1 ;
 2:
 3: void main( void )
 4:     {
 5:     }

 The error can be avoided by not placing the unary plus before the ".1"
 in line 1: or by not using the /qc (quick compile) option.

 Since no source code line number is given in this error message, it
 can be quite difficult to track down this type of error. The error can
 occur almost anywhere in a program. A double variable need only be
 initialized at the time of declaration to a simple floating point
 number with a unary plus preceding it. This problem can occur in a
 global or local declaration.

 The following are suggested methods for tracking down the error:

 1. Search for all lines containing "double". This error occurs only
    when the type specifier double is used.

 2. Comment out sections of code or break up the code into smaller
    parts until you find the problem line.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 913. Internal Compiler Error: '@(#)regMD.c:1.100' Line 929

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64564

 The code below, when compiled using Microsoft C 6.00, produces the
 following error:

    foo.c(15) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)regMD.c:1.100', line 929)
                Contact Microsoft Product Support Services

 Sample Code
 -----------

 // Compile using 'cl -Od':

 #define Rev(x)  ( ( (x) >> 24 ) | \
                   ( ( (x) & 0xff0000 ) >> 8 ) | \
                   ( ( (x) & 0x00ff00 ) << 8 ) | \
                   ( (x) << 24) )

 #define Get(x,y) \
     (((x) == 183) ? (y) : Rev(y))

 void main (void)
 {
    long l;
    long *pl;
    int Order;

    l = Get(Order,*pl);  // This line causes the error.
 }

 The workaround for this problem is to either compile using the "-qc"
 option or to simplify the expression.

 One way of simplifying the above nested macro expression is to call
 each macro separately. For instance, the following is a feasible
 workaround:

 1. Redefine the Get macro as follows:

       #define Get(x,y,z) \
           ((((x) == 183) ? (y) : (z))

 2. Then for every call to the Get macro, use the following two
    statements:

       temp = Rev(x);
       l = Get(Order,*pl,temp);

 Microsoft has confirmed this to be a problem with the C Compiler
 version 6.00. We are researching this problem and will post new
 information here as it becomes available.


 914. #if Uses Only Lower 2 Bytes of Expression for Test

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64565

 The #if compiler directive uses only the lower 2 bytes of the
 evaluated expression when testing for true or false.

 The following code, when compiled using the C 6.00 compiler, will
 evaluate the #if expression to false, when it should evaluate to
 true since the number is non-zero:

 Sample Code
 -----------

 void main (void)
 {
 #if 0xFFFF0000L
   printf("TRUE\n");
 #else
   printf("FALSE\n");
 #endif
 }

 According to the ANSI standard (Section 3.8.1), any long expression in
 an #if directive must be evaluated as if it were a long value.

 The workaround for this problem is to only use 2-byte expressions in
 an #if directive.

 Microsoft has confirmed this to be a problem with the Microsoft C
 Compiler version 6.00. We are researching this problem and will post
 new information here as it becomes available.


 915. Online Help Solution for C4139 Warning Is Incorrect

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc docerr
 Last Modified: 19-JAN-1991    ArticleIdent: Q64640

 Using hexadecimal constants in strings results in a compiler warning
 "C4139: '0xsequence' : hex escape sequence is out of range" if the hex
 digits following the "\x" escape character evaluate to a number too
 large to be converted to an ASCII character. The online help for
 Microsoft C versions 6.00 and 6.00a and QuickC versions 2.50 and 2.51
 show an example of code that produces the following warning:

    printf("\x7bell\n");   /* Error-Causing Code */

 Next, the following workaround is given to resolve the problem:

    printf("\x007bell\n");  /* Supposed to solve problem */

 Unfortunately, the second printf() statement produces the same error
 as the first.

 In Microsoft C version 5.10 and QuickC version 2.00, hexadecimal
 escape sequences are limited to three characters. C version 6.00 and
 QuickC version 2.50 now conform to the ANSI specification by treating
 every potential hexadecimal digit following the "\x" as part of the
 constant.

 Three valid workarounds are listed below:

 1. printf("\x007""bell\n");

 2. char TypeArray[] = "\x007""bell";

    printf("%s\n", TypeArray);

    Note: According to the ANSI standard, adjacent string literals are
    concatenated after escape sequences have been calculated.

 3. printf("\007bell\n");     /* Use Octal */

    Note: This workaround uses an octal constant rather than a
    hexadecimal constant, and is a good solution if portability is a
    concern.

 Additional information is given in the C 6.00 README.DOC file in Part
 2: "Differences between C 5.1 and 6.0," under the subtitle
 "Hexadecimal Constants in Strings."


 916. Nested Nameless Structs Can Cause C2030 Error

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 16-AUG-1990    ArticleIdent: Q64686

 Using the same nameless structure as a member of two different
 structures will cause the compiler error: C2030: 'varname':
 struct/union member redefinition. The code sample below reproduces the
 error:

 Sample Code
 -----------

 #include <stdio.h>

 void main(void)
  {

    struct s1
      {
        int a,b,c;
      };

    struct s2
      {
        struct s1;
        float y;
        char str[10];
      } *p_s2;

    struct s3
      {
        struct s1;
        float z;
        char a[10];
      } *p_s3;
  }

 The error message names the structure member following the nameless
 struct. A second nameless struct may be used only if it contains
 different fields than the first nameless struct.

 Examples of nameless structures and unions are given on Page 434 of
 the "Advanced Programming Techniques" book provided with C version
 6.00. There is also mention of this problem in the README.DOC file.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here when it
 becomes available.


 917. Cannot View Some Include Files Inside the PWB Online Help

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q64687

 Under DOS only, it isn't possible to access the five include files,
 which are normally stored in the C600\include\sys subdirectory, from
 within the PWB online help. The list of include files that cannot be
 viewed is shown below:

    sys\locking.h
    sys\stat.h
    sys\timeb.h
    sys\types.h
    sys\utime.h

 Attempting to view these files produces a dialog box showing the
 message "Cannot Open [$INCLUDE: sys\filename.h]: Not found." The
 available alternatives are to either access these include files from
 inside the QuickHelp (QH) online help or to bring them into an editor
 for viewing. Under OS/2, these include files may be accessed from
 either the QH or Programmer's WorkBench (PWB) online help without
 difficulty.

 To reproduce this problem, select the Contents option from the Help
 menu inside PWB. Next, select C Language, then Include (.h) Files.
 This will bring of a list of all C 6.00 include files. Selecting any
 of the five include files listed above produces the error message.

 Microsoft has confirmed this to be a problem in the PWB version 1.00.
 We are researching this problem and will post new information here as
 it becomes available.


 918. _outtext Can Produce Protection Violation Error

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q64789

 Under certain conditions, the C 6.00 version of _outtext can produce a
 protection violation. The error occurs when executing protected-mode
 programs compiled under the large and compact memory models. The
 following sample code illustrates the problem:

 Sample Code:

 /* Compile with any optimizations in large or compact model... */

 #include <stdio.h>
 #include <graph.h>
 #include <conio.h>

 char a1[10] = "boogie";
 char a2[10];

 void main(void)
 {
    _outtext(a1);        // This _outtext works correctly
    a2[0] = 'a';
    a2[1] = 'b';         // Construct a null-terminated string
    a2[2] = '\0';
    _outtext(a2);        // Segmentation Violation occurs here
 }

 Three methods of working around this problem are listed below:

 1. Initialize the string (that is, char a2[10] = "\0";).

 2. Declare the string variable as a local variable rather than as a
    global variable.

 3. Increase the number of elements in the character array. In the
    large memory model, arrays in the range of 649 to 5,000 bytes in
    size will work without problems. Arrays containing 643 to 5,000
    bytes will work when compiling under the compact memory model.
    (Arrays larger than 5,000 bytes may work also; however, this has
    not been tested.)

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 919. _emit Directive in C 6.00 Does Not Function Properly

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q64790

 The _emit directive does not function properly in C version 6.00.
 Instead of sending the requested values, a 0 (zero) value is always
 sent.

 The QuickC version 2.50 compiler handles the _emit directive correctly
 as does the Quick Compiler option (/qc) in C version 6.00.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 920. Intrinsic Form of memcpy() Can Produce Incorrect Code

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q64791

 In rare cases, the intrinsic form of memcpy may produce incorrect code
 in the large memory model.

 The code below, if compiled with the large memory model (/AL) and any
 optimization that includes intrinsic functions (/Oi, /Ox, /Oz), will
 cause the machine to hang under DOS and cause a protection violation
 under OS/2.

 To work around this problem, either compile without the /Oi option or
 use #pragma "function(memcpy)" to specify the use of the function form
 of memcpy(). The pragma may be turned off for functions following it
 by using #pragma intrinsic(memcpy) to go back to the intrinsic form of
 memcpy.

 Sample Code
 -----------

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

 typedef struct
 {
    int     dummy;
    char  *f_char[8];
    char  *f_attr[8];
 } t_field;

 void copy_fieldtxt(t_field *, t_field *, int, int);

 void main(void)
 {

    t_field *src, *dst;
    void    *calloc();

    src=(t_field *)calloc(1,sizeof(t_field));
    dst=(t_field *)calloc(1,sizeof(t_field));

    src->f_char[0]= strdup("Text string");
    src->f_attr[0]= strdup("attribute string");

    dst->f_char[1]=strdup("Text string");
    dst->f_attr[1]=strdup("attribute string");

    copy_fieldtxt(src,dst,0,1);
    printf("dst->attr[1]==>%s\n",dst->f_attr[1]);

 }
 /* Copies src->f_char[srcndx] to dst->f_char[dstndx]
     and src->f_attr[srcndx] to dst->f_attr[dstndx] */
 void copy_fieldtxt(t_field *src, t_field *dst, int srcndx, int dstndx)
 {
    int maxlen=strlen(dst->f_attr[dstndx]);

    memcpy(dst->f_char[dstndx], src->f_char[srcndx], maxlen);
    memcpy(dst->f_attr[dstndx], src->f_attr[srcndx],maxlen);
 }

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 921. goto Label at End of Block Without ";" Invalid Syntax

 Product Version(s): 4.x 5.x 6.00 | 5.10 6.00
 Operating System:   MS-DOS       | OS/2
 Flags: ENDUSER | s_quickc 1.x 2.00 2.50 s_quickasm 2.01 2.51
 Last Modified: 15-AUG-1990    ArticleIdent: Q64807

 If a goto label appears last in a block of code, the following
 compiler error will be generated:

    error C2143:  missing ';' before '}'.

 The sample code below illustrates the problem.

 The semicolon is required by the ANSI definition of the C programming
 language. In fact, this situation is described in Section 3.6.3 of the
 standard.

 To eliminate the error, use proper syntax as described below.

 Sample Code
 -----------

 #include <stdio.h>
 #include <conio.h>

 void main(void)
   {
      char ch;

      while(!kbhit())
         {
           printf("Want to end this loop?  (y/n)  \n");
           if((ch = getche()) == 'y')
              {
                 printf("out of loop\n");
                 goto mybug;
              }
           printf("More loop processing here....\n");
           mybug:   /* This line generates the syntax error      */
         }          /*       replace with: mybug:  ;             */
   }


 922. _polygon() with _GFILLINTERIOR Does Not Work When Clipped

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 s_quickc setcliprgn
 Last Modified: 17-DEC-1990    ArticleIdent: Q65200

 When _polygon is called to draw a filled polygon inside a clip region
 set with _setcliprgn, the polygon may not be drawn correctly. The
 following program demonstrates the error:

 #include <graph.h>

 struct xycoord pts[4] = {{0,0}, {55,55}, {83,25}, {0,0}};

 void main(void)
 {
      _setvideomode(_ERESCOLOR);

 /* show the polygon */
      _setcolor(3);
      _polygon(_GFILLINTERIOR, pts, 4);
      getch();

 /* show the clipped region */
      _setcolor(3);
      _rectangle(_GBORDER, 0, 0, 75, 50);
      _setcliprgn(0,0, 75, 50);
      getch();

 /*** polygon drawn will have portion missing with _GFILLINTERIOR ***/
      _setcolor(10);
      _polygon(_GFILLINTERIOR, pts, 4);
      getch();

 /* clipped polygon drawn correctly with _GBORDER */
      _setcolor(12);
      _polygon(_GBORDER, pts, 4);
      getch();

      _setvideomode(_DEFAULTMODE);
 }

 Any horizontal lines that are being clipped will not be drawn at all.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here when
 it becomes available.


 923. Why Some Sample Programs Produce Compiler Warnings

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_pascal
 Last Modified: 15-AUG-1990    ArticleIdent: Q64828

 The following list outlines reasons why the sample programs included
 with many Microsoft language products might produce warnings when
 compiled:

 1. Many of the language elements (for instance, typecasts), which
    might be necessary to eliminate the warnings, could obscure the
    points the writer is trying to emphasize.

    The sample programs are included to explain a topic or demonstrate
    how to use a feature, and might not necessarily reflect model
    programming practice.

 2. The documents are written well before the compiler is finished in
    the development process. The warnings sometimes change as the
    compiler progresses. Therefore, it is very difficult to write
    warning-free code early in the development process and have it
    compile with no warnings with the release version.


 924. _memavl() Returns 0 If Not Bound with APILMR.OBJ

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1990    ArticleIdent: Q65243

 When creating a large or compact model bound program that uses the
 _memavl() function, APILMR.OBJ must be added to the BIND line or the
 function will always return 0 (zero). The following code duplicates
 the problem along with the solution:

 Sample Code
 -----------

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

 int main(void)
 {
    size_t bytes;

    bytes = _memavl();
    printf("_memavl returns: %x\n", bytes);
    return(0);
 }

 If the above code is compiled with /AL or /AC, and bound with BIND,
 it will return the following message:

    _memavl returns: 0

 However, when APILMR.OBJ is specified as follows, the program will
 return a valid value:

    bind foo.exe apilmr.obj

 For more information on the APILMR.OBJ file, query in QuickHelp on
 BIND, then click the button for APILMR.OBJ.


 925. C1001: Internal Compiler Error: '@(#)regMD.c:1:100', Line 4634

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65245

 The sample code below causes an internal compiler error when compiled
 in the large or compact memory model with the "e" and "i" optimization
 options. The exact error is as follows:

    foo.c(42) : fatal error c1001: Internal Compiler Error
              (compiler file '@(#)regMD.c:1:100', line 4634)

 Note: Compile with the following:

    /AL /Oei

 Sample Code
 -----------

  1 #include <string.h>
  2 #include <stdlib.h>
  3
  4 void change_value (int *n);
  5
  6 typedef struct smpdata_st *SMP;
  7 typedef struct fdata_st *FDP;
  8
  9 struct fdata_st
 10 {
 11   int resolution,
 12       nwaves,
 13       startwv,
 14       endwv;
 15   char fname[13];
 16   SMP data;
 17 };
 18
 19 struct smpdata_st
 20 {
 21   float *abs;
 22   SMP next;
 23 };
 24
 25 void main(void)
 26 {
 27   extern FDP fptr;
 28   FDP fp = fptr;
 29   SMP p;
 30   int count;
 31   int nsamples, nwaves, startwv = 0;
 32   int temp1, temp2;
 33   char fname[13];
 34
 35   change_value(&nsamples);
 36   change_value(&nwaves);
 37
 38   strcpy (fp -> fname, fname);
 39
 40   if (startwv < fp -> startwv)
 41   {
 42     count = (fp->startwv - startwv) / fp->resolution;
 43     p = fp -> data;
 44     while (p != NULL)
 45     {
 46       memmove (p -> abs + count, p -> abs,
 47                fp -> nwaves * sizeof *p -> abs);
 48       p = p -> next;
 49     }
 50   }
 51 }

 The following are two workarounds:

 1. Avoid using the e and i optimizations together.

 2. Assign both structure references in line 42 to temp variables and
    replace them with their respective temp variables.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 926. C1001: Internal Compiler Error: '@(#)regMD.c:1.100', Line 3431

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified:  7-SEP-1990    ArticleIdent: Q65300

 When compiled with the /Ox option, the code below generates the
 following internal compiler error:

    fatal error C1001: Internal Compiler Error
    (compiler file) '@(#)regMD.c:1.100', line 3431
    Contact Microsoft Product Support Services

 Sample Code
 -----------

 typedef struct {
    char DispCon:1;
    char DispMon:1;
    char Flash:1;
    char Tones:1;
    char TonInt:1;
 } tTVsetup;

 void CopyTVsetup(tTVsetup dest[], tTVsetup src[])
 {
    int calltype;

    for (calltype = 0; calltype < 5; calltype ++)
    {
       dest[calltype].TonInt = src[calltype].TonInt;
       dest[calltype].DispCon = src[calltype].DispCon;
       dest[calltype].DispMon = src[calltype].DispMon;
       dest[calltype].Flash = src[calltype].Flash;
       dest[calltype].Tones = src[calltype].Tones;
    }
 }

 Note that a signed bit-field makes no sense, and when changed to
 unsigned, this code compiles correctly. The "e" optimization seems to
 be causing this error. Not using it on the command line or adding an
 optimize pragma to turn off the function will work as a workaround.

 Microsoft has confirmed this this to be a problem with C version 6.00.
 We are researching this problem and will post new information here as
 it becomes available.


 927. C1001: Internal Compiler Error: '@(#)regMD.c:1.100', Line 929

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65301

 In certain instances the compiler will generate the following
 internal compiler error:

    fatal compiler error C1001: Internal Compiler Error
    (compiler file '@(#)regMD.c:1.100' line 929)
    Contact Microsoft Product Support Services

 In cases where this error is generated, there are several ways to work
 around the problem. Compiling with the /Od option is one way to
 correct the error, but it may not be needed. You may also want to try
 other optimizations and if you find the one that causes the error, use
 the optimize pragma to remove that optimization from the function in
 question. Other workarounds include breaking-up the code into smaller
 modules and/or simplifying the expression that the failure occurs on.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 928. Warning C4056: "Overflow in Constant Arithmetic" May Be Wrong

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 27-NOV-1990    ArticleIdent: Q65302

 The compiler warning "C4056: Overflow in constant arithmetic" may be
 erroneously generated by the compiler. The incorrect warning message
 usually appears when accessing data in arrays. If the quick compile
 (/qc) option is specified, the error message is not generated.

 The C4056 warning is generated on warning level 2 (/W2) or higher.

 Sample Code
 -----------

 // This code fragment will generate the C4056 error on the
 // the two lines that reference rate_file.factor14[8][ctr]

 #include <string.h>

 struct PC_RATE_FILE
 {
   char  kind[3];
   char  state[3];
   char  rate_date[7];
   long  base[20];
   long  factor01[40][20];
   long  factor02[40][20];
   long  factor03[40][20];
   long  factor04[40][20];
   long  factor07[40][20];
   long  factor08[40][20];
   long  factor09[40][20];
   long  factor10[40][20];
   long  factor11[40][20];
   long  factor12[40][20];
   char  factor14[40][20][8];
   long  factor15[40][20];
   char  valid_year[15][3];
   char  valid_terr[40][3];
   char  valid_class[40][3];
 } rate_file;

 int testit()
 {
   long ctr;
   char test_string[80],*ptr;
   long test_rel;

   for (ctr=0;ctr<6;ctr++)
   {
     ptr = (char *)rate_file.factor14[8][ctr];
     strcpy (test_string,rate_file.factor14[8][ctr]);
     test_rel = rate_file.factor15[7][ctr];
   }

   return(1);
 }

 Microsoft has confirmed this to be a problem with C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 929. Quick Help Does Not Work on Some CGA Video Adapters

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65303

 The Quick Help help system does not work on some CGA cards. This will
 manifest itself as garbled data on the screen and a possible machine
 hang. Currently the only workaround is to use a different video card.


 930. C2059 and C2065 May Be Caused by Not Including stdio.h

 Product Version(s): 5.x 6.00 | 5.x 6.00
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER |
 Last Modified: 31-AUG-1990    ArticleIdent: Q65304

 When a function prototype has a pointer of type FILE in the parameter
 list and stdio.h is not included, it will give the error on the "*"
 because the compiler assumes that FILE is a data name instead of a
 typedef, which it really is. To eliminate the error, include stdio.h
 before the FILE typedef is used in the code.

 The same problem (not including stdio.h) may manifest itself as the
 following error message:

    C2065 : 'FILE' : undefined

 The workaround is the same.

 Sample Code
 -----------

 void test(FILE *fp); // This line will cause the C2059 error.

 void main ()
 {
   FILE *fp;          // This line will cause the C2065 error.

   test(fp);

 }

 void test(FILE *vp)
 {
 }


 931. C1001: Internal Compiler Error: '@(#)regMD.c:1.100', Line 4634

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65305

 The code below generates the following error if compiled with /Oe and
 /Ol in any memory model:

    fatal error C1001: Internal Compiler Error
         (compiler file '@(#)regMD.c:1.100', line 4634)

 Sample Code
 -----------

 #include <stdio.h>

 extern FILE *ftable;
 extern int nrules;
 extern short *rrhs;

 output_rule_data()
 {
   int i;
   int j,k;

   for (i=1;i<nrules;i++)
   {
     k = i+1;     // Use k for i+1 in the next line as a workaround

     fprintf(ftable,"%6d",rrhs[i+1] - rrhs[i] - 1);
   }
 }

 The following are suggested workarounds:

 1. Do the incrementing of the index of the array outside the printf
    using a temporary variable, and use that variable as the index
    inside the printf.

 2. Compile without the /Oe or /Ol compile option by NOT including the
    option on the compile line or using the optimize or loopopt pragma.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 932. toupper() Gives C4135 Warning

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 31-AUG-1990    ArticleIdent: Q65306

 When compiling a function that contains a call to toupper() in the
 format

    char toupper (char)

 at warning level 2 or above, the compiler will generate the following
 warning message:

    C4135: Conversion between two integral types

 Since the ANSI-standard draft of December 7, 1988, specifies the
 syntax for this function as follows, the warning is in compliance with
 the standard:

    int toupper (int)


 933. M6110: MATH Floating-Point Error: Stack Overflow

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65307

 When compiled with global register allocation optimization turned on,
 the program produces the following error when executed:

    run-time error M6110: MATH
    - floating-point error: stack overflow

 This error should not occur. This problem occurs in both DOS and OS/2
 with either the emulator or 8087 math libraries.

 You can work around the problem by doing the following:

 1. Turn off global register allocation globally by not including the
    /Oe switch on the compile line, or turn it off locally with the
    #pragma optimize("e",off).

 2. Compile with the /Op switch. This improves the accuracy of floating
    point calculations, but also slows execution.

 Sample Code
 -----------

 #include <malloc.h>

 //#pragma optimize("e",off) //uncomment this line and no error occurs

 void func(float *x1,float *y1,float *x2,float *y2,float *x3,float *y3,
           unsigned size,float *xc1,float *yc1)
     {
     float   tx,ty ;

     while (size--)
         {
         //_asm nop          //uncomment this line and no error occurs
         tx = (*xc1 * *x1) - (*yc1 * *y1) ;
         ty = (*xc1 * *y1++) + (*yc1 * *x1++) ;
         *x3++ = (tx * *x2) - (ty * *y2) ;
         *y3++ = (tx * *y2++) + (ty * *x2++) ;
         }
     }

 void main(void )
     {
     float   xx1[7],xx2[7],xx3[7],yy1[7],yy2[7],yy3[7] ;
     float   xn,yn ;
     unsigned    tsize = 7 ;

     xn = 1 ;
     yn = 0 ;
     func (xx1,xx2,xx3,yy1,yy2,yy3,tsize,&xn,&yn) ;
     }

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 934. Default Optimization Generates Bad Code in Switch Construct

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65308

 The following sample code is compiled incorrectly when the default
 optimizations are used. When compiled with /Ot, /On, /Oc, or the
 default options (/Ocnt), the program fails to recognize certain keys
 as "default" (function keys and the top row of number keys 1, 2, 3,
 etc.). When compiled without the offending optimizations, all keys are
 recognized.

 The workaround is to use the optimize pragma, as follows:

    #pragma optimize("tn","off")

 Or, use the quick compile option /qc.

 Sample Code
 -----------

 #include <stdio.h>
 #include <bios.h>
 #include <stdlib.h>

 #define ESC   0x1b
 #define HT    0x09
 #define S_TAB 0x0f
 #define RT    0x4d
 #define BS    0x08
 #define CR    0x0d

 void main(void)
 {
    unsigned c;

    printf("\n");
    while (1)
    {
       c = _bios_keybrd(_KEYBRD_READ);

       if (! (c&0xff))
          c >>= 8;
       else
          c &= 0xff;
       switch (c)
       {
          case ESC:
             printf("ESCAPE\n");
             exit(0);
          case HT:
             printf("HT\n");
             break;
          case S_TAB:
             printf("SHIFTED TAB\n");
             break;
          case RT:
             printf("RIGHT ARROW\n");
             break;
          case BS:
             printf("BACK SPACE\n");
             break;
          case CR:
             printf("CARRIAGE RETURN\n");
             break;
          default:
             printf("DEFAULT\n");
             break;
       }
    }
 }
 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 935. In-Line Assembler Locks Up C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65309

 The code below will "lock up" C 6.00 regardless of optimizations.

 Using the quick compiler (/qc) will allow the program to compile.

 Sample Code
 -----------

 #define LCPPORT 0
 #define COMREQ 0x14
 #define FOREVER for(;;)

 extern void _far _cdecl delay(int ticks);

 void clrlcp(void)
 {
 int ticks = 4;
    FOREVER
       {
       _asm
          {
          push [ticks]
          call delay
          add sp,2
          mov dx,LCPPORT
          mov ah,7
          int COMREQ
          cmp al,0
          jz done
          mov dx,LCPPORT
          mov ah,6
          int COMREQ
          }
       ticks = 4;
       }
    done: return;
 }

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 936. Compiling C 5.10 Code with C 6.00 Can Cause Stack Overflow

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-AUG-1990    ArticleIdent: Q65311

 Microsoft C version 6.00 uses stack space differently than Microsoft C
 version 5.10. Thus, programs that use most of the allocated stack
 space under C 5.10 will cause a stack overflow when compiled with C
 6.00. This problem can be resolved by increasing the stack space by
 using the /F compile option or the /ST linker option.


 937. Documentation for _strerror() Return Value Is Incorrect

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | docerr s_quickc
 Last Modified: 28-JAN-1991    ArticleIdent: Q65313

 The _strerror() function is documented incorrectly in the online help
 for the Microsoft C Compiler versions 6.00 and 6.00a, as well as
 QuickC versions 2.00, 2.01, 2.50, and 2.51:

 The statement below

    The _strerror function returns no value.

 should be changed to read as follows:

    The _strerror function returns a pointer to the error-message
    string.

 This function is also documented incorrectly in the following manuals:

    "Microsoft C Reference" for C version 6.00, page 338

    "Microsoft C Run-Time Library Reference" for C version 6.00, page 743

    "Run-time Library Reference" for C version 5.10, page 581

    "QuickC Run-Time Library Reference" for QuickC versions 1.00 and 1.01,
     page 581

    Online help for QuickC versions 2.00, 2.01, 2.50, and 2.51

 The online help mentions the correct return value for the _strerror
 function in the body of the "Description" section, but in the section
 titled "Return Value," the return value is documented incorrectly.


 938. C1001: Internal Compiler Error: '@(#)omf.c: 1.88', Line 147

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65314

 The code below, when compiled using default optimizations, produces
 the following error under DOS:

    fatal error C1001: Internal Compiler Error
    (compiler file '@(#)omf.c:1.88', line 147)
    Contact Microsoft Product Support Services

 The following error is produced under OS/2:

    Command line error D2030 : INTERNAL COMPILER ERROR in 'P2'
              Contact Microsoft Product Support Services

 Sample Code
 -----------

 _segment myseg;
 extern int _based(myseg) a[];
 int _based(_segname("foo")) a[] = {{0}};

 To workaround the problem, use one of the following:

 1. Compile with the /qc command-line option.

 2. Switch the order of lines 2 and 3.

 Microsoft has confirmed this to be a problem with the C version 6.00.
 We are researching this problem and will post new information here as
 it becomes available.


 939. C1001: Internal Compiler Error: '@(#)regMD.c:1.100', Line 3837

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65328

 The code below generates the following error when compiled with any
 optimization in any memory model:

    fatal error C1001: Internal Compiler Error
              (compiler file '@(#)regMD.c:1.100', line 3837)

 The only workarounds in this case are as follows:

 1. Do not use a static array for an index.

 2. Do not use register variables for indexing.

 Sample Code
 -----------

 static int keyList[10];

 struct
 {
   int fdkey[10];
 } fsys[30];

 int bar(int i)
 {
   return;
 }

 void foo(int fd)
 {
   register j,k;
   int kk;

   for (k=0;k<j;k++)
   {
     bar(fsys[fd].fdkey[keyList[k]]);
   }
 }

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 940. C1001: Internal Compiler Error: '@(#)newcode.c:1.87', Line 535

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65330

 The code below generates an internal compiler error
 ('@(#)newcode.c:1.87', line 535), when compiled with any optimization
 that includes /Oe. This error occurs with any memory model. The
 workaround is to not use the /Oe optimization.

 Sample Code
 -----------

 #include <stdlib.h>

 #pragma intrinsic (_rotl)

 void _cdecl ink(unsigned row, int nlines, unsigned char _huge *buff)
 {
   _segment seg;
   unsigned char _based(seg) *next_row;
   union
   {
     unsigned char _based(seg) *ptr;
     unsigned _based(seg) *iptr;
   }p;

   do
   {
     *p.ptr++ &= _rotl(*p.iptr,1) & *next_row++;
     if ((int)p.ptr > 0xc000)
        seg += 0xc000;
   }while(1);
 }

 In the case of the above code, the easiest workaround is to use the
 optimize pragma to turn off the "e" optimization. In other cases that
 cause this error, similar solutions may be called for.

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 941. /G1 Switch Does Not Work As Expected

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65331

 When viewing the .COD file generated by the C 6.00 compiler, the
 compiler inserts a .286 and .287 processor specifier when using the
 /G1 compiler option, which is supposed to produce .8087 processor
 code. As a workaround, use the /G0 switch instead of the /G1 switch.

 The C version 5.10 compiler correctly inserts .8087 instead of a .286
 or .287 preprocessor specifier.

 Sample Code
 -----------

 void main ()
 {
   int a;

   a = 25;
 }

 The above code, compiled with the /G1 /Fc options, produces the
 following .COD file:

 ;       Static Name Aliases
 ;
         TITLE   test.c
         .286p               ; Should be blank line
         .287                ; Should be .8087
 INCLUDELIB      SLIBCE
 _TEXT   SEGMENT  WORD PUBLIC 'CODE'
 _TEXT   ENDS
 _DATA   SEGMENT  WORD PUBLIC 'DATA'
 _DATA   ENDS

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 942. Inline Assembly Incorrectly Accesses Far Labels

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 24-OCT-1990    ArticleIdent: Q65818

 The following inline assembly code produces a NULL pointer assignment
 when compiled with the compact or large memory models. The code should
 store the ss:sp in the huge pointer tsrstack. However, the code
 generated assumes that the variables will be in the segment referenced
 by the DS register. This is not a correct assumption for a compact or
 large memory model program. Thus, the values are moved into DGROUP
 causing the R6001 NULL pointer assignment message.

 This is NOT a compiler error. With inline assembly, the compiler makes
 no changes to the code. Therefore, there is no segment override added
 to the code to allow for tsrstack residing in another segment (in this
 case FAR_DATA). It is the developer's responsibility to make sure that
 the correct code is used for each memory model.

 Sample Code
 -----------

 char _huge * tsrstack;
 void main (void)
 {
    _asm MOV WORD PTR tsrstack[0], sp
    _asm MOV WORD PTR tsrstack[2], ss
 }

 This program was extracted from the larger example program ALARM.C,
 which is accessible through online help.


 943. C 6.00 Incorrectly Evaluates Pointer Arrays to Constant Data

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc buglist6.00
 Last Modified: 17-DEC-1990    ArticleIdent: Q65358

 When an array of pointers to constant data is declared, the C version
 6.00 and QuickC versions 2.50 and 2.51 compilers incorrectly consider
 both pointers and data to be constant.

 The following sample code demonstrates the problem:

 void main(void)
 {
  const int *p[1];
  const int Z = 0;

  p[0] = &Z;
 }

 When the sample code is compiled, the following two errors are
 produced:

    warning C4132: 'p': const object should be initialized

    error C2166: lvalue specifies const object

 Only the data should be constant in this case. The compiler considers
 the pointers to be constant, which is in error, and does not allow
 their value to be changed.

 Microsoft has confirmed this to be a problem with the Microsoft C
 Compiler version 6.00. We are researching this problem and will post
 new information here as it becomes available.


 944. Cannot Initialize Union Containing Nameless Struct Member

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65392

 Initializing a union containing a nameless struct as one of its
 members will cause the following compiler errors:

    error C2097:   illegal initialization

    error C2078:   too many initializers

 The sample code shown below reproduces the problem:

 union
 {
    struct
    {
       int a;
       int b;
    };            // Add a name here to allow initialization
    long c;
 } x = {{ 0,0 }};

 The only workarounds available are to either name the struct or to
 leave the union uninitialized.

 Microsoft has confirmed this to be a problem with Microsoft C version
 6.00. We are researching this problem and will post new information
 here as it becomes available.


 945. Missing Semicolon Can Cause Internal Compiler Errors

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc buglist6.00
 Last Modified: 31-AUG-1990    ArticleIdent: Q65393

 If a semicolon (;) is missing at the end of a structure definition and
 the following statement is a variable declaration of unsigned int or
 unsigned char, no compiler error is generated. However, several
 different internal compiler errors can be generated depending on what
 operating system and compiler you are using.

 Sample Code
 -----------

 int f(void);

 struct foo {
     int x;
     int y;
     }                 // Note: no semicolon

 unsigned int goo;

 void main(void)
 {
    goo = f();
 }

 The following are the results when the sample code above is compiled
 under various operating systems and versions of the C 6.00 compiler:

 Compiling Under C 6.00
 ----------------------

 MS-DOS and OS/2 produce the following:

       fatal error C1001: Internal Compiler Error
       (compiler file '@(#)regMD.c:1.100', line 2886)
       Contact Microsoft Product Support Services

 Compiling Under C 6.00 with the /qc Option
 ------------------------------------------

 1. MS-DOS produces the following:

       fatal error C1001: Internal Compiler Error
       (compiler file 'gencode.c', line 437)
       Contact Microsoft Product Support Services

 2. OS/2 produces the following:

       fatal error C1063:

 Microsoft has confirmed this to be a problem with Microsoft C version
 6.00. We are researching this problem and will post new information
 here as it becomes available.


 946. C1001: Internal Compiler Error: @(#)grammar.c:1.138, Line 164

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-SEP-1990    ArticleIdent: Q65544

 The code below produces the following internal compiler error when
 compiled with loop optimization (/Ol) enabled:

    test.c(10) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)grammar.c:1.138', line 164)
                 Contact Microsoft Product Support Services

 Sample Code
 -----------

 void main(void)
 {
         double x;
         int j;

         for(j = 0; j < 1; j++) {
                 x = j > 0 ? 0.0 : 0.5;
                 x = j >> 2 & 1 > 0 ? 0.0 : 0.5;
         }
 }

 To work around this problem, compile without loop optimization
 enabled, or use the #pragma optimize directive to turn off loop
 optimization for the function in which the error is occurring.

 Another valid workaround is to use an if-then construct in place of
 the ternary operators.

 Microsoft has confirmed this to be a problem with the C compiler
 version 6.00. We are researching this problem and will post new
 information here as it becomes available.


 947. C1001: Internal Compiler Error: @(#)exphelp.c:1.115, Line 698

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-SEP-1990    ArticleIdent: Q65545

 When compiled with default optimizations in the huge memory model, the
 code below produces the error message:

    test.c(10) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)exphelp.c:1.115', line 698)
                 Contact Microsoft Product Support Services

 When compiled in the large memory model, the same code produces the
 following error message:

    test.c(10) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)emit.c:1.115', line 437)
                 Contact Microsoft Product Support Services

 Sample Code
 -----------

 void main(void)
 {
         char *foo, *bar;
         int baz;

         foo = (bar - ((char *) 0) + baz) & ~ baz;
 }

 Microsoft has confirmed this to be a problem with the C compiler
 version 6.00. We are researching this problem and will post new
 information here as it becomes available.


 948. Text/Graphic Mode Determines _setbkcolor() Parameters to Use

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1991    ArticleIdent: Q65552

 When using _setbkcolor() in a graphics mode, you should use the
 predefined color constants found in graph.h. Examples of these
 constants are _BLUE, _GREEN, _RED, etc. When using _setbkcolor() in a
 text mode, you should use values from 0L to 15L. These two systems of
 specifying colors are not interchangeable. For instance, if you use
 _setbkcolor(_BLUE) under a text mode, you will not get a blue
 background.

 For more information, see page 668 of the "Microsoft C Optimizing
 Compiler Run-Time Library Reference" manual or query the online help
 for "_setbkcolor()".


 949. _Floodfill() Doesn't Completely Fill Areas with Patterns

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 24-SEP-1990    ArticleIdent: Q65590

 The sample code below draws two circles that are cut in half with a
 line. There is a small gap (2 pixels) in the line. When _floodfill()
 is used to fill the circle with a solid color, it fills the entire
 circle. When _floodfill() is used to fill the circle with a pattern,
 it fills only half of the circle.

 In this instance, the two-pixel gap in the line corresponds to the gap
 in the fill pattern. This causes _floodfill() to treat it as a solid
 line and fill only half the circle.

 To fill the entire circle with the pattern, create a second
 _floodfill() with a point on the other side of the line, as in the
 commented section of the code below:

 Sample Code
 -----------

 #include <conio.h>
 #include <graph.h>
 #include <time.h>
 #include <stdlib.h>
 #include <stddef.h>

 void main(void)
 {
     unsigned char fill[] = {0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22};

     if( !_setvideomode( _MAXRESMODE ) )
        exit(1);

     _setfillmask( NULL );     /*  Fill circle with a solid color  */
     _setcolor(2);
     _ellipse( _GBORDER, 50, 100, 250, 300 );
     getch();
     _moveto( 50, 200 );
     _lineto( 248,200 );       /*  Line with a 2 pixel gap */
     getch();
     _setcolor(4);
     _floodfill( 100, 210, 2); /* Fill the circle with a solid color */
     getch();

     _setfillmask( fill );     /*  Fill circle with a pattern  */
     _setcolor(2);
     _ellipse( _GBORDER, 350, 100, 550, 300 );
     getch();
     _moveto( 350, 200 );
     _lineto( 548, 200 );      /*  Line with a 2 pixel gap */
     getch();
     _setcolor(4);
     _floodfill( 400, 210, 2); /*  Fill half of the circle with a pattern */

 /*  _floodfill( 400, 180, 2);   This _floodfill() will fill in the other */
 /*                              half of the circle with a pattern.       */
      getch();
     _setvideomode( _DEFAULTMODE );

 }


 950. C1001: Internal Compiler Error: grammar.c:1.138, Line 164

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 S_QuickC
 Last Modified: 24-OCT-1990    ArticleIdent: Q65641

 The sample program shown below will generate the following error when
 compiled with Microsoft C version 6.00, with or without optimizations:

    bar.c(6) : fatal error C1001: Internal Compiler Error
                (compiler file '@(#)grammar.c:1.138', line 164)
                Contact Microsoft Product Support Services

 The following error is generated by the QuickC version 2.50 compiler
 when it tries to compile the same code:

    bar.c(6) : fatal error C1001: Internal Compiler Error
                (compiler file 'gencode.c', line 437)
                Contact Microsoft Product Support Services

 Sample Code:
 ------------

 char foo[7];
 float test;

 void bar(void)
 {
   test+=foo;
 }

 The above program is incorrect because it is attempting to do
 arithmetic on incompatible types, a float and an address. If you
 correct this inconsistency then the program will compile.

 Microsoft has confirmed this to be a problem with C version 6.00 and
 QuickC version 2.50. We are researching this problem and will post new
 information here as it becomes available.


 951. getcwd() and _getdcwd Return Backslash for Root Requests

 Product Version(s): 5.x 6.00 | 5.x 6.00
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER | buglist6.00 s_quickc
 Last Modified: 24-OCT-1990    ArticleIdent: Q65642

 The Microsoft C version 6.00 library functions getcwd() and _getdcwd()
 will append a backslash to the drive specification for requests made
 from a drive's root directory.

 General requests made to the getcwd() or _getdcwd() function will not
 place a final backslash after the directory name. For example, when
 called from c:\dos\foo\ the return value of getcwd() will be
 c:\dos\foo. However, when invoked from a drive's root directory, the
 backslash character is appended (for example, when called from d:\ the
 return value is d:\). This inconsistent behavior can cause problems
 when programs append a backslash followed by a filename to the return
 of getcwd() in order to create data files in the current working
 directories. In these cases it is important to check for the root
 directory condition, in which case a backslash need not be appended.

 The following code demonstrates the possible conflict; it will fail
 when the default directory is a drive's root directory:

 Sample Code
 -----------

 #include<stdio.h>
 #include<stdlib.h>
 #include<direct.h>
 #include<string.h>

 void main(void)
 {
    FILE *fp;
    char buffer[_MAX_DIR+13];
    if (getcwd(buffer,_MAX_DIR)==NULL)
       perror("getcwd error");
    else
    {
       strcat(buffer,"\\test.dat");
       if((fp=fopen(buffer,"w"))!=NULL)
          fputs("hello",fp);
       else
          puts("failure in writing to current drive\n");
    }
 }
 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 952. Use of Ternary Conditional Operator with a Constant

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65645

 The following use of the ternary conditional operator (?) should
 convert the integer 2 into a float to match the 3.00. However, because
 the constant 1 is used instead of a variable, the conversion is never
 done. Instead of 2.0 (float), 2 (integer) is passed to printf() and
 instead of printing 2.000000, the program prints 0.000000.

 Sample Code
 -----------

 #include <stdio.h>

 double x;

 void main (void)
 {
    x= 5.5;
    printf ("%f\n", 1?2:3.00);
 }

 According to the ANSI Standard, if the second and third operands to a
 conditional operator are arithmetic types, the usual arithmetic
 conversions are performed to make them a common type. (See Section
 3.3.15, Lines 6-10). In this case, they should both evaluate to
 floats.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 953. /Zg Prototypes Unsigned Functions as Unsigned Short

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS |
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q65646

 Using the /Zg option on the following code, the compiler will
 generate a function prototype for func() that returns an unsigned
 short. This is by design and is not a problem if the code is to be
 compiled on a machine where ints and short ints are the same size.

 Sample Code
 -----------

 unsigned func(void)
 {
    unsigned b = 1;
    printf("Hello World\n);
    return (b);
 }

 The code generates the following prototype:

    unsigned short func (void);

 Both unsigned and unsigned int specify the same data type; unsigned is
 a shortened name for unsigned int. Likewise, unsigned short is another
 name for unsigned short int. In the Microsoft C 6.00 implementation,
 unsigned/unsigned int and unsigned short/unsigned short int specify
 compatible data types.


 954. Warning C4035 When Compiling with /Zg and Either /W3 or /W4

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q65647

 Compiling with a combination of /Zg and either /W3 or /W4 on the
 code below produces the following warning:

    test.c(4) : warning C4035: 'func' : no return value

 Sample Code
 -----------

 1: int func(void)
 2: {
 3:     return(1);
 4: }

 The compiler generates the warning only when these options are used
 together. Microsoft has confirmed this to be a problem in C version
 6.00. We are researching this problem and will post new information
 here as it becomes available.


 955. Fatal Error C1002: Out of Heap Space in Pass 2

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 24-SEP-1990    ArticleIdent: Q65702

 Fatal error c1002 is produced when pass 2 of the compiler (C2.EXE) can
 find no more memory available to store information that is needed to
 continue compiling. This information typically consists of defined
 variables, function names, and temporary information used when
 evaluating complex expressions. Information used for optimizing may
 even use dynamic memory, which can cause this error to occur.

 One of the following may be a solution:

 1. Divide the source file into smaller source files. This provides
    many advantages, including the following:

    a. It reduces compiling time for small changes in a program.

    b. It allows the functions to be separated from the program so they
       may be used by other programs.

    c. The .OBJs may be placed into a library.

    d. Placing code in separate files may aid in readability because
       the developer does not need to search through large files.

 2. Break complex expressions into smaller subexpressions. Using
    temporary variables for intermediate assignments is an example.
    This can also help with program readability.

 3. If using OS/2, recompile using the /B2 C2L.EXE option. This invokes
    the high-capacity compiler (C2L.EXE) on the second pass of the
    compiler. C2L.EXE may cause a longer compiling time and should not
    be used if not needed.

 4. If running any TSRs (terminate-and-stay-resident programs) or
    device drivers, try removing these to free more memory. The
    compiler does not take advantage of extended or expanded memory, so
    try to free as much of the 640K conventional memory as possible.

 5. If using NMAKE, MAKE, or other program building utilities, try
    compiling without them. These programs reside in memory when your
    compiler is invoked. If using DOS, try running NMK.COM rather than
    NMAKE.EXE. (Refer to the online help for differences between
    NMK.COM and NMAKE.EXE.)

 6. Observe the compiling options. Change these to see if these have
    any affect. For example, disable optimizations with /Od if
    optimizing is currently enabled.


 956. Invalid Offset Generated for jmp After In-Line Assembly

 Product Version(s): 6.00    | 6.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified: 24-SEP-1990    ArticleIdent: Q65743

 The Microsoft C version 6.00 compiler can generate incorrect offsets
 for jmp instructions following the termination of in-line assembly
 blocks in certain situations.

 The sample code below will generate the incorrect offset for the
 return statement following the termination of its in-line assembly
 block. The only known workaround is to compile with the /qc option,
 thus invoking the quick compiler.

 If the optimize pragma is removed from this code, it will generate the
 following error with any command-line optimization switch.

    fatal error C1001: Internal Compiler Error
    (compiler file '@(#)main.c:1.176', line 807)
    Contact Microsoft Product Support Services

 Sample Code
 -----------

 #pragma optimize("",off)

 #include<stdio.h>

 long double asin(long double f_in)
 {
     _asm
     {
         fld      f_in
         fld      st
         fmul     st,st
         fld1
         fcom     st(1)
         fstsw    ax
         sahf
         jc       toobig
         fsubr
         fsqrt
 /*      fxch     st(1)  uncomment for acos */
         fpatan
         jmp      done
 toobig:
         fstp     st
         fstp     st
         fabs
         fchs
         fsqrt
 done:
         fstp     f_in
      }
      return f_in;
 }

 main()
 {
     char s[200];
     long double f_in,f_out;
     f_in=0.0;
     while(gets(s)!=NULL)
     {
         if (sscanf(s,"%Lf",&f_in)==1)
         {
            f_out=asin(f_in);
            printf("in %Lf asin %Lf\n",f_in,f_out);
         }
     }
     exit(0);
 }

 The following is incorrect code generated as viewed from within
 CodeView's mixed source/assembly mode (compiled with cl /Od /Zi
 file.c):

 29:         fstp     f_in
 0047:004C 9B             WAIT
 0047:004D DB7E04         FSTP      TByte Ptr [BP+04]
 30:          }
 31:          return f_in;
 0047:0050 9B             WAIT
 0047:0051 DB6E04         FLD       TByte Ptr [BP+04]
 0047:0054 9B             WAIT
 0047:0055 D9C0           FLD       ST(0)    ; different from below
 0047:0057 9B             WAIT
 0047:0058 DDD9           FSTP      ST(1)    ; perhaps repetitive
 0047:005A 90             NOP
 0047:005B 9B             WAIT
 0047:005C E9FAFF         JMP       0059 ;notice incorrect offset here
 32:     }
 0047:005F 5E             POP       SI
 0047:0060 5F             POP       DI
 0047:0061 8BE5           MOV       SP,BP
 0047:0063 5D             POP       BP
 0047:0064 C3             RET
 33:

 The following is correct code (compiled with cl /qc /Od /Zi file.c):

 0047:004C 9B             WAIT
 0047:004D DB7E04         FSTP      TByte Ptr [BP+04]
 30:          }
 31:          return f_in;
 0047:0050 9B             WAIT
 0047:0051 DB6E04         FLD       TByte Ptr [BP+04]
 0047:0054 90             NOP
 0047:0055 9B             WAIT
 0047:0056 E90000         JMP       0059              ; offset correct here
 32:     }
 0047:0059 5F             POP       DI
 0047:005A 5E             POP       SI
 0047:005B 8BE5           MOV       SP,BP
 0047:005D 5D             POP       BP
 0047:005E C3             RET
 33:

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 957. C 6.00 Fails to Generate Symbolic Info for ELSE IF Statement

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00, S_CodeView
 Last Modified: 16-OCT-1990    ArticleIdent: Q65744

 The following code, when compiled with Microsoft C version 6.00 for
 CodeView debugging, does not stop at breakpoints placed on the ELSE IF
 line of code. Also, any attempt to step onto the line using the trace
 or step command will skip over this line as if no executable code was
 associated with it.

 Sample Code
 -----------

 /* compile line = cl /Zi /Od file.c */

 void main(void)
 {
    int i=100;

    if (i==2);
    else if(i==7);  /* cannot stop on this line */
 }

 As can be seen by switching into mixed source/assembly mode, there is
 executable code associated with the ELSE IF statement. And, if a
 breakpoint is placed on one of the assembly instructions associated
 with the ELSE IF line, execution will be able to stop on that
 instruction demonstrating that the code is being executed.

 The following are two possible workarounds to this problem:

 1. Compile with the quick compiler, which generates the correct
    symbolic information (for example, cl /qc /Zi /Od file.c).

 2. Put the ELSE and IF on separate source lines, as follows:

       ELSE
            IF(i==7);

 This method allows stepping through the IF statement.


 958. C 6.00 Optimization Pops Too Much Off Stack in Some Situations

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q66051

 In certain situations involving the passing of structures to a
 function, Microsoft C version 6.00's optimizations can cause too many
 bytes to be popped off the stack in preparation for the function call.
 In addition, the actual structure can be placed on the stack
 incorrectly. Currently, the only workaround is to compile without any
 optimizations.

 The following code demonstrates the problem. When compiled in Large or
 Compact model (/AL or /AC) with even default optimizations enabled,
 too many bytes are popped off the stack as is demonstrated by the
 extracts from the .COD files reproduced below.

 Microsoft has confirmed this to be a problem in Microsoft C version
 6.00. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 #include<stdio.h>

 #define EDGE 1
 typedef struct _point_
    {
       double x;
       double y;
    } _point;

 typedef struct _window_
    {
       _point min_scale;
       _point max_scale;
       struct _window_ *data_windows_list;
       struct _window_ *current_data_window;
       struct _window_ *next_window;
    } _window;

 typedef struct _display_
    {
       _point min_scale;
       _point max_scale;
       _window *current_window;
       _window *windows_list;
    } _display;

 int d_edge_window (_display *display);
 int d_edge_window_1(_display *display);
 int d_rectangle(_display *display, _point corner_1,
                 _point corner_2,int fill);

 int d_rectangle(_display *display,_point corner_1,
                        _point corner_2,int fill)
 {
   printf("%lf %lf %lf %lf %lf %lf %d \n",
              display->min_scale.x,display->min_scale,
              corner_1.x,corner_1.y,corner_2.x,corner_2.y,fill);
 }

 void main(void)
 {
    _window moo;
    _display goo;

    goo.min_scale.x=1.1;
    goo.min_scale.y=2.2;
    goo.max_scale.x=3.3;
    goo.max_scale.y=4.4;
    goo.current_window=&moo;
    goo.windows_list=&moo;

    moo.data_windows_list=&moo;
    moo.current_data_window=&moo;
    moo.next_window=&moo;
    moo.min_scale.x=5.5;
    moo.min_scale.y=6.6;
    moo.max_scale.x=7.7;
    moo.max_scale.y=8.8;

    d_edge_window(&goo);
    d_edge_window_1(&goo);
 }

 int d_edge_window(_display *display)
 {
    d_rectangle(display,display->current_window->min_scale,
                         display->current_window->max_scale,EDGE);
    return 0;
 }

 int d_edge_window_1 (_display *display)
 {
    d_rectangle(display,display->min_scale,display->max_scale,EDGE);
    return 0;
 }

 Partial .COD Listing
 --------------------

 ;   display = 6
 ;|***   d_rectangle(display,display->current_window->min_scale,
 ;|***               display->current_window->max_scale,EDGE);
 ; Line 64
     *** 000005  6a 01        push 1         ; push EDGE on stack
     *** 000007  c4 5e 06     les  bx,DWORD PTR [bp+6]    ;display
     *** 00000a  26 8b 47 20  mov  ax,WORD PTR es:[bx+32]
     *** 00000e  26 8b 57 22  mov  dx,WORD PTR es:[bx+34]
     *** 000012  8b c8        mov  cx,ax
     *** 000014  8b f2        mov  si,dx
     *** 000016  05 10 00     add  ax,16
     *** 000019  8b f9        mov  di,cx
     *** 00001b  83 ec 10     sub  sp,16 ; make room for max_scale
     *** 00001e  57           push di
     *** 00001f  56           push si
     *** 000020  1e           push ds
     *** 000021  8b f0        mov  si,ax
     *** 000023  8b fc        mov  di,sp
     *** 000025  83 c7 0c     add  di,12 ; should be add di,6
     *** 000028  16           push ss
     *** 000029  07           pop  es
     *** 00002a  8e da        mov  ds,dx
     ASSUME DS: NOTHING
     *** 00002c  b9 08 00     mov  cx,8
     *** 00002f  f3           rep
     *** 000030  a5           movsw      ; copy max_scale to stack
     *** 000031  1f           pop  ds
     ASSUME DS: DGROUP
     *** 000032  07           pop  es    ; es shouldn't be popped
     *** 000033  5e           pop  si
     *** 000034  5f           pop  di
     *** 000035  83 ec 10     sub  sp,16 ; make room for min_scale
     *** 000038  06           push es    ; rest has been thrown off
     *** 000039  1e           push ds
     *** 00003a  56           push si
     *** 00003b  8b f7        mov  si,di
     *** 00003d  8b fc        mov  di,sp
     *** 00003f  83 c7 08     add  di,8
     *** 000042  16           push ss
     *** 000043  07           pop  es
     *** 000044  1f           pop  ds
     ASSUME DS: DGROUP
     *** 000045  b9 08 00     mov  cx,8
     *** 000048  f3           rep
     *** 000049  a5           movsw
     *** 00004a  1f           pop  ds
     ASSUME DS: DGROUP
     *** 00004b  07           pop  es
     *** 00004c  06           push es
     *** 00004d  53           push bx
     *** 00004e  9a 00 00 00 00  call  FAR PTR _d_rectangle
     *** 000053  83 c4 26     add  sp,38
 ;|***   return 0;


 959. fflush() and flushall() Do Not Write Data Directly to Disk

 Product Version(s): 5.00 5.10 6.00 6.00a | 5.00 5.10 6.00 6.00a
 Operating System:   MS-DOS               | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q66052

 The C run-time functions fflush() and flushall() do not write files to
 disk. These functions only flush the file buffers internal to a C
 program; they do not affect the flushing of DOS or OS/2 system-level
 buffers. For example, if fflush() is used but DOS does not write its
 own buffers to disk before a system crash (or equivalent event),
 information may still be lost.

 One solution to this problem is to use the DOS "Commit file" function
 if you are running under DOS version 3.30 or later. This will force
 DOS to flush the buffer associated with a file handle to disk. To
 accomplish this, do the following:

 1. Use the fflush() or flushall() function to flush the C run-time
    buffer(s) for the file(s) to be committed to disk.

 2. Use the fileno() function to get the handle(s) associated with the
    file(s). This is necessary because DOS deals with file handles, not
    streams.

 3. Execute an INT 21h, function 68h call. This may be done using
    inline assembly, the int86() function, or the intdos() function.
    Regardless of the method used to issue the INT 21h call, the
    following registers need to be set to the specified values:

       AH = 68h
       BX = <file handle>

 Remember that this function is available only in MS-DOS versions 3.30
 and later. For MS-DOS versions earlier than 3.30, you must close the
 file in order for the buffers to be committed to disk. For more
 information on this and other DOS functions, see the book "MS-DOS
 Functions," published by Microsoft Press.

 To perform the same function under OS/2, there are two separate API
 calls depending on the version of OS/2. For 16-bit OS/2 (versions
 1.x), use the DosBufReset() API function. For 32-bit OS/2 (version
 2.00), use the DosResetBuffer() function.


 960. fputs() Fails with R6003 When Writing to STDAUX

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 24-OCT-1990    ArticleIdent: Q66053

 The fputs() run-time library function will fail with the following
 error when you try to put a string to STDAUX:

    run-time error R6003
    - integer divide by 0

 Microsoft has confirmed this to be a problem in Microsoft C versions
 6.00 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.

 The following code demonstrates this error when compiled with the
 default options:

 #include <stdio.h>
 void main (void)
 {
    fputs("hello world\n", stdaux);
 }

 The fputs() function should have disabled buffering when dealing with
 STDAUX, but it doesn't. To work around this problem, you can disable
 buffering yourself by calling the setvbuf() function as follows:

    setvbuf(stdaux, NULL, _IONBF, 0);

 The following code works correctly:

 #include <stdio.h>
 void main (void)
 {
    setvbuf(stdaux, NULL, _IONBF, 0);
    fputs("hello world\n", stdaux);
 }


 961. Use of _far Keyword in Tiny Programs

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 17-DEC-1990    ArticleIdent: Q66104
 A tiny memory model program cannot have _far code. The following
 documentation taken from online help is incorrect because it is not
 possible to use the _far keyword with code addresses or static data
 addresses in a tiny program. It is also not possible to use the _huge
 keyword with static data addresses.

    The tiny-model option creates a program with the .COM extension.
    The program contains a single segment for both code and data. Code
    and data combined are limited to 64K.

    Both code and data items are accessed with near addresses. You can
    override the defaults with the _far keyword for code and the _far
    or _huge keyword for data.

 The _far keyword does override the near addresses correctly, but the
 linker will generate the following error message because a .COM file
 cannot have segment references:

    LINK : fatal error L1127: far segment references not allowed with
    /TINY

 It is possible to use _far and _huge keywords to create pointers for
 use with dynamic memory or to set up pointers with absolute addresses,
 such as a pointer to video memory. This is because these pointers do
 not have segment values that depend on where the program is loaded in
 memory. A .EXE file contains a table of all segment references that
 are made by the program in its header. When the program is loaded, all
 segment values in the table are adjusted for the programs load
 location. Because .COM files do not have this header information, they
 cannot contain segment references.

 No Microsoft graphics library routines can be used when generating
 .COM files because they are all compiled as far calls.


 962. Code Generation Error with /Gs

 Product Version(s): 6.00  6.00a | 6.00 6.00a
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 22-OCT-1990    ArticleIdent: Q66105

 When the sample code shown below is compiled with stack checking
 disabled (/Gs) and default optimizations, the compiler generates
 incorrect code.

 The following code/assembly listing shows that the stack frame is
 never initialized upon entry to the function. In other words, the base
 pointer, BP, is not pushed onto the stack and the stack pointer, SP,
 is not moved into BP.

 However, the procedure continues to reference BP to access the
 parameters passed to the function. Furthermore, at the end of the
 assembly procedure, the stack frame is restored; the value of BP is
 moved into SP and BP is popped off the stack.

 Turning off default optimizations (/Od) or rearranging portions of the
 code causes the stack frame to be initialized upon entry to the
 function.

 Sample Code
 -----------

 struct foo {
      int i;
 };

 unsigned u;
 char ch;
 void func(char);

 unsigned test(struct foo *a[], int *x, int y)
 {
      struct foo *tmp;

      u=(ch << 8);
      func(ch);

      *x=y;
      tmp=a[y];
 }

 Partial .COD listing
 --------------------

 Note: The program is compiled with the following: cl /c /Gs /Fc program.c

 _test     PROC NEAR
                                      ; no stack frame set up

      *** 000000     56        push si
 ;    tmp = -2
 ;    y = 8
 ;    x = 6
 ;    a = 4

      .
      .
      .

 ;|***      *x=y;
 ;|***      tmp=a[y];
 ; Line 17
      *** 000013     8b 5e 08  mov  bx,WORD PTR [bp+8] ;y  *uses bp*
      *** 000016     8b 76 06  mov  si,WORD PTR [bp+6] ;x
      *** 000019     89 1c          mov  WORD PTR [si],bx
 ;|*** }
 ; Line 18
      *** 00001b     5e        pop  si
      *** 00001c     8b e5     mov  sp,bp    ; un-does the stack
      *** 00001e     5d        pop  bp       ; frame it never set up
      *** 00001f     c3        ret

 _test     ENDP

 Microsoft has confirmed this to be a problem with the C compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.


 963. Using _psp for Pointer Checking

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 17-OCT-1990    ArticleIdent: Q66127

 Problem:

 I want to implement my own pointer checking routine. If the psp
 (program segment prefix) is set up in the lowest segment of available
 memory, then I should be able to use _psp as the lower bounds for
 legal pointer segments. However, if I write a program that compares
 _psp with pointer segments returned by malloc(), I get back segment
 values less than _psp.

 Response:

 When DOS loads an .EXE or .COM file, the psp is set up in the lowest
 segment of the largest contiguous block of available memory. There may
 be other blocks of available memory below the location of the psp;
 these blocks of memory are usually fairly small. If DOS returns one of
 these segments, when pointer checking is implemented with the /Zr
 option (available only with the /qc compiler option), the segment is
 simply discarded and DOS is called again. This process is repeated
 until a segment value greater than _psp is returned.

 You can implement a similar routine in any C program by making calls
 to a function, as demonstrated below, rather than making calls
 directly to malloc(). However, the start-up code still will make calls
 to malloc() directly for environment and argument space. Thus, the
 pointer segments for the environment and arguments may still be less
 than _psp. Further, it should be noted that this routine does not
 implement pointer checking; it only enables programmers to implement
 their own pointer checking by comparing segment values against _psp.

 Another method of getting only pointer segments greater than _psp is
 to modify the start-up code so that the value of _psp is stored at
 _aseglo. This is the actual location used to store the lower segment
 limit when pointer checking is implemented. The code to check the
 segment returned by DOS against this location, and to call DOS again
 if necessary, is already implemented. If it is necessary to have
 pointer segments for the environment and argument variables greater
 than _psp, a similar assignment can be used to modify the start-up
 code. If this assignment is done before the space for these variables
 is allocated in the start-up code, they will have segment values
 greater than _psp. However, you should be aware that Microsoft can
 make no guarantees about the implementation of this feature in any
 future releases.

 If a call to malloc() requires a new segment to be allocated from the
 operating system, the call to DOS will be made requesting only the
 amount of memory required by the malloc(). In subsequent calls,
 requests are made for 8K blocks of memory until no more memory is
 available from that segment. Since the blocks of memory below the psp
 are small, they may not be allocated during the first calls to
 malloc(). Thus, you cannot be sure exactly when these blocks of memory
 will be allocated.

 Code Example
 ------------

 void * _new_malloc (size_t size)
   {
   void * temp_ptr;
   temp_ptr= malloc (size);
   while ((temp_ptr != NULL) && (FP_SEG(temp_ptr) < _psp))
     temp_ptr= malloc (size);
   return temp_ptr;
   }


 964. Use of the shflag with sopen()

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 17-OCT-1990    ArticleIdent: Q66129

 The shflag used with the sopen() function can be one of five manifest
 constants (defined in FCNTL.H). The following lists the constants and
 their uses:

 SH_COMPAT   Sets compatibility mode. Other programs can open the file
             and perform read or write operations as long as no process
             specifies any sharing mode other than compatibility mode.
             This is the sharing mode used in the open function under
             MS-DOS. This sharing code is not available under OS/2.

 SH_DENYRW   Deny all. Other programs cannot open the file.

 SH_DENYWR   Deny write. Other programs cannot open the file in
             compatibility mode or with write access.

 SH_DENYRD   Deny read. Other program cannot open the file in
             compatibility mode or with read access.

 SH_DENYNO   Deny none. Other programs can open the file and perform
             both read and write operations but cannot open the file in
             compatibility mode. This is the sharing mode used in the
             open function under OS/2.

 In a network environment under MS-DOS, it is recommended that the
 SH_COMPAT mode be used if the file is to be shared for reading and
 writing. For further information about file modes, see the "MS-DOS
 Encyclopedia," Article 7, "File and Record Management".


 965. Must Use Parentheses with _fpreset()

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q66149

 When using the signal() function, it is necessary to call the
 _fpreset() function before calling longjmp() within the function
 referenced by signal(). If this is not done, the program will give
 unpredictable results. In the program example below, due to user error
 the loop is executed twelve times, then a pointer gets lost (caused by
 longjmp) and proceeds to hang the machine (under OS/2 you will get a
 protection violation) because the _fpreset function doesn't have
 parentheses after it.

 Even though "_fpreset" is stated within the fperror() function in the
 code example below, it is evaluated only as an expression rather than
 a function because the parentheses required to call a function are not
 included in the statement [for example, "_fpreset()"]. Therefore,
 _fpreset is evaluated but no value is assigned to it, which gives it
 the characteristics of an assembly language NOP instruction.

 If you compile this code with the default warning level, there won't
 be any warnings or indications of error, so you might think the
 compiler is generating incorrect code; in fact, if you compile the
 code on warning level 4 (/W4), you will get "warning C4205: statement
 has no effect", which indicates that the _fpreset will have no effect,
 or in other words, is going to do nothing.

 Sample Code
 -----------

 #include <signal.h>
 #include <setjmp.h>
 #include <conio.h>
 #include <stdio.h>
 #include <float.h>

 void fperror(int sig, int num);
 jmp_buf mark;

 double val, d;
 int fpe, st, k;

 void main(void)
 {
    d=0;
    signal (SIGFPE, fperror);
    while(!kbhit())
    {
       val=100;
       st=0;
       fpe=setjmp(mark);
       if(fpe==0)
       {
          printf("BEFORE /0 st = %-4d k = %-5d\n", st, k++);
          val=val/d;
          printf("NOERR val = %f st = %-4d\n", val, st);
       }
       else
       {
          printf("FPERROR val = %f st = %-4d\n", val, st);
       }
    }
 }

 void fperror(int sig, int num)
    {
       _fpreset;          /* should be "_fpreset()" */
       st=1;
       longjmp(mark,-1);
    }


 966. Internal Compiler Error: '@(#)regMD.c:1.100', Line 3837

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified: 24-OCT-1990    ArticleIdent: Q66169

 When the code below is compiled from the command line with

    cl filename.c

 it will produce the following error:

    fatal error C1001: Internal Compiler Error
    (compiler file '@(#)regMD.c:1.100', line 3837)
    Contact Microsoft Product Support Services

 Workaround
 ----------

 To work around the problem, do one of the following:

 1. Change the register value to a nonregister value.

 2. Put the quantity (x[p] + y[a]) into a temporary variable, then use
    the temporary.

 3. Compile with one or more of -Ol, -Oe, or -Og.

 4. Use the C version 6.00a update, which corrects this problem.

 A code example, which demonstrates this problem, is shown below:

 Code Example
 ------------

 #include <stdio.h>

     unsigned y[200];
     unsigned x[320];
     char buffer[0x4000];
     char far *scrn;

 void test(p)
 int p;
 {
    register a;

    buffer[ x[p] + y[a] ] = scrn[ x[p] + y[a] ];

     }

 void main(void)
 {
    int b;
    test(b);
 }


 967. \" Sequence Must Be Used to Define Strings with /D Switch

 Product Version(s): 5.10 6.00 | 5.10 6.00
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 24-OCT-1990    ArticleIdent: Q66213

 The /D compiler switch is used to define a constant value to the
 preprocessor. It is equivalent to using a #define statement in the
 source code. The C version 6.00 "Microsoft C Reference" manual gives
 the syntax as follows:

    /Did[=[value]]

 "Value" can be a number, character, or string constant such as "foo".
 In order to define a string constant, the '\"' escape sequence must be
 used. This requirement is undocumented. Please see the example shown
 below, where FOO is defined as "bar":

    cl /DFOO=\"bar\" s.c


 968. C 5.10 _setlogorg Is Replaced by _setvieworg in C 6.00

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q66214

 The Microsoft C version 5.10 _setlogorg graphics function is used to
 move the logical origin (0, 0) to the physical point (x, y). All other
 points move the same direction and distance. This function is not
 present in the C 6.00 graphics run-time library because it has been
 replaced by the _setvieworg function.

 The _setlogorg function is defined in the C 6.00 version of the
 graph.h include file. Because of this, code that was originally
 compiled under C 5.10 need not be changed before recompiling it under
 C 6.00.

 If a C 5.10 .OBJ containing a call to _setlogorg() needs to be linked
 with C 6.00 .OBJ files and libraries, you will get an unresolved
 external link error on _setlogorg. To work around this problem,
 compile the following code under C 6.00 and link it in with the other
 .OBJ files:

 #include <graph.h>

 #undef _setlogorg

 struct xycoord _far _setlogorg(short x, short y)
 {
      return(_setvieworg(x, y));
 }


 969. Loop Optimizations May Generate Bad Code on Nested Loops

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 24-OCT-1990    ArticleIdent: Q66216

 The code below illustrates a problem in using loop optimizations with
 nested loops.

 With loop optimizations disabled, the compiler calculates the value of
 x for each iteration of the loop and produces the correct result.

 When loop optimizations are turned on, the compiler initializes the
 value of x and subtracts it by 10 on each loop iteration. The problem
 occurs here with the miscalculation of x when variable i increments.

 Workaround
 ----------

 The only workaround is to compile without loop optimizations, which
 can be done in the following ways:

 1. Do not use the /Ol option.

 2. Insert the #pragma optimize statement in the code to turn off loop
    optimization for the particular function.

 Microsoft has confirmed this to be a problem in C version 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 #include<stdio.h>

 void main(void)
 {
      int i, j, x;

      for (i=0; i<2; i++)
      {
           for (j=0; j<4; j++)
           {
                x=(i*4+3-j)*10;
                printf("%d\n", x);
           }
      }
 }

 The following table demonstrates the output when the code above is
 compiled with and without loop optimizations:

    Correct Output Without /Ol     Incorrect Output with /Ol
    --------------------------     -------------------------

       30                             30
       20                             20
       10                             10
        0                              0
       70                             -10
       60                             -20
       50                             -30
       40                             -40


 970. Pascal Modifier Might Generate Bogus Warning C4059

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q66217

 In certain cases, the use of the Pascal modifier on a function will
 generate the following warning incorrectly:

    test.c(18): warning C4059: segment lost in conversion

 The following code, when compiled using "cl /W2 /c test.c" will
 generate the C4059 warning:

 Code Example
 ------------

 #include <stdio.h>

 struct s {int i,j,k,l; };

 struct s Pascal foo(void)
 {
 struct s b = {1, 2, 3, 4};

     return b;
 }

 void foobar(struct s b)
 {
     printf("%d %d %d %d\n", b.i, b.j, b.k, b.l);
 }

 void main () {
    foobar(foo());              /* this line causes warning C4059 */
 }

 This warning should not be generated for the above code. The problem
 occurs if you call a function that takes a structure as an argument
 with a procedure that returns a structure and is declared with the
 Pascal modifier, as in the above example. The problem does not occur
 with C 5.10.

 Although the warning is intended to flag a possible problem, the
 warning is not valid and the compiler generates the correct code in
 the above situation. Note that the code is incorrect only if /Au or
 /Aw are used.

 The warning goes away if you do one of the following:

 1. Compile with the /qc option. This uses the quick compiler rather
    than the full optimizing compiler.

 2. Remove the Pascal modifier from line 3.

 3. Compile in compact or large memory models (/AC or /AL).

 Microsoft has confirmed this to be a problem with C version 6.00. We
 are researching this problem and will post new information here as it
 becomes available.


 971. Possible Cause of L2029: '__aDBswpchk': Unresolved External

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-OCT-1990    ArticleIdent: Q66225

 A common cause of "L2029: '__aDBswpchk': unresolved external" is
 linking in the real mode graphics library, GRAPHICS.LIB, with an OS/2
 application. OS/2 may use the text graphics functions from Microsoft's
 library, but they must be linked with the protected mode version of
 the graphics library, GRTEXTP.LIB. The following example will compile
 and link an OS/2 application that uses text graphics functions, using
 the sample program TEXT.C from the on-line help.

    cl /Lp text.c /link grtextp.lib


 972. What _getvideoconfig() Returns for Non-Standard Adapters

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm 2.50 2.51
 Last Modified: 24-OCT-1990    ArticleIdent: Q66287

 The _getvideoconfig() run-time library function returns, among other
 things, the type of the current display adapter. The possible return
 values are documented. However, what if the adapter does not match any
 of the cards represented by the nine manifest constants defined in
 graph.h?

 When the adapter is recognized as a "superset" of an adapter that is
 supported, the value of the supported adapter is returned. For
 example, if the adapter is a Super VGA card, the value _VGA is
 returned.

 When the active adapter is completely unrecognized, the
 _getvideoconfig() function returns the least common denominator. If
 the adapter supports color, _CGA is returned; otherwise the return
 value is set to _MDPA.

 A good programming strategy to reduce device dependencies is to use
 _MAXRESMODE or _MAXCOLORMODE when calling _setvideomode, and using
 _getvideoconfig to determine what mode was actually set. There is more
 information on these topics in the Microsoft Advisor online help
 system, which comes with your C compiler package.


 973. Reference to _pgmptr in CRTEXE.OBJ Is Invalid

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q66290

 Problem:

 My program uses _pgmptr to find the pathname of the executable
 program. When I change my Build Options to "PM multithreaded EXE
 with runtime in DLL," _pgmptr contains all zeros.

 Response:

 This problem stems from the fact that while _pgmptr exists in
 CDLLOBJS.DLL, there is no reference to _pgmptr in CDLLOBJS.DEF and
 there is an invalid reference to it in CRTEXE.OBJ. Because of this,
 you are unable to access it from your program. The first problem is
 easily corrected by adding _pgmptr to the .DEF file. The second is not
 possible to correct because Microsoft does not release the source code
 to CRTEXE.OBJ.

 Workaround
 ----------

 However, there is a workaround if a DLL is used to access _pgmptr.
 Fortunately the .OBJ file that links the start-up code into the DLL
 does have the correct code to perform the function. The following code
 fragment is an example of how this is done:

 Code Example
 ------------

 In your main application, prototype a function to take the place of
 _pgmptr. For instance:

 char *DLLpgmptr(void);          // returns _pgmptr from DLL

 The function itself will be defined as follows:

 /* foo.c */

 extern char *_pgmptr;
 char *_export _loadds DLLpgmptr(void);

 char *_export _loadds DLLpgmptr(void)
 {
         return(_pgmptr);
 }

 There is also a required .DEF file that may be defined as follows:

 ; foo.def

 LIBRARY FOO INITINSTANCE
 PROTMODE
 DESCRIPTION    '_pgmptr replacement  function'
 HEAPSIZE  8192
 STACKSIZE 2048
 DATA MULTIPLE

 The compile line to make this into a DLL is as follows:

 cl /c /MD /Gs /W4 foo.c

 The link line is as follows:

 link crtdll foo.obj, foo.dll ceexample os2, foo.def;
 implib foo.lib f.dll

 Move the resulting DLL to your LIBPATH and call DLLpgmptr() wherever
 you would normally use _pgmptr, and link the library that results from
 running IMPLIB into the final .EXE.


 974. What Happens to Stack Memory When Thread Terminates?

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q66295

 Question:

 If I call _beginthread() with NULL as the second parameter, the
 run-time is supposed to create a thread stack for me. How is this
 done? Also, when the thread terminates with _endthread(), is the
 memory automatically released back to the operating system?

 Response:

 If _beginthread() is called with NULL for the thread stack, a stack of
 size stack_size (passed as the third parameter) is malloc()'ed from
 the heap. At the time the thread is terminated, the stack is still in
 use; therefore, _endthread() does not automatically free it. In fact,
 the last thing _endthread() does is push the appropriate arguments
 onto the stack and call DosExit().

 However, the memory is recovered. The next time that thread ID is
 used, _beginthread() will check to see if the thread stack had been
 previously malloc()'ed internally by the function. If so, it will call
 free() at that time. Note that the thread memory doesn't go to the
 operating system; instead, it is returned to the heap. Due to the fact
 that OS/2 will use a thread ID from terminated threads first, there
 will usually be only one thread stack not free()'ed.

 As a side note, in 32-bit OS/2, this is all a moot point. The 32-bit
 DosCreateThread() API call will automatically allocate/deallocate the
 thread stack.


 975. Errors in Chapter 16 of Advanced Programming Techniques

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 19-JAN-1991    ArticleIdent: Q66303
 Due to printing problems and proofing oversight, there are several
 documentation errors, shown in detail below, in Chapter 16 of the
 "Microsoft C Advanced Programming Techniques" manual that shipped with
 C version 6.00 and 6.00a. These errors can cause various problems if
 you are attempting to learn how to use C 6.00 to develop OS/2
 applications. Some examples of the problems are as follows:

 1. Sample code fails to compile.

 2. Sample application fails to function correctly.

 3. Running a sample application causes SYS2070 error (Unable to Demand
    Load application segment xxxxx) from the operating system.

 The following are documentation errors occurring in Chapter 16 of the
 "Microsoft C Advanced Programming Techniques" manual, and their
 corrections:

 1. Page 404; example at top of page:

       #pragma stack_check(off)

    Should be as follows:

       #pragma check_stack(off)

    Program will not compile as is.

 2. Page 404; example at top of page:

       "while (s = TargetBuff)" and "while (d = TargetBuff)"

    Both should be changed to the following:

       "while (s >= TargetBuff)" and "while (d >= TargetBuff)"

    The sample program will not function correctly as is.

 3. Page 402; middle of page (details of /ML and /MD switch).
    Page 404; bottom of page.
    Page 410; bottom of page.
    Page 412; top of page (in the paragraph at the top).
    Page 412; bottom of page (in the example).

    All define switches to the compiler should have underscores instead
    of spaces (that is, /D MT should be /D_MT, and /D DLL should be /D_DLL.

    Without this, the correct sections of the include files will not
    be used. Symptoms include incorrect program operation and link
    failure (especially obvious with floating-point math functions).

 4. Page 407; top of page.
    Page 411; bottom of page (end of Step 3).
    Page 412; bottom of page.

       All the link lines should include /NOI.

    Without this, the programs that use run-time in a DLL will likely
    fail at run-time due to name mismatch. In the SYS2070 error
    message from the OS, the function name will probably be uppercase
    with a leading underscore. The actual function name is probably
    mixed case.

 5. Page 411; top of page (end of Step 2).

    This step defines the building of the .DEF file for the
    application-specific DLL. The .DEF file should also include "DATA
    MULTIPLE." This fact was mentioned on Page 398.

    If this is not done, the program will likely run correctly until a
    second process attempts to gain access to the DLL. At that time,
    the second process will likely overwrite the run-time instance data
    from the first process.

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


 976. _setcliprgn Does Not Work Inside a _setviewport

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q66305

 There is a conflict between the _setviewport() and _setcliprgn()
 functions included in the graphics libraries in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51. The _setcliprgn() function
 should not affect the viewport coordinates, but using it after
 _setviewport() causes changes in some graphics output.

 The code below illustrates this problem. It draws an arc in the
 upper-right corner of the window and then sets the clipping region
 just inside the viewport; the program then draws the same arc again.
 The second arc is shifted to the right and changed from the previous
 arc.

 Code Example
 ------------

 #include <stdio.h>
 #include <conio.h>
 #include <graph.h>

 void main(void)
 {
     struct videoconfig vc;

     _setvideomode(_MAXRESMODE);
     _clearscreen(_GCLEARSCREEN);
     _getvideoconfig(&vc);
     _setviewport(55, 55, vc.numxpixels-55, vc.numypixels-55);
     _setwindow(1, 0.0, -10.0, 10.0, 10.0);
     _rectangle_w(_GBORDER, 0.0, -10.0, 10.0, 10.0);
     _ellipse_w(_GBORDER, 5.0, 5.0, 15.0, 15.0);
     _moveto(10,10);
     _outtext("Press any key to set a clipping region ");
     _outtext("and display the same arc...");
     getch();
     _setcliprgn(56, 56, vc.numxpixels-56, vc.numypixels-56);
     _ellipse_w(_GBORDER, 5.0, 5.0, 15.0, 15.0);
     getch();
     _setvideomode(_DEFAULTMODE);
 }

 Microsoft has confirmed this to be a problem with Microsoft C Compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.


 977. C4093 Can Be Caused by MASM-Style Comments in _asm Code

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00
 Last Modified: 24-OCT-1990    ArticleIdent: Q66310

 The C4093 (Unescaped NewLine in Character Constant in Inactive Code)
 warning message will be generated if a section of code is removed with
 the preprocessor (#if, #ifdef, etc.) and a constant spans two lines or
 is not completed. The following is an example:

 void main(void)
 {
 #ifdef foo
    printf("This is an error\n );
 #endif
 }

 However, the C4093 error can also occur in a MASM-style comment to an
 inline assembler instruction. For instance:

 void main(void)
 {
 #ifdef foo
    _asm mov ax, 10  ; "Set return code
 #endif
 }

 In this case, if the code hadn't been inactive, the line would not
 have been flagged.

 Workarounds
 -----------

 There following are two workarounds:

 1. Do not use MASM-style comments. If C-style comments (// or /* */)
    are used instead, the error is not generated.

 2. Add the closing quotation mark to the line.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 978. D2030 Compiler Error in "P3" or Machine Hangs During Compile

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 24-OCT-1990    ArticleIdent: Q66322

 When the code below is compiled under OS/2 using the Microsoft C
 version 6.00a compiler and using the following command-line switches

    cl /Gi /Od test.c

 the result is as follows:

    Command line error D2030 : INTERNAL COMPILER ERROR IN 'P3'
                  Contact Microsoft Product Support Services

 Under DOS, the system will hang during pass three of the compiler.

 Code Example
 ------------

 #include <stdio.h>
 void foo(void)
 {
      char Key;
      switch( Key = getch() ) {
            case '1' : break;
            case '2' :
            default: break;
      }
 }
 void main(void)
 {
      foo();
 }

 This error indicates that the third pass of the compiler ("P3") is
 encountering a general protection fault. This error does not occur
 under C version 6.00.

 Workaround
 ----------

 The following are three possible workarounds:

 1. Compile without the /Gi option.

 2. Compile with the /qc option.

 3. Compile with the medium or large memory model.

 Microsoft has confirmed this to be a problem with the C compiler
 version 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 979. Problem with Switch List Usage Due to Problem in PMSHL.H

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified: 24-OCT-1990    ArticleIdent: Q66341

 You may encounter a problem when trying to build an application that
 makes use of various "PM Switch List" information. The symptoms may
 include "typedef not defined" errors at compile time or "unresolved
 external reference" errors at link time.

 This problem is most likely caused by a problem with the PMSHL.H file
 that shipped with the OS/2 Presentation Manager Toolkit version 1.20
 or Microsoft C version 6.00. Because of a problem in the #ifdef logic,
 certain sections of the include file may be undefined when they are
 actually needed.

 To correct these errors, the following modifications to PMSHL.H are
 required:

 On line 286, change

    #endif  /* not INCL_NOCOMMON */

 to the following:

    #ifdef  INCL_WINSWITCHLIST

 On line 319, change

    #endif

 to the following:

    #endif  /* INCL_WINSWITCHLIST */

    #endif  /* INCL_WINSWITCHLIST or NOT INCL_NOCOMMON */

 Because another #ifdef is added, it must be resolved by adding a
 closing #endif.

 Microsoft has confirmed this to be a problem with C version 6.00. This
 problem has been corrected in the PMSHL.H include file included with
 the C 6.00a maintenance release.


 980. Uninitialized Globals in Wrong Segment in Assembly Listing

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 15-JAN-1991    ArticleIdent: Q66343

 When declaring uninitialized global data, the segments allocated to
 store this data are the FAR_BSS segment for the compact, large, and
 huge memory models and the C_COMMON segment for the small and medium
 memory models. When the /Fa or /Fc compiler switches are used to
 produce assembly listings from the C source code, the listing that is
 generated actually has the segment incorrectly allocated as just _BSS.

 Using the /Fm switch to generate a map file from the linker will show
 that the segment is in fact FAR_BSS.

 Microsoft has confirmed this to be a problem in C version 6.00. We are
 researching this problem and will post new information here as it
 becomes available.


 981. BSEDOS.H in C 6.00 Has Incorrect Prototypes

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 21-JAN-1991    ArticleIdent: Q66345

 The prototypes for DosPeekQueue() and DosFileLocks() in the BSEDOS.H
 file are incorrect.

 The fourth parameter for DosPeekQueue() is defined in the header file
 as being of type PULONG, as shown in the following:

    PULONG ppBuf

 For OS/2 versions 1.x, the fourth parameter should be as follows:

    PVOID FAR *ppBuf

 The prototype is correct as it is for OS/2 version 2.00.

 For OS/2 versions 1.x, the second and third parameters for
 DosFileLocks() are defined as being of type PLONG, and should be of
 type PFILELOCK.

 This function does not exist in OS/2 version 2.00.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 982. C1001: Internal Compiler Error: @(#)exphelp.c:1.115, Line 391

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  9-NOV-1990    ArticleIdent: Q66430

 The sample code below will produce the following internal compiler
 error when compiled with both /Oi and /Oe optimizations:

    sample.c(10) : fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)exphelp.c:1.115', line 391)
                       Contact Microsoft Product Support Services

 The following are several workarounds to this particular internal
 compiler error.

 1. Avoid using the optimizations /Oi and /Oe together.

 2. Insert the #pragma optimize statement into the code to turn off the
    offending optimizations for the particular function.

 3. Use temporary variables to simplify the expression on line 10.

 Sample Code
 -----------

 1:      #include <math.h>
 2:      void main(void)
 3:      {
 4:           double x, y, z;
 5:           struct {
 6:                   double d;
 7:           } data;
 8:
 9:           z=2.0 * x;
 10:          data.d=(2.0*x) / sqrt( pow(2.0-y,2) + pow(z,2) );
 11:     }

 Microsoft has confirmed this to be a problem in C version 6.00. This
 problem has been corrected in version 6.00a.


 983. How to Read Internal Floating-Point Function Names

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  9-NOV-1990    ArticleIdent: Q66431

 Question:

 I am looking at the .COD listing for an application compiled for
 Alternate Math using the Microsoft C version 6.00 compiler. While
 examining the generated code, I noticed that several functions are
 called in order to perform the floating-point calculations in my code.
 What does each function do?

 Response:

 The functions you see in the code perform a task similar to the 80x87
 instructions that would be needed for the same situation. Therefore,
 it is fairly easy to determine what the name of each function means
 and what the function does.

 Each name is composed of fields similar to the following

    __a(far/near call)(segment)(operation)(data type)(reverse/pop)

 where

    (far/near call) is either "F" or "N". This specifies that the
                    altmath helper is called either far or near.

    (segment)       is "f", "s", or "e". If the altmath helper
                    needs an argument, the compiler will set BX to
                    point to the argument. If the altmath routine
                    has an "f" in its segment field, then DS:BX points
                    to the argument. "s" means that SS:BX points to
                    the argument and "e" means ES:BX. If no argument
                    is needed, then "f" is used. (For example, __aNfadd
                    doesn't need an argument but instead uses st(0)
                    and st(1) off of the altmath stack, just like the
                    "fadd" 80x87 instruction.)

    (operation)     is similar to the 80x87 instructions. "add",
                    "sub", "mul", "div", "ld" (load to altmath stack),
                    and "st" (store from stack).

    (data type)     is one of the following:

                       "s" for single precision or float.
                       "d" for double precision or double.
                       "w" for word or 16 bit integer.
                       "l" for long or 32 bit integer.
                       "q" for qword or 64 bit integer.
                       ''  for no data type needed.

                    This field is used only when bx points to an
                    argument.

    (reverse/pop)   is "p", "r" or ''. In most cases, it is not
                    used. If the operation was a "st" (store), then a
                    "p" at the end means to pop the stack after the
                    store. If the operation was div or sub, then an
                    "r" means to do the reverse version of the
                    operation.

 So, __aNfadds is a near called routine that will add the top of the
 altmath stack st(0) with the float (single precision) in DS:BX. This
 is similar to "fadd  dword ptr ds:[bx]" in 80x87 code.


 984. VioWrtTTy should be VioWrtTTY in the APT

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 11-NOV-1990    ArticleIdent: Q66457

 On Page 352 of the Microsoft C "Advanced Programming Techniques,"
 there is a typographical error in the list of Family API Functions for
 the last function listed. The function is incorrectly listed as
 VioWrtTTy, and should be VioWrtTTY.


 985. Pascal 4.00 and C 6.00 Mixed Language Considerations

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_pascal
 Last Modified: 19-JAN-1991    ArticleIdent: Q66458

 To link objects created with Microsoft Pascal version 4.00 and
 Microsoft C version 6.00 or 6.00a into the same executable, certain
 objects must be removed from the standard Pascal library. If these
 objects are not removed, the linker error "L2025: symbol defined more
 than once" will occur on several symbols. These symbols are listed
 below.

 The following LIB command will remove the proper objects from the
 Pascal library. LIB will create a backup of the original library
 called LIBPASE.BAK. You will want to keep this backup copy for
 straight Pascal linking.

    lib libpase -crt0 -nmalloc -fmalloc -amalloc -pnmsize;

 When linking, the /NOD and /NOE switches must be used on the link
 command line, and the C libraries must be listed before the Pascal,
 for example:

    link /NOD /NOE c.obj pascal.obj,test.exe,,mlibce libpase;

 Following is a list of errors that will occur if an attempt is made to
 link without removing the necessary objects from the Pascal library:

    libpase.lib(nmalloc.asm) : error L2025: __nfree :
        symbol defined more than once
    libpase.lib(nmalloc.asm) : error L2025: __nmalloc :
        symbol defined more than once
    libpase.lib(amalloc.asm) : error L2025: __amblksiz :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __aexit_rtn :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __acmdln :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __asizds :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __astart :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __atopsp :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __acfinfo :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __aenvseg :
         symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __cintDIV :
        symbol defined more than once
    libpase.lib(os2\crt0.asm) : error L2025: __amsg_exit :
        symbol defined more than once

 This procedure described above is necessary because the newer
 libraries that shipped with C 6.00 use different start-up and memory
 handling routines. Because the routines in the Pascal libraries will
 not work correctly with the C 6.00 libraries, the objects must be
 removed. Remember when building your application to compile the C code
 with /AM, /AL, or /AH because the Pascal code will require far
 function calls.


 986. Error: Cannot Open Response File : "

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-NOV-1990    ArticleIdent: Q66506

 When compiling and linking in one step with C 6.00, the following
 message may occur during linking:

    Cannot open response file : ""

 The above error message is created when an older version of the linker
 is being found in the search path. Specifically, if linker version
 3.05 is being executed, this error will occur.

 Check your DOS utilities directory, or any other directory specified
 with the PATH command, for an older version of the LINK.EXE file.


 987. -Aw/-Au Uses Wrong Segment When Passing Pascal Function Return

 Product Version(s): 6.00 6.00a  | 6.00 6.00a
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  9-NOV-1990    ArticleIdent: Q66508

 When compiling for DS!=SS (-Au or -Aw) and when passing the return
 value of a Pascal function that returns a structure to another
 function, the compiler will use the BX register for accessing the
 returned structure without an SS override. (Memory accesses default to
 the DS register unless the BP or SP register is involved in the
 address calculation, in which case SS is the default.)

 The compiler does correctly issue the following warning in this
 situation:

    test.c(18): warning C4059: segment lost in conversion

 Code Example
 ------------

 #include <stdio.h>

 struct s {int i,j,k,l; };

 struct s pascal foo(void)
 {
 struct s b = {1, 2, 3, 4};

     return b;
 }

 void foobar(struct s b)
 {
     printf("%d %d %d %d\n", b.i, b.j, b.k, b.l);
 }

 void main () {
    foobar(foo());       /* this line causes warning C4059 */
 }

 The problem is shown in the following excerpt of the .COD (/Fc)
 listing. Note the structure was returned on the stack, not in DGROUP.
 Without /Au or /Aw, this is acceptable because the stack is IN DGROUP.
 However, when /Au or /Aw is used, this will cause the words to be
 read from the wrong segment.

 ;| |***    foobar(foo());         /* this line causes warning C4059 */
 ; Line 18
    *** 00006d      8d 46 f8                lea     ax,WORD PTR [bp-8]
    *** 000070      50                      push    ax
    *** 000071      e8 8c ff                call    FOO
    *** 000074      8b d8                   mov     bx,ax
    *** 000076      ff 77 06                push    WORD PTR [bx+6]
    *** 000079      ff 77 04                push    WORD PTR [bx+4]
    *** 00007c      ff 77 02                push    WORD PTR [bx+2]
    *** 00007f      ff 37                   push    WORD PTR [bx]
    *** 000081      e8 c0 ff                call    _foobar


 988. Unable to Create a File Larger Than 32MB with DOS 4.x

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC S_MASM appnote PATCH32M.ARC
 Last Modified: 11-NOV-1990    ArticleIdent: Q66514

 Question:

 I am creating a database program and I cannot create files larger than
 32 megabytes (MB). Doesn't Microsoft's C compiler allow me to do this?

 Response:

 The problem isn't with the C compiler but with the operating system.
 Microsoft has confirmed that MS-DOS versions 4.00 and 4.01 do not work
 correctly when accessing files that are close to or larger than 32MB
 in size. The file size does not get updated past 32MB.

 Microsoft has produced a patch program, PATCH32M.EXE, for DOS versions
 4.x, which corrects this problem by modifying the MSDOS.SYS (or
 IBMDOS.COM) file on your system disk. This patch is found in the
 Software/Data Library or it can be obtained by calling Microsoft
 Product Support.
 PATCH32M can be found in the Software/Data Library by searching for
 the keyword PATCH32M, the Q number of this article, or S12506.
 PATCH32M was archived using the PKware file-compression utility.


 989. C 6.00 SAMPLES.DOC Omits CHRTOPT.C in CHARTDEMO Files List

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 24-JAN-1991    ArticleIdent: Q66573

 The SAMPLES.DOC file that came with the Microsoft C version 6.00
 compiler package contains a list of files required to make the
 CHRTDEMO sample application. The file fails to mention that CHRTOPT.C
 is required also.

 The SAMPLES.DOC file reads as follows:

    CHRTDEMO.MAK       CHRTDEMO illustrates presentation graphics
    CHRTDEMO.C         techniques. You can use this program as a tool
    CHRTSUPT.C         for testing different modes and options before
    CHRTDEMO.H         building them into your own programs. Real mode
                       only.

 It should read as follows:

    CHRTDEMO.MAK       CHRTDEMO illustrates presentation graphics
    CHRTDEMO.C         techniques. You can use this program as a tool
    CHRTSUPT.C         for testing different modes and options before
    CHRTOPT.C          building them into your own programs. Real mode
    CHRTDEMO.H         only.


 990. Multithreaded Version of strtok() in C 6.00 Can Cause GP Fault

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified: 21-JAN-1991    ArticleIdent: Q66575

 In certain cases, using the multithreaded version of the strtok()
 function from Microsoft C version 6.00 can cause a General Protection
 fault. This problem has been identified and corrected in the C version
 6.00a maintenance release.

 Sample Code
 -----------

 #define INCL_DOS
 #include <os2.h>
 #include <conio.h>
 #include <process.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>

 void StartThread(char *pszFileName);
 void ThreadProc(char *pszFileName);

 void main(void)
  {
   StartThread("THREAD01.TXT");
   StartThread("THREAD02.TXT");
   StartThread("THREAD03.TXT");
   StartThread("THREAD04.TXT");
   StartThread("THREAD05.TXT");
   while(!kbhit());
  }

 void StartThread(char *pszFileName)
  {
   int ThreadID;

   ThreadID = _beginthread(ThreadProc,
                            NULL,
                            8192,
                            pszFileName);
   if(ThreadID == -1)
              printf("Couldn't Start Thread for '%s'\n", pszFileName);
  }

 void ThreadProc(char *pszFileName)
 {
    FILE *Input, *Output;
    char Line[256], *t, OutFileName[16];

    Input = fopen(pszFileName, "rt");
    if(Input == NULL)
    {
       printf("%.3d: Error Opening Input File - '%s'\n",
                  *_threadid, pszFileName);
       _endthread();
    }
    sprintf(OutFileName, "THREAD%.2d.OUT", atoi(&pszFileName[6]));

    Output = fopen(OutFileName, "w");
    if(Output == NULL)
    {
       printf("%.3d: Error Opening Output File - '%s'\n",
                 *_threadid, OutFileName);
       fclose(Input);
       _endthread();
    }
    while(fgets(Line, sizeof(Line), Input))
    {
       Line[strlen(Line)-1] = '\0';

       fprintf(Output, "%.3d: Input Line: '%s'\n", *_threadid, Line);

       for(t = strtok(Line, " \n\r");
            t != NULL; t = strtok(NULL, " \n\r"))
          fprintf(Output, "%.3d:  Token: '%s'\n", *_threadid, t);

       fprintf(Output, "\n");
    }
    fclose(Input);
    fprintf(Output, "\n%.3d: Going to sleep\n", *_threadid);
    fclose(Output);
    DosSleep(10000L);
    _endthread();
 }


 991. Compiler Incorrectly Generates 80186+ Code

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 11-NOV-1990    ArticleIdent: Q66697

 The sample code below incorrectly generates the instruction "shl bx,
 2" for 8086/8088 machines when compiled with the large or compact
 memory model (/AL or /AC). When using an 8086/8088 machine, the only
 valid second operands are cl and 1. The ability to use an immediate
 value other than 1 was not available until the 80186.

 Sample Code
 -----------

 extern int bar (double *,double *, double *, double *,
                 int, int, void *, int, char, int);

 void foo (double *, double *, double *, double *,
                 int, int, int, int, int, int);

 #define RESET 0x02

 void foo (double * dPtr1, double *dPtr2, double *dPtr3,
           double * dPtr4, int i1, int i2, int i3, int i4,
           int i5, int i6)
 {
    double **ldPtrPtr;

    bar(dPtr1, dPtr2, dPtr3, dPtr4, i4, i1, &ldPtrPtr[i4][i1],
        RESET, RESET, i6);
 }


 992. Program Crashes If Run on a Machine Without an 80x87

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  9-NOV-1990    ArticleIdent: Q66578

 Question:

 I have a multithreaded application that I developed on a system with
 an 80x87 coprocessor. Everything is working properly; however, when I
 try to run the code on a machine that doesn't have a coprocessor, it
 always fails with a General Protection fault. I have tried all
 variations of the run-time library (LLIBCMT.LIB and CDLLOBJS.LIB) to
 no avail. Is there a problem with using the multithreaded run-time
 libraries on a machine without a coprocessor?

 Response:

 There is no problem with using the multithreaded run-time libraries on
 a machine without a coprocessor.

 The problem is probably caused by not using _beginthread() to start
 the threads that perform the floating point calculations. If you use
 DosCreateThread() to start the thread, there is required
 initialization code that is not performed in the run-time for that
 thread; this is mandatory because 80x87 emulation is performed in the
 run-time in cases where there is no coprocessor.


 993. C4059 Warning May Be Caused by Errors in OS2DEF.H and PMWIN.H

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 24-JAN-1991    ArticleIdent: Q66645

 Using the header files shipped with the OS/2 Toolkit version 1.20, and
 compiling the sample code below with /AL, the compiler will issue a
 C4059 error message on lines 8 and 9. This error is caused by the way
 these two macros are defined. If the following changes are made, the
 error will go away:

 1. In OS2DEF.H, change

       #define LOUSHORT(l) ((USHORT)(l))

    to the following:

       #define LOUSHORT(l) ((USHORT)(ULONG)(l))

 2. In PMWIN.H, change

       #define CHAR1FROMMP(mp) ((UCHAR)(mp))

    to the following:

       #define CHAR1FROMMP(mp) ((UCHAR)(ULONG)(mp))

 The first change has already been made to the include files that
 shipped with Microsoft C version 6.00; the second change has not been
 made. Microsoft has confirmed this to be a problem with C version 6.00
 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.

 Sample Code
 -----------

  1. #include <os2def.h>
  2. #include <pmwin.h>
  3. void test(MPARAM mp1);
  4. void test(MPARAM mp1)
  5. {
  6.     USHORT i;
  7.     UCHAR  c;
  8.     i=LOUSHORT(mp1);
  9.     c=CHAR1FROMMP(mp1);
 10. }


 994. Compiler Hangs If Array of Voids Is Initialized

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  1-NOV-1990    ArticleIdent: Q66648

 If the sample code below is compiled with the Microsoft C version 6.00
 compiler, under any optimization or memory model, it will hang the
 computer after generating a C2182 warning message.

 Microsoft has confirmed this to be a problem with C version 6.00. This
 problem has been corrected in the C 6.00a maintenance release.

 The C2182 warning is defined as follows:

    'identifier' : has type void

     The given variable was declared with the void keyword. The void
     keyword can be used only in function declarations.

 Sample Code
 -----------

 void buf[] = { 1, 2 };

 void main (void)
 {
    return;
 }


 995. _far16 Generated by Mistake for Huge with /Zg

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  1-NOV-1990    ArticleIdent: Q66651

 If the /Zg switch is used with the Microsoft C version 6.00 compiler,
 it will erroneously generate _far16 where huge is required.

 Microsoft has confirmed this to be a problem with the C version 6.00
 compiler. This problem has been corrected in the version 6.00a
 maintenance release.

 The /Zg switch causes the compiler to generate prototypes for all the
 functions in the module. If a function is declared as

    char huge * foo( char huge *){}

 the compiler will generate the following prototype:

    char _far16 * foo (char _far16 *);

 Upon subsequent compiling with the generated prototype, the compiler
 will fail with various syntax errors because _far16 is an unknown
 keyword.


 996. Redirecting Standard Input Does Not Affect getch() Under OS/2

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified: 11-NOV-1990    ArticleIdent: Q66700

 Redirecting STDIN (standard input) in the OS/2 environment does not
 change the behavior of the getch() function; it will continue to read
 from the keyboard. This is different from the DOS environment where
 redirecting STDIN also causes getch() to be redirected.

 The getchar() function could be used instead because it reads from
 standard input and will conform with redirection under OS/2. However,
 if standard input is not redirected, you will have to press ENTER
 after each character typed in. This can be nuisance when the program
 does not know if input will be redirected or not.

 A simple workaround is to use the FAPI function DosQHandType to
 determine if standard input has been redirected or not. The program
 can then call either getch() or getchar(), accordingly. The following
 sample code illustrates the workaround:

 Sample Code
 -----------

 #define INCL_VIO
 #include<os2.h>
 #include<conio.h>

 void main(void)
 {
    USHORT fsType, usDeviceAttr;

    DosQHandType(0, &fsType, &usDeviceAttr);

    if(LOBYTE(fsType) == HANDTYPE_DEVICE)
    {
       /* Standard input is not redirected. */
       /* Use getch() for input.            */
    }
    else if(LOBYTE(fsType) == HANDTYPE_FILE)
    {
       /* Standard input is redirected to a file. */
       /* Use getchar() for input.                */
    }
 }


 997. C 6.00/6.00a Online Help Example for _heapwalk() Is Incorrect

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr _heapwalk
 Last Modified: 28-JAN-1991    ArticleIdent: Q66703

 The program example HEAPWALK.C that is found in the C versions 6.00
 and 6.00a online help is incorrect. Compiling the program under large
 model in OS/2 causes a general protection error. When compiling the
 program without the Quick Compile option (/qc) turned on, the
 following warning message will appear twice:

    Warning c4061: long/short mismatch in argument: conversion supplied

 This warning message is cause by the failure to type cast the
 following statement

    heapdump(254);

 to the following:

    heapdump((char)254);

 The second "for" loop in the program causes the general protection
 fault. The variable "i" is not initialized to the correct value. The
 code currently reads as follows:

    for( ; i >= 0; i-- )
    {
       free( p[i] );
       printf("Deallocating %u at %Fp\n",
                _msize( p[i] ), (void _far *)p[i]);
    }

 It should read as follows:

    for( i=9; i >= 0; i-- )    // <--- THIS LINE HAS BEEN CHANGED.
    {
       free( p[i] );
       printf( "Deallocating %u at %Fp\n",
               _msize( p[i] ), (void _far *)p[i] );
    }

 The problem with the loop is that the value of i is equal to 10 when
 the loop begins; it should be 9.


 998. Results Unpredictable with Multiple va_arg() in Parameter List

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 15-JAN-1991    ArticleIdent: Q66738

 Because the order of expression evaluation is not always defined in C,
 certain behavior depends strictly on the particular C implementation.
 This is demonstrated by the sample program below, which shows the
 unpredictable values passed to a function when the va_arg() macro is
 used more than once in a function parameter list.

 Sample Code
 -----------

 #include<stdio.h>
 #include<stdarg.h>

 void foo(int, ...);

 void main(void)
 {
      foo(1, 2, 3, 4);
 }

 void foo(int first, ...)
 {
      va_list arg_ptr;
      va_start(arg_ptr, first);

      printf("%d %d %d %d\n",first, va_arg(arg_ptr, int),
                                    va_arg(arg_ptr, int),
                                    va_arg(arg_ptr, int));
 }

 When compiled under C version 5.10, the output is as follows:

    1 4 3 2

 When compiled under C version 6.00 or C 6.00a, the output is as
 follows:

    1 4 4 4

 The va_arg() macro provides a way to access the arguments of a
 function when the function takes a variable number of arguments. The
 va_arg() macro returns a variable parameter by referencing the pointer
 (arg_ptr) to the list of arguments and then increments this pointer to
 point to the next variable argument. Thus, the values passed to the
 printf() function in the above example depend on the order in which
 the va_arg() macros are evaluated.

 However, the C language does not guarantee the evaluation order of
 most expressions, so code should never be written in a way that
 depends on the evaluation order within an expression to proceed in a
 particular manner. The output of the sample code above demonstrates
 the undefined behavior and the unwanted side effects that may result
 from this type of code just from compiling it under different versions
 of the compiler.

 To preserve the original order of the arguments in the sample above,
 the va_arg() macro must be used only once in a single expression. One
 method is to use a loop to call the va_arg() macro once every
 iteration. The loop will process the variable arguments one by one and
 stop when the last parameter is reached. This can be done by passing
 an additional parameter as a flag to the function foo.

 The following is a corrected version of the program where the
 expressions are independent of evaluation order:

 Corrected Sample Code
 ---------------------

 #include<stdio.h>
 #include<stdarg.h>

 void foo(int, ...);

 void main(void)
 {
      foo(1, 2, 3, 4, -1);     /* using -1 as a flag */
 }

 void foo(int first, ...)
 {
      int temp;
      va_list arg_ptr;
      va_start(arg_ptr, first);

      temp=first;
      while(temp != -1)        /* test for flag -1 */
      {
           printf("%d ", temp);
           temp=va_arg(arg_ptr, int);
      }
 }

 The output is as follows:

     1 2 3 4


 999. Based Variable EXTRN Directive Wrongly Located in ASM Listing

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a _based
 Last Modified: 10-NOV-1990    ArticleIdent: Q66773

 The Microsoft C Optimizing Compiler provides options for generating
 assembly language listings from C source files. In cases where based
 allocation is used, the assembly language listings produced with /Fa
 (.ASM files) and /Fc (.COD files) contain an error. The EXTRN
 directive emitted for based variables is located in the wrong place.

 The EXTRN directive for a based variable should be located between the
 SEGMENT and ENDS directives for the segment in which the variable is
 declared to reside. This allows MASM to generate the correct fixups
 for references to this variable, which in turn enables LINK to detect
 whether the variable is actually defined in the specified segment.

 To workaround this problem, edit the .ASM or .COD listing so that the
 EXTRN directives for based variables are located between the correct
 SEGMENT and ENDS directives.

 Note that this problem also occurs for functions specified in an
 alloc_text pragma.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1000. _wrapon() Function Will Prevent Text Windows From Scrolling

 Product Version(s): 5.10 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified:  9-NOV-1990    ArticleIdent: Q66774

 A text window filled with characters will normally scroll when a
 character is placed into the last position in the lower-right corner
 of the window. You can use the _wrapon() function to prevent the
 window text from scrolling while still allowing a character to be
 placed in the last position.

 Functions, such as _outtext(), are designed such that the current
 cursor location is one character PAST the last output position. Thus,
 when the cursor is turned on, it blinks just past the most recently
 written character.

 Note, This assumes that you are using text mode. In graphics mode [or
 with _outgtext()], this is not a problem.

 In the case where text wrap is enabled and a character is written to
 the last position of a line, the cursor must blink on the first
 position of the next line. On the last line of a window, this will
 will cause a scroll. The workaround for situations such as this is to
 turn off text wrap while drawing the last character, which is why
 _wrapon() is provided.

 The _wrapon() function accepts either of two parameters: _GWRAPON or
 _GWRAPOFF. _GWRAPOFF is the parameter that is needed in this case. The
 sample code below demonstrates this problem and the use of _wrapon()
 to correct it.

 Sample Code
 -----------

 #include <stdio.h>
 #include <ctype.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <conio.h>
 #include <string.h>

 void main(void)
 {
    int i, response;
    char ch[11];

    _clearscreen( _GCLEARSCREEN );
    printf("\n\nDo you want text wrap on? (y/n)");
    response = getch();
    if ( _toupper(response) == 'Y' )
       _wrapon( _GWRAPON );
    else
       _wrapon( _GWRAPOFF );

    // Label screen grid for easy reference

    _clearscreen( _GCLEARSCREEN );
    _outtext( "123456789" );
    for( i = 2; i <= 9; i++ )
    {
       _settextposition( i, 1 );
       _outtext( itoa( i, ch, 10 ) );
    }

    // Set a text window and fill all but last line

    _settextwindow( 3, 3, 9, 9 );
    for( i = 1; i <= 6; i++ )
    {
       _settextposition( i, 1 );
       memset( ch, i+'0', 10 );
       _outmem( ch, 7 );
    }

    // Fill last line, all but last character

    _settextposition( i, 1 );
    memset( ch, i + '0', 10 );
    _outmem( ch, 6 );
    getch();

    // Fill last character in window -- the entire window will scroll
    //   if text wrap was specified

    _outmem( ch, 1 );
    getch();
    _clearscreen( _GCLEARSCREEN );
 }

 Note: This program utilizes the _outmem() function, which did not
 exist in the C version 5.10 or QuickC 2.00 libraries. To build this
 program with either of these compilers, the program must be rewritten
 without the _outmem() function.


 1001. Global Unsized Array May Result in L2029: Unresolved External

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 5.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC S_LINK
 Last Modified: 10-NOV-1990    ArticleIdent: Q66775

 A globally declared unsized array in Microsoft C is considered to be
 an external declaration. A module with this type of declaration must
 be linked with another .OBJ that contains a declaration for the same
 global array, which includes the size, or an "L2029: unresolved
 external" error will result during linking.

 Because a global unsized array declaration is considered external, the
 C compiler has no way of determining whether the unspecified size was
 intentional or a programming error; therefore, no compiler error
 message is generated. If it is an error, it will be detected only at
 link time. The following code demonstrates this problem:

    int foo[];

    void main(void)
    {
    }

 If this code is compiled and linked, the following error will be
 generated at link time:

    error L2029: '_foo' : unresolved external

 However, if a separate object module that declares foo with a size
 (for example, "int foo[2]") is linked in with the above code, no LINK
 error will be generated.

 This behavior is expected and will occur with all Microsoft C and
 QuickC compilers.


 1002. No Warning for Redeclared Parameter on Old-Style Declarations

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 10-NOV-1990    ArticleIdent: Q66776

 In situations where the so-called "old-style" or "K&R-type" function
 declarations are used, the C compiler will not generate a warning when
 formal parameters are declared twice, even if they are redeclared with
 different types. This is expected behavior because one of the
 declarations is ignored when this type of function declaration is
 used. If ANSI-style, prototyped function declarations are used, a
 warning will be generated for any redeclarations.

 The following code sample demonstrates this redeclaration problem:

    int func1(x, y)
    int x;
    long y;
    float x;       /* x is redeclared here, but no warning is given */
    {
       return (int)(x + y);
    }

 Even when this code is compiled at warning level 4 (/W4), the
 redeclaration of x does not generate any warnings -- the compiler only
 warns that func1() is using an old-style function declarator.

 Microsoft is committed to the ANSI standard and no diagnostic-message
 changes are planned to accommodate inconsistencies arising from use of
 the old declaration style. The ANSI specification, in section 3.9.5,
 page 96, states the following:

    The use of function definitions with separate parameter identifier
    and declaration lists (not prototype-format parameter type and
    identifier declarators) is an obsolescent feature.


 1003. Formal Parameter Cannot Be Based on Previous Formal Parameter

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 26-NOV-1990    ArticleIdent: Q66777

 Based pointers and variables are introduced in Microsoft C version
 6.00. One limitation of based addressing is that a formal parameter to
 a function cannot be based on a previous formal parameter to the same
 function. For example, the compiler will generate an error for the
 following function definition, which has two formal parameters with
 the second parameter based on the first:

    void foo( _segment myseg, int _based(myseg) *bptr )
    {
    }

 The first parameter (myseg) is of type segment, while the second is a
 based pointer to an integer (bptr) that is based on the myseg. If
 these same variable declarations are not part of a formal parameter
 list, they will compile without problem, but the above function will
 generate the following compiler error for the based variable:

    error C2065: 'myseg' : undefined

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and buglist2.51).
 We are researching this problem and will post new information here as
 it becomes available.


 1004. Error Messages May Say "short" Instead of "enum"

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 26-NOV-1990    ArticleIdent: Q66778

 Because an enumerated type is handled internally the same as a short
 type, certain Microsoft C compiler error messages may refer to a
 "short" even though the error involves an "enum". The following sample
 code contains an error to demonstrate this situation:

    enum {A, B, C}      /* missing ';' at end */
    double y;

 When the above code is compiled with the Microsoft C or QuickC
 compiler, the following error message is generated:

    error C2139: type following 'short' is illegal

 In this particular case, the error should say

    type following 'enum' is illegal"

 but the compiler does not keep track of whether or not an item was
 specified as an enum.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and
 buglist2.51). We are researching this problem and will post new
 information here as it becomes available.


 1005. PG Chart Displays May Have Uneven Spacing Between Bars

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 14-JAN-1991    ArticleIdent: Q66779

 If a large number of bars or pie slices are displayed in a
 Presentation Graphics chart, the spacing between the bars or pie
 slices may be inconsistent. In most situations, any variation between
 the sizes of bar separations is minimal and generally unnoticeable.
 The sample program below demonstrates this problem on a bar, column,
 and pie chart.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.

 Sample Code
 -----------

 #include <conio.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <string.h>
 #include <pgchart.h>

 #define COUNTRIES 25

 float _far value[COUNTRIES] = { 18.9F,  7.7F, 42.5F, 14.3F, 35.2F,
                                 21.3F, 42.5F, 14.3F, 35.2F, 21.3F,
                                 42.5F, 14.3F, 35.2F, 21.3F, 32.6F,
                                 42.5F, 14.3F, 35.2F, 21.3F, 32.6F,
                                 42.5F, 14.3F, 35.2F, 21.3F, 32.6F };
 char _far *category[COUNTRIES] = { "AB","YZ","UR","GD","USA","UK",
                                    "UR","GD","USA","UK","UR","GD",
                                    "USA","UK","Other","UR","GD",
                                    "USA","UK","Other","UR","GD",
                                    "USA","UK","Other" };
 short _far explode[COUNTRIES] = { 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
                                   1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1,
                                   1, 1, 1 };

 void main(void)
 {
    chartenv env;

    if( !_setvideomode( _MAXRESMODE ) )
            exit( 1 );

    _pg_initchart();              // Initialize chart system

    // Single-series bar chart

    _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
    strcpy( env.maintitle.title, "Widget Production" );
    _pg_chart( &env, category, value, COUNTRIES );
    getch();
    _clearscreen( _GCLEARSCREEN );

    // Single-series column chart

    _pg_defaultchart( &env, _PG_COLUMNCHART, _PG_PLAINBARS );
    strcpy( env.maintitle.title, "Widget Production" );
    _pg_chart( &env, category, value, COUNTRIES );
    getch();
    _clearscreen( _GCLEARSCREEN );

    // Pie chart

    _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );
    strcpy( env.maintitle.title, "Widget Production" );
    _pg_chartpie( &env, category, value, explode, COUNTRIES );
    getch();

    _setvideomode( _DEFAULTMODE );
 }


 1006. _fullpath() Changes Some Arguments to Uppercase

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 14-JAN-1991    ArticleIdent: Q66780

 In certain situations, the _fullpath() function may capitalize a
 portion of the file specification that it returns. If _fullpath() is
 called with a lowercase drive letter and an incomplete path
 specification, then the returned "full" path will have an uppercase
 drive letter and any portion of the full path not specified in the
 call will be returned in uppercase.

 If _fullpath() is called with a complete path specification, then the
 path returned from the function will match the case of the argument
 passed to it on a character-per-character basis. If _fullpath() is
 called with a relative or partial path specification, then every part
 of the path filled in by _fullpath() will be in uppercase and the
 drive letter will be changed to uppercase regardless of the case used
 in the argument.

 The following examples demonstrate these situations. Assume that drive
 D contains a subdirectory called WORK, which has a subdirectory called
 TEST. In addition, assume that the TEST directory contains a file
 called FILE.C and that D:\WORK\TEST is the current directory:

    If _fullpath() Is
    Called with the            Then it Will Return
    Following:                 the Following:
    ------------------         -------------------

    d:\work\test\file.c         d:\work\test\file.c
    d:\WORK\test\FILE.C         d:\WORK\test\FILE.C
    file.c                      D:\WORK\TEST\file.c
    d:file.c                    D:\WORK\TEST\file.c
    ..\test\file.c              D:\WORK\test\file.c
    d:                          D:\WORK\TEST
    d:\                         d:\

 Notice that everything except the drive letter specified in the
 argument to _fullpath() retains its case, while the information
 supplied by _fullpath() is uppercase.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and buglist2.51).
 We are researching this problem and will post new information here as
 it becomes available.


 1007. Header Files Do Not Contain Prototypes for C_INIT and C_TERM

 Product Version(s): 5.10 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 10-NOV-1990    ArticleIdent: Q66781

 The standard header files shipped with the Microsoft C compilers do
 not contain prototypes for the functions C_INIT() and C_TERM(). These
 functions are called only in specific situations when writing DLLs;
 therefore, they were specifically left out of the header files.

 When writing DLLs with Microsoft C, you can write your own
 initialization and termination routines to override the default
 initialization and termination. (This procedure is documented on pages
 395-397 of the "Advanced Programming Techniques" manual shipped with C
 6.00.) To do this, you must make a call in your code to the functions
 C_INIT() and C_TERM(), respectively.

 Because these functions are not prototyped anywhere, you must include
 your own prototypes to guarantee the correct calling conventions for
 these functions and to avoid unresolved external errors when linking.
 The correct prototypes are as follows:

    void _far _pascal C_INIT( void );
    void _far _pascal C_TERM( void );

 Note that _far and _pascal must be specified without the underscore if
 you are using C version 5.10.


 1008. Fastcalls (/Gr) Incompatible with Disabled MS Extensions (/Za)

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a _fastcall
 Last Modified: 15-NOV-1990    ArticleIdent: Q66782

 The Microsoft C versions 6.00 and C 6.00a compiler options /Za and /Gr
 are not currently compatible. /Gr enables the register calling
 convention for passing function parameters in registers, and /Za
 disables Microsoft-specific extensions to the C language. In C 6.00
 and C 6.00a, the register calling convention relies on Microsoft
 extensions being enabled (/Ze).

 If you try to specify both /Gr and /Za, the compiler will halt with
 the following error:

    Command line error D2020 : -Gr option requires extended
    keywords to be enabled (-Ze)

 Removal of this limitation is being considered for a future release of
 the C compiler.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1009. _floodfill() May Not Stop at the Correct Boundary Color

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 14-JAN-1991    ArticleIdent: Q66783

 The _floodfill() function takes a parameter that specifies the color
 of the boundary at which flood-filling should stop. In certain cases,
 the filling will stop at an incorrect boundary.

 A situation where _floodfill() may fill incorrectly is if a screen
 consists of two horizontal lines of the same color with one line near
 the top of the screen and the other near the bottom. The problem
 occurs if _floodfill() is then called with a start position at the
 middle of the screen between these lines and the filling color is the
 same as the lines, while the boundary color specified is something
 else.

 Because the fill color is different from the boundary color, the
 filling should cover the entire screen because there is no boundary to
 stop it. However, in actuality the filling stops when it reaches the
 horizontal lines. The sample program below demonstrates this problem.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and in QuickC versions 2.00, 2.01, 2.50, and 2.51. We are
 researching this problem and will post new information here as it
 becomes available.

 Sample Code
 -----------

 #include <graph.h>
 #include <conio.h>

 void main(void)
 {
    _setvideomode( _ERESCOLOR );
    _setcolor( 5 );

    _moveto( 0, 100 );
    _lineto( 640, 100 );
    _moveto( 0, 300 );
    _lineto( 640, 300 );

    _floodfill( 320, 200, 7 );
    getch();
    _setvideomode( _DEFAULTMODE );
 }


 1010. Nesting for-loops Too Deep Gives C1026: Parser Stack OverFlow

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 10-NOV-1990    ArticleIdent: Q66784

 The Microsoft C Compiler versions 5.10, 6.00, and C 6.00a are limited
 in the number of levels deep allowed for nested for-loops. Attempts to
 nest for-loops too deep will result in the error "C1026: parser stack
 overflow, please simplify your program."

 There is no specific limit to the nesting level because the parser
 stack capacity depends on the actual contents of the code, but the
 overflow generally occurs with for-loop nesting about 10 to 15 levels
 deep. This is an arbitrary limit and it will be increased in the
 future to ensure compatibility with the 15 nesting-level minimum
 specified in the ANSI specification.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 1011. Extended ASCII Characters on CGA Card

 Product Version(s): 5.10 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist5.10 buglist6.00 buglist6.00a s_quickc
 Last Modified:  9-NOV-1990    ArticleIdent: Q66785

 The _outtext() function from the graphics library will not display
 extended ASCII characters on a CGA adapter while in graphics mode
 (_MRESNOCOLOR, _MRES4COLOR, _HRESBW). The _outtext() function will
 display characters with values greater than 128 on VGA adapters in all
 display modes. However, _outtext() will only display shaded blocks for
 these characters on CGA systems working in the above mentioned
 graphics modes.

 Microsoft has confirmed this to be a problem in all versions of
 GRAPHICS.LIB up to and including the version that shipped with
 Microsoft C version 6.00a and Microsoft Quick C versions 2.50 and
 2.51. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 #include <conio.h>
 #include <graph.h>

 void PrintItOut (void);
 void main(void);

 char buf1 [65];
 char buf2 [65];
 char buf3 [65];

 void main(void)
 {
    int i;

    for( i = 0; i < 64; i++ )
    {
       buf1[i]= (char) 32+i;
       buf2[i]= (char) 96+i;
       buf2[i]= (char) 160+i;
    }
    buf1[i]= 0;
    buf2[i]= 0;
    buf3[i]= 0;

    _setvideomode( _MRES4COLOR);

    PrintItOut();

    _setvideomode( _MRESNOCOLOR);

    PrintItOut();

    _setvideomode( _HRESBW);

    PrintItOut();

    _setvideomode( _DEFAULTMODE);
 }
 void PrintItOut (void)
 {
    _clearscreen( _GCLEARSCREEN );
    _setbkcolor( 0 );
    _settextposition( 3, 1 );
    _settextcolor( 15 );
    _outtext( buf1 );
    _outtext( buf2 );
    _outtext( buf3 );

    getch();
 }


 1012. Does /ND Override /Aw?

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-NOV-1990    ArticleIdent: Q66841

 Question:

 I have two separate modules to an application that I compile with
 /Alfw and /ND. The documentation states that /Aw will assume SS!=DS
 and DS is not loaded. However, when I examine the assembler output
 (/Fc or /Fa), I see that DS is loaded for each function in the modules
 compiled with /ND. Is this a problem in the compiler? Does /ND
 override /Aw?

 Response:

 You are confusing the functionality of these two switches. The /Aw
 switch is used by the compiler to determine if local variables
 (typically stack based) can be based on DS, as well as SS. Take the
 case where a variable needs to be copied from local data to global
 data, which would normally include a couple of MOV instructions. If
 the compiler can assume DS=SS, it can generate a LEA instruction on
 the stack-based variable and set up ES:DI with the destination. DS
 will already be set to the correct value. If DS != SS, the compiler
 will have to generate more code to correctly access the stack-based
 variable.

 Now, for the /ND switch. In this case, the data segment for the module
 is not the default segment. The compiler will do an explicit DS load
 at function entry point because of just this fact, that is, there is
 no way for the compiler to know that DS is properly set to the
 nonstandard segment name (not DGROUP). While this behavior is indeed
 the same behavior as the _loadds keyword, it has nothing to do with
 the main reason for /Aw (DS!=SS).

 To summarize, the /Aw switch doesn't cause the segment load, but it
 also doesn't stop it. This is one case where one switch (/ND) can
 override one of the effects of another switch (/Aw). However, the main
 effect of the /Aw switch is not changed (don't assume DS = SS).


 1013. R6012 Caused by Error in strtok() and strpbrk() Example

 Product Version(s): 6.00a 6.00 | 6.00a 6.00
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 23-JAN-1991    ArticleIdent: Q66922

 The online help example for strtok(), strpbrk(), strcspn(), and
 strspn() contains an error in the code. When compiled with pointer
 checking turned on in small or medium model and run, the following
 error occurs:

    run-time error R6012
    - illegal near-pointer use

 The error can be eliminated by changing the pointer incrementing in
 the vowel count loop from post-increment to pre-increment. For
 example, change.

    /* Count vowels. */
    p = string;
    count = 0;
    do
    {
       p = strpbrk( p, vowels );
       count++;
    } while( *(p++) );

 to the following:

    /* Count vowels. */
    p = string;
    count = 0;
    do
    {
       p = strpbrk( p, vowels );
       count++;
    } while( *(++p) );          // <-- Change here...

 In this case, the error caught by the pointer checking routine would
 not have caused any harm because it would have failed on the last
 iteration of the loop.


 1014. _fastcall Code Generation Error with Shifted Operands

 Product Version(s): 6.00 6.00a  | 6.00 6.00a
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a fastcall
 Last Modified: 18-NOV-1990    ArticleIdent: Q66923

 When using _fastcall, shifted immediate operands may be passed
 incorrectly. In the example below, the two parameters to be passed to
 the sub1() function are stored in ax and dx (per _fastcall
 convention). Because of a problem in the compiler, the correct values
 are not used in this case. As a workaround, either use the /Os
 optimization or assign the value to a temporary variable and pass that
 variable instead.

 Sample Code
 -----------

 #include <stdio.h>

 int _fastcall sub1(int i, int j);

 long a=0x12345678;

 void main(void)
 {
    int llama;

    printf("%x\n",(int)(a>>15));
    llama = sub1( (int)(a>>15), (int)(a>>15) );
    printf("%x\n",llama);
 }

 int _fastcall sub1(int i, int j)
 {
    printf("%x \t %x\n",i,j);
    return(i);
 }

 In all optimizations except /Os and /Od, the compiler calculates the
 right-shift value correctly but passes the high-order two bytes of the
 result instead of the low-order two bytes. When compiled with /Od, the
 generated code correctly passes one variable but not the other.
 Finally, with the /Os optimization, a helper function performs the
 shift calculation and the correct values are passed in both cases.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1015. extern _based(_segname) May Define Segment of Class CODE

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 18-NOV-1990    ArticleIdent: Q66924

 When using the _based keyword to declare data, if the data is declared
 externally, the "/Fc" listing and .OBJ file may incorrectly define the
 segment as class 'CODE'.

 Sample Code
 -----------

 // file1.c

 char _based(_segname("STORAGE")) achar1;
 extern char _based(_segname("STORAG1")) achar2;
 extern char _based(_segname("STORAG2")) achar3;
 char _based(_segname("STORAG2")) achar4;

 void main(void) {}

 // file2.c

 char _based(_segname("STORAG1")) achar2;

 The /Fc listing for file1.c declares the _based segments as follows:

 STORAGE SEGMENT WORD PUBLIC 'FAR_DATA'
 STORAG1 SEGMENT WORD PUBLIC 'CODE'
 STORAG2 SEGMENT WORD PUBLIC 'FAR_DATA'

 The .OBJ file for file1 will contain a SEGDEF (SEGment DEFinition)
 record defining STORAG1 as a class CODE segment. However, there is no
 PUBDEF (PUBlic DEFinition) record to confuse the linker. In the .OBJ
 file for file2, there is a SEGDEF record defining STORAG1 as a class
 'FAR_DATA' segment, AND a PUBDEF record for the linker to resolve the
 external reference of achar2 in file1. Therefore, although there will
 be an extra segment (of zero length) defined in the final .EXE, there
 will be no detrimental effects to this problem.

 If there is another variable defined in file1.c that is initialized
 and is also based on a named segment, the invalid SEGment DEFinition
 will not be generated by the compiler. The above example with the
 STORAG2 segment illustrates this.

 This is only a problem with the full optimizing compiler. The Quick
 Compiler (/qc option) works correctly.

 Microsoft has confirmed this to be a problem in Microsoft C version
 6.00 and 6.00A. We are researching this problem and will post new
 information here as it becomes available.


 1016. _getfontinfo and Vector Mapped Fonts

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr s_quickc
 Last Modified: 18-NOV-1990    ArticleIdent: Q66925

 _getfontinfo() is documented as returning a _fontinfo structure
 containing information including type, facename, filename, ascent,
 pixheight, pixwidth, and avgwidth about the font currently set.
 However, _getfontinfo() only reads these values from the .FON file in
 which they are stored. This can cause problems when using vector fonts
 that have been scaled by the _setfont() function because the values
 for ascent, pixheight, and avgwidth will probably be incorrect.

 Vector fonts are stored in the .FON file as a series of equations that
 can be multiplied by some scaling factor to generate fonts of
 different sizes. By default, the scale factor is 1. When
 _getfontinfo() is called, it will always return the values for ascent,
 pixheight, and avgwitch assuming the default scale factor. If the font
 is scaled to some type size other than the default (using _setfont()
 with WxHy parameters), the new values for ascent, pixheight, and
 avgwidth will need to be recalculated. The factor can be determined by
 dividing the pixheight value returned from _getfontinfo() by the Hy
 parameter passed to _setfont().


 1017. OS/2 Graphics Functions May Fail on 8514/A Display Adapter

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a 8514A
 Last Modified: 18-NOV-1990    ArticleIdent: Q67005

 The graphics functions in GRTEXTP.OBJ provided for OS/2 in Microsoft C
 version 6.00 do not properly recognize the 8514/A display adapter when
 setting video modes. This results in the inability to set the number
 of text rows to certain values.

 If the 8514/A display is set to 50-line mode, an attempt to use
 _settextrows() to set the number of rows to 43 will fail. If the
 screen is set to 25- or 43-line mode, the call to _settextrows() will
 succeed, but the screen may only be in 25-line mode.

 To view this problem, use the SORTDEMO program supplied as an example
 with the C 6.00 package. This program tries to put the screen in
 43-line mode.

 Compile SORTDEMO.C for OS/2 as described in the comments at the top of
 the file. Type MODE CO80,50 at the OS/2 command-prompt to put the
 screen in 50-line mode, then run the program. The program will cause a
 general protection violation (GP fault). If you type MODE CO80,25, the
 program will run but it will only detect CGA equivalent video, and
 therefore, will only run in 25-line mode.

 Microsoft has confirmed this to be a problem in C version 6.00. This
 problem has been corrected in C version 6.00a.


 1018. C1001: Internal Compiler Error: regMD.c:1.110, line 1017

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 18-NOV-1990    ArticleIdent: Q67006

 The sample code below will produce the following internal compiler
 error when compiled with /Oe (global register allocation) or /Ox
 optimization:

    file.c
    file.c(19) : fatal error C1001: Internal Compiler Error
                 (compiler file '@(#)regMD.c:1.110', line 1017)
                 Contact Microsoft Product Support Services

 This problem appears to be related to the multiple structure member
 assignments. To workaround this problem, simplify statements with
 structure assignments as much as possible, disable global register
 allocation by not using /Oe, or use the #optimize pragma to turn
 global register allocation off for the particular functions where
 problems occur.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 #include <stdlib.h>

 typedef struct {
                  short x0, y0, x1, y1;
                } BOX;

 typedef struct {
                  long x0, y0, x1, y1;
                } LONG_RCT;

 typedef LONG_RCT  *LONG_RCT_PTR;

 LONG_RCT_PTR compute_extent(BOX *bound)
 {
    static LONG_RCT rct;
    rct.x0 = (long) min(bound->x0, bound->x1);
    rct.y0 = (long) min(bound->y0, bound->y1);
    rct.x1 = (long) max(bound->x0, bound->x1);
    rct.y1 = (long) max(bound->y0, bound->y1);
    return(&rct);
 }


 1019. C1001: '@(#)regMD.c:1.100', Line 3101

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 18-NOV-1990    ArticleIdent: Q67031

 The sample code below produces the following internal compiler errors
 under different versions of the compiler when any of the following
 individual optimizations are used:

    /Oa /Oc /Oi /On /Op /Or /Os /Ot /Ow /Oz

 Internal Compiler Error Under C 6.00a
 -------------------------------------

 test.c(11) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)regMD.c:1.100', line 3101)
                    Contact Microsoft Product Support Services

 Internal Compiler Error Under C 6.00
 ------------------------------------

    test.c(11) : fatal error C1001: Internal Compiler Error
                       (compiler file '@(#)regMD.c:1.100', line 3074)
                       Contact Microsoft Product Support Services

 The following are three possible workarounds:

 1. Add one of the following optimizations:

       /Od /Oe /Og /Ol /Ox

 2. Do not declare the structure variables of type register.

 3. Use an if-else statement instead of the ternary operator.

 Sample Code
 -----------

 1:  void main(void)
 2:  {
 3:     struct foo {
 4:           int i;
 5:     };
 6:     int n;
 7:
 8:     register struct foo *moo, *goo;
 9:
 10:    moo=goo;
 11:    n= moo->i ? moo->i :10000;
 12: }


 1020. C1001: exphelp.c, Line 370 and regMD.c, Line 725

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 28-NOV-1990    ArticleIdent: Q67032

 Compiling the sample code below with Microsoft C versions 6.00 and
 6.00a using any combination of optimizations that have /Oe included
 will result in the following internal compiler error:

 Internal Compiler Error in C 6.00
 ---------------------------------

    foo.c(17) : fatal error C1001: Internal Compiler Error
            (compiler file '@(#)exphelp.c:1.115', line 370)
            Contact Microsoft Product Support Services

 Internal Compiler Error in C 6.00a
 ----------------------------------

    foo.c(17) : fatal error C1001: Internal Compiler Error
            (compiler file '@(#)regMD.c:1.110', line 725)
            Contact Microsoft Product Support Services

 Disabling the /Oe optimization will correct this error.

 Sample Code
 -----------

 void foo(int boo, int hoo)
 {
         int x;
         int y;
         int Foo[4];
         int Bar[4];
         int i;

         for (i=0; i<4; i++) Foo[i] = Bar[i] = i;
         if (boo)
         {
                 y = Foo[hoo];
                 x = Bar[boo];
                 Foo[x] = y;
                 Foo[hoo] = boo;
                 Bar[boo] = hoo;
         }
 }

 Microsoft has confirmed this to be a problem in Microsoft C versions
 6.00 and 6.00a. We are researching this problem and will post new
 information here as it becomes available.


 1021. C1001: Internal Compiler Error: @(#)grammer.c:1.138, Line 164

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc buglist6.00 buglist6.00a
 Last Modified: 28-NOV-1990    ArticleIdent: Q67033

 If a semicolon (;) is missing at the end of a structure, union, or
 enumerator definition, and the statement following the semicolon is a
 variable declaration of any of the unsigned types except for
 "unsigned", no compiler error is generated. However, in the sample
 code below, attempting to use this variable may result in the
 following internal compiler error:

    fatal error C1001: Internal Compiler Error
         (compiler file '@(#)grammar.c:1.138', line 164)
         Contact Microsoft Product Support Services

 Similarly, QuickC version 2.51 does not generate an error on the
 missing semicolon; however, no internal compiler error is generated
 and the program will experience unpredictable results on attempts to
 use the variable declared after the structure, union, or enumerator
 definition.

 Sample Code
 -----------

 struct foo {
      int i;
 }                    /* missing semicolon (;) */

 unsigned char c;

 void main(void)
 {
      c==0;
 }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1022. Compiler Hangs Under DOS with Long Relative Path for #include

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 18-NOV-1990    ArticleIdent: Q67034

 The DOS versions of the Microsoft C versions 6.00 and 6.00a Compilers
 cannot handle #include directives that specify files with extremely
 long path specifications. For example, if the following sample line is
 included in a C source file, the compiler will hang, requiring a
 reboot of the computer:

 #include "..\test\..\test\..\test\..\test\..\test\..\test\..\test\\
 ..\test\..\test\..\test\..\test\..\test\..\test\header.h"

 A long relative path, but not as long as the one above, may also
 result in the following compiler error:

    fatal error C1063: compiler limit: compiler stack overflow

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1023. DS Used Instead of Base Segment for Based Pointer Dereference

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 18-NOV-1990    ArticleIdent: Q67035

 There are some situations where a based pointer will be incorrectly
 dereferenced in relation to the default data segment, rather than the
 segment on which the pointer is based. This problem occurs only with
 the QuickC Compiler or when the /qc (quick compile) option is used
 with the C Optimizing Compiler.

 The sample program below demonstrates this problem. When the code is
 compiled with C versions 6.00 or 6.00a and the /qc option, the value
 returned from the function is DS:0, instead of 0:0. By eliminating the
 /qc option, the expected value is returned.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51. We are researching this
 problem and will post new information here as it becomes available.

 Sample Code
 -----------

 #include <stdio.h>
 #include <stdlib.h>

 char far *get_address(void);

 void main(void)
 {
     char far *addr;

     addr = get_address();
     printf("Address = %Fp -- Address expected = 0000:0000\n", addr);
 }

 char far *get_address(void)
 {
     _segment base = 0;

     return ( (char far *)(base:>NULL) );
 }


 1024. ANSI Spec Says Taking Address of register Array is Not Allowed

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q67036

 According to the ANSI specification, you may not explicitly or
 implicitly compute the address of an object declared with register
 storage-class. Yet, the C and QuickC compilers DO allow you to take
 the address of such an array declared with register storage-class. The
 only operator that should be allowed to be used with these types of
 arrays is sizeof.

 The sample code below should give an error according to ANSI but no
 errors or warnings are generated.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and buglist2.51).
 We are researching this problem and will post new information here as
 it becomes available.

 Sample Code
 -----------

 void main(void)
 {
     register int array[10]; /* declared w/register storage-class */
     int *ptr;

     /* According to ANSI, none of the following should be allowed */

     ptr = array;         /* implicit address computation of array */
     ptr = &array[0];     /* explicit address computation with '&' */
     ptr = array + 5;     /* computation based on address of array */
 }

 In Section 3.5.1 of the ANSI specification, there is a footnote (55)
 that includes the following information:

     ...whether or not addressable storage is actually used, the
     address of any part of an object declared with storage-class
     specifier register may not be computed, either explicitly (by
     use of the unary & operator) or implicitly (by converting an
     array name to a pointer). Thus the only operator that can be
     applied to an array with storage-class specifier register is
     sizeof.


 1025. Embedded Unnamed Structures and Unions Cannot Be Initialized

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 20-NOV-1990    ArticleIdent: Q67037

 The ability to utilize "nameless" structures and unions provides a
 convenient shorthand for referring to structures embedded in other
 structures, but the current design of the compiler does not allow
 these unnamed members to be initialized.

 Permitting initialization involves a number of ambiguities that the
 compiler does not currently track. If you attempt to initialize a
 nameless structure or union, the compiler will generate a "C2097 :
 illegal initialization" error. The sample code below demonstrates this
 limitation.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51. We are researching this
 problem and will post new information here as it becomes available.

 Sample Code
 -----------

 typedef struct _reg {
     union {
         long   eax;
         short  ax;
         };
     union {
         long   ebx;
         short  bx;
         };
     } regtype;

 regtype  foo = { {1l}, {2l} };    /* This initialization attempt
                                      generates a C2097 error     */

 void main(void)
 {
 }


 1026. Inline Assembly Won't Allow Expressions for the TYPE Operator

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 18-NOV-1990    ArticleIdent: Q67038

 The TYPE Operator in MASM returns a number that represents the type of
 an identifier or expression. With the inline assembly capability in C
 and QuickC, the TYPE operator does not have the full functionality
 that it does in MASM. In an _asm block, the TYPE operator will only
 accept an identifier -- expressions are not allowed.


 1027. /qc Option Cannot Be Combined with /Ol and register Variables

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 28-NOV-1990    ArticleIdent: Q67039

 When using either QuickC or the quick compile option (/qc) with the
 Microsoft C compiler, loop optimization (/Ol) cannot be specified for
 any functions that contain variables declared with the register
 storage-class that are referenced in an inline assembly (_asm) block.

 This combination will result in the following compiler error for any
 register variables referenced in the inline assembly code:

    error C2418: variable not in a register.

 This problem occurs because /Ol results in register variables not
 being allocated in registers, a problem that also occurs with the C
 compiler without /qc. For more information, query on the following
 words:

     C4024 and register and inline and stack

 Because the variables are not in registers, the compiler cannot handle
 register instructions that reference them in the inline assembly.
 Therefore, the C2148 error is generated. When using the C compiler
 without /qc, /Ol is prevented from causing this problem.

 To work around this problem, eliminate one of the following three
 contributing factors:

 1. Turn off loop optimization.

 -or-

 2. Do not use register variables that are referenced in an _asm block.

 -or-

 3. Compile without /qc.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC versions 2.50 and 2.51 (buglist2.50 and buglist2.51).
 We are researching this problem and will post new information here as
 it becomes available.


 1028. /Ol Causes register Variables to Be Allocated on the Stack

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 28-NOV-1990    ArticleIdent: Q67040

 In most cases, a variable declared with the register storage-class
 will not be allocated to a register if loop optimization (/Ol) is
 enabled. Instead, the compiler will place the variable on the stack.

 Only if the function contains an inline assembly (_asm) block will the
 register storage be allocated, due to the fact that inline assembly
 takes precedence over optimization. This is reflected by the following
 warning message, which is generated when /Ol is used on a function
 with an _asm block:

    warning C4204: in-line assembler precludes global optimizations

 The sample program below demonstrates both of the situations described
 above. If the program is compiled as is with /Ol, the register
 declared variable "i" will not be put in a register; it will be
 handled exactly like "j", which is not declared with register
 storage-class.

 If the line at the end of main() with the _asm block is uncommented,
 then "i" will be allocated storage in a register and the C4204 warning
 will be displayed if the warning level is set at 3 or 4 (/W3 or /W4).
 To see the difference, you can generate an assembly listing with /Fa,
 or you can compile and link the program with CodeView information and
 then view the mixed source and assembly listing in the debugger.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 int foo(void);

 void main(void)
 {
     register int i = 7;
     int          j = 9;

     while ( i < 10 ) {
        i += foo();
        j += foo();
     }

     /* Uncomment the following line to have i put in a register */
     /* _asm xor i,i */
 }

 int foo(void)
 {
    return (1);
 }



 1029. Structure Tags Visible Outside of Function Prototype Scope

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC buglist6.00 buglist6.00a
 Last Modified: 28-NOV-1990    ArticleIdent: Q67041

 The scope of an identifier in C is determined by the placement of its
 declaration. According to the ANSI specification, if an identifier's
 declarator or type specification appears within a list of parameter
 declarations in a function prototype, the identifier is said to have
 "function prototype scope." This scope terminates at the end of the
 function prototype. In the C and QuickC compilers, this scope is not
 correctly terminated for structure and union tags, and a C2025 error
 may be incorrectly generated.

 The following sample code demonstrates this problem:

 /* Compile with the /Za option */
 void main(void)
 {
     int num;
     union tag1 { int   i;
                  float f; };
     {
         void func1( float num, struct tag1 *ptr );
     }
 }

 The identifier "tag1" is a struct/union tag that does appear twice,
 but because the second instance appears in the prototype for func1(),
 it should have scope that is local to the prototype only. The same is
 true for "num".

 In section 3.1.2.1 of the ANSI specification, it states the following:

    If an outer declaration of a lexically identical identifier exists
    in the same name space, it is hidden until the current scope
    terminates, after which it again becomes visible.

 Thus, both of these identifiers should not be visible outside of the
 prototype itself. Yet, the compiler correctly allows the name "num" to
 be reused, while incorrectly generating the following error for
 "tag1":

    error C2025: 'tag1' : enum/struct/union type redefinition

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC 2.50 and 2.51 (buglist2.50 and buglist2.51). We are
 researching this problem and will post new information here as it
 becomes available.


 1030. Different Warnings May Appear Using Different Optimizations

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified:  4-JAN-1991    ArticleIdent: Q67078

 Different warning messages can appear from separate compiles of the
 same code when different optimizations are used. This is normal and
 occurs because some warnings are found only while optimizing.

 If the sample code below is compiled with /W4 (all warnings) and the
 /Os optimization (optimize for space), no warnings are found. However,
 when the code is compiled with /W4 and /Osle (optimize for size, loop,
 and global-register allocation), the following warning is generated:

    FILE.c(7) : warning C4202: unreachable code

 There are several other optimizations and code examples that will
 exhibit this same type of behavior. Once again, this is normal and
 serves to notify the developer that there MAY be a problem.

 Sample Code
 -----------

  1. #include <stdio.h>
  2.
  3. void main(void)
  4. {
  5.    goto bottom;
  6.
  7.    printf("Not used\n");    // Code that is not used
  8.
  9. bottom:printf("Hello World!");
 10. }


 1031. Error C2141 When Initializing enum Constant to -32768

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC buglist5.10 buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67079

 Although the range of values for an enum constant should be the same
 as that for signed integer constants, the Microsoft C and QuickC
 compilers do not allow a value of -32768 to be used as an initializer
 for an enum constant.

 -32767 (Ox8000) is the largest negative number that will fit into a
 16-bit signed integer. The compilers will allow this value to be used
 as an integer constant. If you try to use this value to initialize an
 enum constant, the compilers will generate the following error
 message:

     error C2141: value out of range for enum constant

 The sample program below demonstrates this limitation. Uncommenting
 the "Hex8000" line and compiling will result in the C2141 error above.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.

 Sample Code
 -----------

 #include <stdio.h>

 int MaxNegative = 1 << 15;       // -32768 : this works for int

 enum {
        Hex4000 =  1 << 14,       //  16384 : this works for enum
        Hex7FFF = (1 << 15) - 1,  //  32767 : this is ok for enum
 //     Hex8000 =  1 << 15        // -32768 : this fails for enum
      };

 void main(void)
 {
     printf("\nHex4000 = %d\n", Hex4000);
     printf("Hex7FFF = %d\n", Hex7FFF);
     printf("MaxNegative = %d\n", MaxNegative);
 }


 1032. Functions in Function Prototypes Cannot Have Typedef Arguments

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC buglist5.10 buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67080

 According to the ANSI specification, types and typedefs should both be
 able to exist interchangeably in function prototypes, and the
 Microsoft C and QuickC compilers do allow function prototypes to
 include typedefs in the parameter type list. However, the compilers do
 not allow parameters to functions or function pointers within the type
 list to have typedef'd parameters. For example, given the following
 declarations

    typedef int FirstType;
    typedef int SecondType;
    int foo( int, FirstType, int *( SecondType ) );

 the compilers have no problem with "FirstType" but they will halt with
 an error when they reach "SecondType".

 Although the syntax is correct according to ANSI, the compilers
 incorrectly generate the following error when they encounter the
 second typedef:

    error C2061: syntax error : identifier 'SecondType'

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 1033. String Constants May Be Interpreted as Trigraphs in C 6.00

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | S_QUICKC
 Last Modified: 15-JAN-1991    ArticleIdent: Q67082

 To maintain compatibility with other systems, a series of
 ANSI-mandated trigraphs have been implemented beginning with Microsoft
 C version 6.00 and Microsoft QuickC version 2.50. The addition of
 these trigraphs may require that changes be made to code that was
 previously written for other versions of C that do not support these
 codes. The code example below illustrates one such instance where this
 is necessary. The trigraphs are listed on page 424 of the Microsoft C
 "Advanced Programming Techniques" manual.

 Trigraphs are three-character combinations that are used to represent
 certain symbols in the C language that are not available in all
 character sets. For example, some keyboards or character sets do not
 have the opening and closing brace characters, "{" and "}". These
 characters are essential to writing a C program; therefore, someone
 without these characters can use the trigraphs "??<" and "??>" in
 place of the braces.

 The compiler translates the three-character trigraph combinations into
 single characters at compile time. If a sequence of characters in a
 constant string matches a trigraph pattern, the compiler will replace
 the three characters with the single corresponding character that the
 trigraph represents.

 This situation may manifest itself when using functions, such as
 _dos_findfirst(), that may use these characters in a constant to
 represent wildcard characters when doing a file search. The workaround
 is to break up the constant with double quotation marks, as shown
 below. This procedure will cause the compiler to concatenate the two
 strings without first translating the characters.

 Sample Code
 -----------

 #include <dos.h>
 #include <errno.h>
 #include <stdio.h>

 void main( void)
 {
    struct find_t fileinfo;

    /* '??-' in the following line will be replaced by a '~' */

    if( _dos_findfirst( "??-100.*", _A_NORMAL, &fileinfo) != 0)
       {
       printf( "No -100 Files Found!\n");
       return;
       }
    else
       printf( "Files Found, Program will proceed normally!\n");
 }

 To prevent the compiler from misinterpreting the "??-" character
 sequence as an unintended trigraph, you could replace the
 _dos_findfirst() line above with the following line:

    if( _dos_findfirst( "??""-100.*", _A_NORMAL, &fileinfo) != 0)

 Notice that the only difference is the double quotation marks used to
 break up the string into two substrings, thus eliminating the trigraph
 pattern.


 1034. Online Help Lists Wrong Warning Level for C4127 and C4135

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 21-NOV-1990    ArticleIdent: Q67083

 The online help for Microsoft C versions 6.00 and 6.00a lists the
 wrong warning level for compiler warnings C4127 and C4135. The help
 states that both of these are level 4 warnings, but they actually
 appear when compiling at warning level 3 (/W3).


 1035. Make Your Function Return Zero When Redefining _nullcheck()

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr S_QUICKC
 Last Modified: 18-DEC-1990    ArticleIdent: Q67084

 By default, Microsoft C checks the NULL segment before the final
 termination of a program in order to determine if a null pointer
 assignment has occurred. This check can be suppressed by defining your
 own function called _nullcheck(), which is the name of the library
 routine that is normally linked in to do the checking.

 The online help for C versions 6.00 and 6.00a and QuickC versions 2.50
 and 2.51 describes how to replace this function, but there is an error
 in the help files. The help states that you just need to declare your
 own routine "named _nullcheck that does nothing". This is not
 completely true. You actually need to make your function return a
 value of zero; otherwise, the program exit code will be set to 255.

 The following is a valid way to define the _nullcheck() function in
 your program:

     int _cdecl _nullcheck( void)
     {
         return (0);
     }


 1036. va_arg() Fails on Odd-Size Structs Packed on 1-Byte Boundaries

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | s_quickc buglist5.10 buglist6.00 buglist6.00a
 Last Modified: 19-JAN-1991    ArticleIdent: Q67086

 Because the va_arg() macro does not handle odd-sized arguments
 properly, odd-sized structures should not be passed by value to
 variable argument functions if the structures are packed on 1-byte
 boundaries. Because an even number of bytes is always put on the stack
 for each argument passed, a packed structure with an odd size will not
 be retrieved properly. Using an even packing size or passing the
 structure by reference will eliminate this problem.

 For more information on the va_arg() problem with odd-sized arguments,
 query on the following words:

    va_arg and char

 To demonstrate this problem, assume a program contains code resembling
 the following:

 #pragma pack(1)

 struct foo {
              int  x;
              char y[5];
            } oddstruct;

 If the structure "oddstruct" is passed to a function by value and that
 function takes a variable number of arguments, then accessing the
 structure from within the function with va_arg() will fail. The
 sizeof(oddstruct) is actually 7 in this case, but 8 bytes will have
 been pushed on the stack.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 1037. Spaces Between /Fe or /Fo and Filename Cause Unclear Warning

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC docerr buglist5.10 buglist6.00 buglist6.00a
 Last Modified:  4-JAN-1991    ArticleIdent: Q67087

 The /Fe and /Fo compiler options are used to name the executable file
 and the object file, respectively. These switches require that the
 name of the file immediately follows the switch with no intervening
 spaces. If one or more spaces separate the option from the filename,
 the compiler will generate one of the following unexpected warnings:

    Command line warning D4002 : ignoring unknown flag '-Fe'
    Command line warning D4002 : ignoring unknown flag '-Fo'

 This limitation is documented in the online help but the "Microsoft C
 Reference" manual does not make this clear because it shows the
 switches with a space before the filenames. In addition, these
 messages are not indicative of the true nature of the errors, implying
 instead that these options are not implemented.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 1038. STARTUP.BAT Gives Error U1073: Don't Know How to Make stdio.h

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified: 29-NOV-1990    ArticleIdent: Q67161

 When running the batch file STARTUP.BAT that comes with Microsoft C
 versions 6.00 and 6.00a, it is possible to receive the following
 error:

     U1073: don't know how to make 'stdio.h'.

 This can be caused by having more than one search path for the INCLUDE
 environment variable, as shown in the following example:

    include=c:\c600\include;c:\masm\include

 To correct the problem, only one search path should be used, as in the
 following example:

    include=c:\c600\include

 Microsoft has confirmed this to be a problem in the C Compiler
 versions 6.00 and 6.00a. We are researching this problem and will post
 new information here as it becomes available.


 1039. C 6.00a Setup with Monochrome Monitor

 Product Version(s): 6.00a   | 6.00a
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | docerr buglist6.00 buglist6.00a
 Last Modified:  4-JAN-1991    ArticleIdent: Q67162

 When using the Setup program that comes with the C version 6.00 to
 6.00a update kit on a monochrome system, the selected menu item may be
 invisible. To correct the problem, use the /mono switch as shown in
 the following example:

    setup /mono

 This switch is not documented.

 Microsoft has confirmed this to be a problem in the C Compiler version
 6.00 to 6.00a update kit Setup program. This problem does not affect
 the Setup program for any other C 6.00a package. We are researching
 this problem and will post new information here as it becomes
 available.


 1040. C1001: Internal Compiler Error: grammar.c, Line 140

 Product Version(s): 6.00a  | 6.00a
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00a
 Last Modified: 29-NOV-1990    ArticleIdent: Q67235

 Compiling the sample code below with default optimizations and a
 memory model with far data (/AL or /AC) will result in the following
 error:

    sample.c(15) : fatal error C1001: Internal Compiler Error
                   (compiler file '../grammar.c', line 140)
                   Contact Microsoft Product Support Services

 The following are valid workarounds:

 1. Compile with /Od (optimizations disabled).

 2. Use the optimize pragma to disable optimizations for the function
    in which the error occurs.

 3. Compile in the small or medium memory model.

 4. Compile with the /qc (quick compile) option.

 5. Assign the "0 - msc.a" expression to a temporary variable, and
    assign the temporary variable to msc.a on line 15.

 Sample Code
 -----------

  1: void foo(void);
  2: void sub(void);
  3:
  4: struct _msc
  5: {
  6:    long a;
  7: };
  8:
  9: extern struct _msc msc;
 10:
 11: void sub()
 12: {
 13:    msc.a = 0 - msc.a;
 14:    foo();
 15:    msc.a = 0 - msc.a;
 16: }

 Microsoft has confirmed this to be a problem in C version 6.00a. We
 are researching this problem and will post new information here as it
 becomes available.


 1041. Documentation Error in APT and Tiny Model Link Line Example

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr s_quickc
 Last Modified: 29-NOV-1990    ArticleIdent: Q67252

 As stated in the Microsoft C version 6.00 README.DOC, page 36 of the
 "Advanced Programming Techniques" manual incorrectly states that to
 link a tiny model program, you must link in CRTCOM.OBJ.

 Note: You must link with CRTCOM.LIB, not CRTCOM.OBJ.

 The link line below is an example of other requirements needed to link
 a tiny model program. These requirements include putting the
 CRTCOM.LIB file before the actual compiled .OBJ file on the link
 command line. The effect of putting this library first on the link
 line is that the entire library is linked into the output file.
 CRTCOM.LIB contains special .COM file start-up code, which is to be
 used instead of the small model start-up code in SLIBCE.LIB. This code
 must be first because CRTCOM.LIB contains the entry point for the
 program, which must be at the beginning of the file (which loads at
 100H).

 If this is not done, the following error message is produced:

    LINK : fatal error L2051: start address not equal to
           0x100 for /TINY

 Because the new executable will be named CRTCOM.COM by default, you
 should specify a new .COM name. Also, the /NOE switch is necessary
 because CRTCOM.LIB replaces the start-up code in SLIBCE.LIB.

 Link Line Example:

    link /NOE crtcom.lib test.obj,test.exe;

 As stated above, this documentation error is noted in the README.DOC
 shipped with C version 6.00.


 1042. C1001: Internal Compiler Error: codegen.x, Line 559

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist6.00 fixlist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67272

 If the sample code below is compiled with the Microsoft C Compiler
 version 6.00, using /AL and /Oe, the following internal compiler error
 will be generated:

    C1001: Internal Compiler Error
    (compiler file '@(#)codegen.x:1.148', line 559)
    Contact Microsoft Product Support Services

 This error will not be generated if the /Oe optimization is used with
 /Og and/or /Ol. Microsoft has confirmed this to be a problem in
 Microsoft C version 6.00. This problem has been corrected in Microsoft
 C version 6.00a.

 Sample Code
 -----------

 #define DB_PTERM_PTR(id)  (db_ptr[id] ? db_ptr[id] : db_swap_in(id))

 extern DBRS_PTERM *db_swap_in(int);
 extern DBRS_PTERM **db_ptr;

 typedef struct
 {
    int type;
    int factors[1];
 }  DBRS_PTERM;

 void foo(int pt_id)
 {
    int id;
    int i, j, k;

    j = 0;
    for (i=0;(id=DB_PTERM_PTR(pt_id)->factors[i]) != 0; i++)
    {
       for(k=j;k>=0;--k)
       {}
       DB_PTERM_PTR(pt_id)->factors[j++] = id;
    }
 }


 1043. Error in Installation Manual for bounds-error() Routine

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  4-DEC-1990    ArticleIdent: Q67273

 Page 58 of the Microsoft C "Installing and Using the Professional
 Development System" manual is unclear when stating that the program
 example will overwrite bounds and CodeView will catch that error. The
 program returns the following run-time error upon exiting the
 bounds_error routine, rather than when the error actually took place:

    run-time error R6012
    - illegal near-pointer use

 The manual states:

    The program runs until it reaches the "for" statement in the
    "bounds_error" function, where the array bounds are exceeded. The
    output window reports an error while a CodeView dialog box
    indicates the program has terminated.

 This statement implies that the program will fail when the bounds of
 the array are exceeded, which is not entirely true.

 The program will indeed fail in this case because the array bounds are
 exceeded, overwriting stack information in the process. However, the
 program will not fail until *after* the for loop when the
 bounds_error() function terminates. At that time, the pointer check
 function will determine that the stack has been overwritten and will
 issue the error message above.

 If the array had not been stack based (that is, global or static) and
 the stack data had not been trashed, the program would not have
 failed. However, important data may still have been lost. To trap
 overwrite errors of this nature, you could use "Bounds Checker" by
 Nu-Mega.

 Sample Code
 -----------

 void bounds_error(void)
 {
    int loop, the_num[10];
    for(loop=0;loop<15;loop++)
       the_num[loop]=loop;
 }
 void main(void)
 {
    bounds_error();
 }


 1044. Typedef and Struct Member with Same Name Give Bad C2062 Error

 Product Version(s): 5.10 6.00 6.00a | 5.10 6.00 6.00a
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | S_QUICKC buglist5.10 buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67352

 If an identifier is used both as a typedef name and as the name of a
 structure member, the compiler may incorrectly generate a C2062 error.
 This error depends on which way the identifier is first used, but it
 should not be generated in either case. According to the ANSI
 specification, using the same identifier in these two different
 contexts is perfectly acceptable.

 The following code sample demonstrates this problem. Notice that "foo"
 is used as both a typedef name and as the name of a character pointer
 in a structure:

 typedef char foo[80];

 struct stype {
               int   num;
               char *foo;
              };

 void main(void)
 { }

 When this code is compiled, the following error message is generated:

    file.c(5) : error C2062: type 'foo' unexpected

 The compiler appears to check the typedef name space when it gets to a
 structure member name, but the reverse is not true. Thus, when a name
 is used first as a typedef and later as a structure member name, the
 C2062 error is generated. On the other hand, the compiler accepts the
 code when the name is used in the structure first and later as a
 typedef name. Therefore, in the code above, reversing the positions of
 the struct and the typedef, so that the struct comes first, will allow
 the code to compile without error.

 This same exact problem may occur when building a PWB extension if
 both EXT.H and BIOS.H are included in the same source file. If EXT.H
 is included before BIOS.H, then the following error is generated:

    bios.h(77) : error C2062: type 'buffer' unexpected

 This is due to "buffer" being used as a typedef name in EXT.H and as a
 structure member name in BIOS.H. As in the example given above,
 reversing the order of the two definitions will eliminate the problem.
 So, although it is rare to use BIOS functions in a PWB extension, if
 you want to do so, just include BIOS.H before EXT.H.

 Microsoft has confirmed this to be a problem in C versions 5.10, 6.00,
 and 6.00a and QuickC versions 2.00, 2.01, 2.50, and 2.51 (buglist2.00,
 buglist2.01, buglist2.50, and buglist2.51). We are researching this
 problem and will post new information here as it becomes available.


 1045. Math Functions in LLIBCDLL May Not Return Zero on Domain Error

 Product Version(s): 6.00 6.00a
 Operating System:   OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67353

 The C run-time math routines in the statically-linked DLL library
 (LLIBCDLL.LIB) that are designed to return zero when they encounter a
 domain error may not return zero. Domain errors are detected correctly
 but the return values are incorrect in these instances because they
 should be zero.

 For example, calling the sqrt() function with an argument of -1 should
 cause a DOMAIN error and cause the return value to be zero. The
 LLIBCDLL version of sqrt() does set errno to EDOM (domain error) in
 this case, but the return value from the function is non-zero. The
 sqrt() function in the standard library xLIBCEP.LIB, the multithreaded
 library LLIBCMT.LIB, and the version that goes into a C run-time DLL
 all correctly return zero.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1046. putch() Displays Values 9 and 255 Differently in DOS and OS/2

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67354

 The putch() function will display different output for the values 9
 (tab) and 255 depending on whether you are running in DOS or OS/2.
 When passing a tab (ASCII 9) to putch() under DOS, the graphic ASCII
 character for 9 is displayed. Under OS/2, a tab is expanded out to
 actual spaces when passed to putch().

 When passing the value 255 to putch() under DOS, the value is ignored
 and nothing is displayed. Passing 255 to putch() under OS/2 results in
 a space being displayed.

 Because the cprintf() function uses putch() to display characters, the
 same differences will appear with these values when calling cprintf().

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1047. Compiler May Hang Under DOS When Using /qc and Memory Runs Out

 Product Version(s): 6.00 6.00a
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67355

 Under certain circumstances, the compiler may run out of memory when
 trying to compile a source module. In some situations, when both
 compiling under DOS and specifying the /qc option to invoke the quick
 compiler, an out-of-memory condition may result in garbage output
 being dumped to the screen, or the following error may be generated:

    fatal error C1063: compiler limit : compiler stack overflow

 Depending on the particular code being compiled and the optimizations
 specified, the C1063 error may or may not contain any error text. In
 some cases, only the error number is displayed and then the computer
 hangs before the "compiler limit" message is displayed.

 This problem has been observed only with the real-mode quick compile
 option. Simplifying the code is one way to work around the problem.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1048. C4127 Warning Message May Be Generated with Loop Optimization

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified:  4-DEC-1990    ArticleIdent: Q67356

 Under certain circumstances, a C4127: "conditional expression is
 constant" warning may be generated by the compiler when loop
 optimization (/Ol) is enabled. The warning message usually involves a
 comparison of unsigned numbers, where an unsigned is being checked
 against zero because an unsigned value must ALWAYS be greater than or
 equal to zero. However, this warning can also occur with loop
 optimization; in that case, it is an indication that the loop will be
 executed at least once.

 When you specify /Ol optimization, the compiler normally places two
 tests in the code: one at the beginning of the loop and one at the
 end. Consider the following sample program:

 unsigned foo (unsigned x, unsigned y)
 {
    unsigned i;

    for ( i = 0 ; i <= x ; i++ )
       y += i;

    return y;
 }

 Without loop optimization, the compiler does generate code that
 includes a test before the loop to check the initial condition, and
 then a check at the end to see if the loop should be terminated.

 In this case, however, the variable i starts out as zero and the
 initial test checks whether i is less than or equal to x, which must
 be true because x is unsigned. This given condition allows the
 compiler to optimize the loop by removing the initial test because the
 possible values for i and x guarantee that the loop will always be
 executed at least once.

 When the compiler optimizes out the first test based on this fact, it
 generates the C4127 warning message to inform you of the situation.
 This message does not necessarily indicate any problems, it just lets
 you know that loop will be executed at least once no matter what the
 value of i is. This would be important if you expect a value of zero
 to cause the loop to not be executed.

 If loop optimization is disabled or signed numbers are used instead of
 unsigned, then the warning will not be generated. Also, changing the
 comparison from "<=" to just "<" will prevent the compiler from being
 able to assume that the comparison will always be true the first time
 around.

 Since the warning message itself is not very descriptive for what is
 actually occurring, a new message is being considered for future
 versions of the compiler.


 1049. Void _saveregs Function Does Not Preserve AX Register

 Product Version(s):
 Operating System:   6.00 6.00a | 6.00 6.00a
 Flags: MS-DOS     | OS/2
 Last Modified: 15-FEB-1991    ArticleIdent: Q67357
 ENDUSER | s_quickc buglist6.00 buglist6.00a

 Functions with a void return type that are declared with the _saveregs
 attribute do not preserve the AX register. An arbitrary return value
 is stored in AX unnecessarily.

 The C online help states the following:

    The _saveregs keyword causes the compiler to generate code that
    saves and restores all CPU registers when entering and exiting the
    specified function. Note that _saveregs does not restore registers
    used for a return value (the AX register, or AX and DX).

 The second sentence states that AX will not be preserved whenever
 there is a return value, but a void function has no return value.
 Thus, there is no reason the AX register should not be preserved.

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a and QuickC version 2.50 (buglist2.50). We are researching this
 problem and will post new information here as it becomes available.


 1050. C1001: Internal Compiler Error: regMD.c, Line 4688

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist6.00 buglist6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67358

 The sample code below produces the following internal compiler errors
 under different versions of the compiler. These problems occur when
 any of the following individual optimizations are used under the small
 and medium memory models:

    /Oa /Oc /Oi /On /Op /Or /Os /Ot /Ow /Oz

 Under C 6.00a
 -------------

    test.c(7) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)regMD.c:1.110', line 4688)
                    Contact Microsoft Product Support Services

 Under C 6.00
 ------------

    test.c(7) : fatal error C1001: Internal Compiler Error
                    (compiler file '@(#)regMD.c:1.100', line 4634)
                    Contact Microsoft Product Support Services

 The following are four possible workarounds:

 1. Add one of the following optimizations:

       /Od /Oe /Og /Ol /Ox

 2. Do not declare the structure variables of type register.

 3. Use an if-else statement instead of the ternary operator.

 4. Compile under the compact or large memory models.

 Sample Code
 -----------

 1:  void main(void)
 2:  {
 3:     register int *boo, *hoo;
 4:     int n;
 5:
 6:     boo=hoo;
 7:     n= *boo ? 1 / *boo : 1;
 8:  }

 Microsoft has confirmed this to be a problem in C versions 6.00 and
 6.00a. We are researching this problem and will post new information
 here as it becomes available.


 1051. Incorrect Definition Given for the Time Zone Variable

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  4-DEC-1990    ArticleIdent: Q67359

 The variable, "timezone", a member of the timeb structure defined in
 SYS\TIMEB.H, is incorrectly documented as returning the difference in
 seconds between Greenwich Mean Time and local time, in both the online
 help and the Microsoft Press book, "Microsoft C Run-Time Library
 Reference." The difference is returned in minutes, not seconds.

 The "timezone" variable is documented correctly in both the online help
 and the Microsoft Press book, "Microsoft C Run-Time Library Reference"
 manual, in the description for the ftime() function.


 1052. Error in C and QuickC Example Program: BESSEL.C

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr s_quickc
 Last Modified: 17-DEC-1990    ArticleIdent: Q67393

 When compiling the BESSEL.C sample program with the Warning Level set
 to 4, the warning below is displayed. The sample program is available
 in the online help shipped with C versions 6.00 and 6.00a, and QuickC
 versions 2.00 and 2.50:

    Warning C4129: 'F': unrecognized escape sequence

 The warning is caused by an extra "\" (backslash) in a printf()
 statement. The line that causes the problem is as follows:

    printf("  Kind\t\t\Order\t\Function\tResult\n\n");

 Notice that there is an extra backslash before the word "Function."
 This should be removed.






 Microsoft QuickC
 =============================================================================


 1. Documentation Error in QuickC "Up and Running" on /FPi87

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 14-DEC-1990    ArticleIdent: Q67512

 Page 14 of the Microsoft QuickC "Up and Running" manual incorrectly
 states that the custom flag "/FPi87" may be placed in the "Linker
 Flags dialog box".

 It should read "Compiler Flags dialog box".


 2. Accessing Help with the CodeView Upgrade for QuickC

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | S_CODEVIEW
 Last Modified: 12-DEC-1990    ArticleIdent: Q67610

 When installing CodeView version 3.11 for QuickC, you must set the
 environment variable HELPFILES to the QC25\BIN directory (or the
 correct directory on your system) in order to access help from
 CodeView.

 The correct setting for HELPFILES on a system where QuickC is
 installed on drive C in a directory called "\QC25\BIN" is:

    SET HELPFILES=C:\QC25\BIN\*.HLP

 This is not covered in the CodeView for QuickC printed documentation,
 but is stated clearly in the CodeView for QuickC Setup program.


 3. C 6.00 Pragmas Supported by QuickC

 Product Version(s): 2.50 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JAN-1991    ArticleIdent: Q67881

 The QuickC online help system documents support for the following four
 pragmas:

    check_stack, check_pointer, message, and pack

 Six pragmas are actually supported, but using any of the others (which
 are also supported by the C 6.00 compiler) with QuickC will have no
 effect, even though warnings are generated for only four of them.

 Below is a list of pragmas supported by the C compiler version 6.00
 and the behavior exhibited by QuickC versions 2.00 and 2.50 when they
 are encountered in a source file. Those that are not supported and
 that actually issue a warning will generate the following warning
 message:

    C4118: pragma not supported

    A pragma that the compiler does not support was used. The pragma
    was ignored.

    Pragma                       Behavior
    ------                       --------

    #pragma alloc_text()         Supported but not documented

    #pragma check_pointer()      Supported and documented

    #pragma check_stack()        Supported and documented

    #pragma comment()            Not supported -- issues a warning at level
                                 3 and above.

    #pragma intrinsic()          Not supported -- issues a warning at level
                                 1 and above.

    #pragma function()           Not supported -- issues a warning at level
                                 1 and above.

    #pragma linesize()           Not supported -- ignored (but is only
                                 useful with /Fs, which is not
                                 supported by QuickC).

    #pragma loop_opt()           Supported (but only with -Ol -- otherwise
                                 ignored).

    #pragma message()            Supported and documented.

    #pragma optimize             Not supported -- ignored.

    #pragma pack()               Supported and documented.

    #pragma page()               Not supported -- ignored, same as
                                 linesize.

    #pragma pagesize()           Not supported -- ignored, same as
                                 linesize.

    #pragma same_seg()           Not supported -- issues a warning at level
                                 1 and above.

    #pragma skip()               Not supported -- ignored, same as
                                 linesize.

    #pragma subtitle()           Not supported -- ignored, same as
                                 linesize.

    #pragma title()              Not supported -- ignored, same as
                                 linesize.


 4. No Mouse with GRDEMO.EXE Sample Program May Cause M6111

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50 s_quickasm
 Last Modified: 17-JAN-1991    ArticleIdent: Q68111

 The Microsoft QuickC versions 2.50 and 2.51 compiler includes a sample
 program called GRDEMO.EXE that is created using GRDEMO.MAK. The module
 MOUSE.C incorrectly returns from the function MouseInit() when no
 mouse is found. It will return without cleaning up the stack, which
 may cause the following error:

    run-time error M6111: MATH
    floating-point error: stack underflow

 To work around this problem, make the following programming changes in
 MOUSE.C, and rebuild the program:

 1. Change line 74 from

       ret

    to the following:

       jmp    nomouse

 2. Add the label "nomouse" just prior to the end of the inline
    assembly code:

    ...
       mov   mi.cBtn, bx      ; Save...
    nomouse:
    }

 Microsoft has confirmed this to be a problem in QuickC versions 2.50
 and 2.51. We are researching this problem and will post new
 information here as it becomes available.


 5. QuickC Displays "Incompatible Operands" When Watching Arrays

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | fixlist2.50
 Last Modified: 11-JAN-1991    ArticleIdent: Q68146

 Attempting to watch individual elements of global arrays in the Debug
 window may result in the message "Incompatible operands" being
 displayed. This problem only occurs when a Program List is created
 containing more than one C module.

 The following steps illustrate the problem:

 1. Create two C modules similar to the ones below and add them
    to a program list.

           TEST.C                         DUMMY.C
     ------------------                -------------

     #include<string.h>                #define dummy

     char str[80];

     void main(void)
     {
          strcpy(str, "Hello World");
     }

 2. Rebuild the application with debug (CodeView) information.

 3. Trace through the program by pressing F8.

 4. Enter str and str[0] into the Watch (Debug) window.

 The following lines will be displayed in the Debug window:

    str : <Cannot display>
    str[0] : <Incompatible operands>

 Microsoft has confirmed this to be a problem in QuickC versions 2.00
 and 2.01. The problem does not occur in versions 2.50 and 2.51.


 6. Writing to Video Memory in the QuickC Environment

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-NOV-1988    ArticleIdent: Q36935

 Problem:

 Code that writes directly to video memory compiles properly within
 QuickC, but may not execute as you would expect if you run the code in
 the QuickC environment.

 This problem occurs because when you write directly to video memory
 within the QuickC environment, you will over-write, distort, or
 corrupt the screen information for QuickC. You may also hang the
 computer.

 More Info:

 If you are trying to achieve some effect through writing directly to
 the video memory while in QuickC's environment, you should try other
 alternatives instead, such as using DOS or BIOS interrupts.



 7. QuickC Generates Warning Message "C4071" erroneously

 Product Version(s): 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER | BUGLISTQC
 Last Modified: 20-OCT-1988    ArticleIdent: Q37020

 The code below fragment demonstrates a problem with the way the
 QuickC environment handles certain prototypes. When compiled inside
 the environment at warning level three, the compiler generates the
 warning message C4071 "<function name> no prototype given," even
 though the function does have a prototype.

 Microsoft has confirmed this to be a problem in Version 1.01. We are
 researching this problem and will post new information as it becomes
 available.

 This message appears only with functions of type void with no
 parameters. Because you cannot avoid such constructions if you use
 indirect recursion, you cannot work around this problem. However, you
 can lower the warning level to two and this problem will not occur.

 The following sample code demonstrates this problem:

         void a(void);
         void b(void);

         void a(void)
         {
         }

         void b(void)
         {
           a();
         }

         void main(void)
         {
         }


 8. QuickC 2.50 Environment Does Not Run on a Tandy 2000

 Product Version(s): 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-JAN-1991    ArticleIdent: Q68295

 The QuickC versions 2.50 and 2.51 environments do not run on a Tandy
 2000 with the configuration listed below. The Setup program runs
 properly, but the environment locks the system up, requiring a reboot.

 System Configuration:

    Tandy 2000
    RGB monitor
    B/W graphics kit
    Color graphics kit


 9. Increasing the Automatic Repeat Rate of the Keyboard

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68625

 A customer noted that by running Windows and then running QuickC, the
 automatic repeat rate of the keyboard (called the typematic rate)
 increased. Thus, when he held down a key, the speed at which his
 cursor would move across the screen increased. He wanted to know how
 to get this effect without running Windows.

 By writing a program that calls int 16h function 03h, you can set this
 repeat rate. The following program will set the keyboard for the
 fastest repeat rate. (Note: This will work only on PS/2- and AT-class
 machines; it will not work on XT-class machines.) More information on
 int 16h can be found in the "IBM ROM BIOS: Programmer's Quick
 Reference" by Ray Duncan.

 Sample Code
 -----------

 #include <dos.h>

 union REGS r;

 void main ()
   {
   r.h.ah= 3;
   r.h.al= 5;
   r.h.bh= 0;
   r.h.bl= 0;
   int86 (0x16, &r);
   }


 10. Differences in MAKE Files among QuickC 1.00, 1.01, and 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q37494

 If you have upgraded from QuickC Version 1.00 or 1.01 to Version 2.00,
 and you have already created MAKE files for your programs under the
 previous versions of QuickC, you must make the following changes to
 these MAKE files so that they are compatible with QuickC Version
 2.00's NMAKE utility.

 To convert old-style MAKE files to NMAKE files, do the following:

 Note: It is almost always easier and quicker to delete the old
 MAKE file and allow QuickC Version 2.00 to build a new one from
 scratch.

 1. Make a copy of your old MAKE file, so you can return to the
    original if needed.

 2. Remove the two lines of the inference rule by deleting them or
    commenting them out with a "#" at the start of the
    line.

    The inference rule is in the form of the following:

             .c.obj
                 qcl /c /AM $*.c

 3. Add the following as the new first target:

    "all: prog.exe"
    (where "prog" is the name of your program's executable)

 4. Change "Prog.exe" to "prog.exe" in the last target "prog.obj".
    (Again "prog" is the name of your program's executable.)

 5. Enter QuickC.

 6. Choose the MAKE menu and the SET option

 7. Save the MAKE file.

 The MAKE file has now been converted so that it is compatible with
 QuickC Version 2.00's NMAKE.

 This information can be found in the "Microsoft QuickC 2.00 Toolkit"
 manual in Sections 7.5 and 7.6. A complete description of NMAKE's
 capabilities and functionality can be found in Chapter 7.


 11. "Save Before Rebuild" Does Not Work Properly

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50 buglist2.51
 Last Modified:  6-FEB-1991    ArticleIdent: Q69066

 In QuickC, if you choose Display from the Options menu, there are two
 options for "Prompt Before Save" and "Save Before Build." If you are
 using a program list containing more than two files, you will always
 be prompted to save the modified file regardless of how the "Save
 Before Build" option is set.

 Microsoft has confirmed this to be a problem in QuickC versions
 2.50 and 2.51. We are researching this problem and will post new
 information here as it becomes available.


 12. Use of the HELPFILES Environment Variable by QuickC

 Product Version(s): 2.00 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm Quick C
 Last Modified: 31-JAN-1991    ArticleIdent: Q68800

 The QuickC environment's use of the HELPFILES environment variable is
 not documented; however, QuickC versions 2.00 and 2.50 will use this
 variable when searching for help files. Versions of QuickC earlier
 than 2.00 do not support the HELPFILES environment variable.

 QuickC's use of HELPFILES differs from that of Microsoft C version
 6.00 and QuickHelp version 1.70 in that QuickC does not allow any
 wildcard characters in the filenames specified in the HELPFILES
 environment variable. QuickC expects a complete filename to appear in
 this environment variable. It should also be noted that multiple
 filenames may be specified and that full pathnames will also work. If
 no path is specified, QuickC will look in the current directory.

 Correct HELPFILES settings for QuickC:

    HELPFILES=c:\help\f.hlp;..\g.hlp;b.hlp;

 Incorrect HELPFILES settings for QuickC:

    HELPFILES=c:\help\*.hlp;

 This feature is very useful because it allows the use of additional
 help files without having to append them to an existing QuickC help
 file.


 13. Differences among QuickC Versions 2.00, 1.00, and 1.01

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-JAN-1991    ArticleIdent: Q38032

 QuickC version 2.00 is a window-like programming environment that
 integrates a text editor, a compiler, a debugger, and a make utility.
 Major differences between version 2.00 and the previous releases of
 QuickC are listed below. After each listing there is a source
 reference where you can find more detailed information in the
 documentation that accompanies QuickC version 2.00.

 The following listing shows features that are exclusive to QuickC
 version 2.00:

  1. 512K memory available required for QC.EXE.

  2. Online Help. QuickC version 2.00 offers instant Online information
     on all important C topics. The following lists some of the topics
     for which help is available:

     a. C-keywords, operators, library functions, prototypes,
        definitions

     b. Environment Help (help on menu choices, dialog boxes, etc.)

     c. C Run-time Errors

     d. Help (on Help)

     You can also add information to the OnLine Help database yourself,
     using the HELPMAKE utility. (See Chapter 4 "Getting Help" in the
     "Up and Running" documentation.)

  3. Customize the QuickC Editor:

     It is possible to use another set of editing command keystrokes
     using the .KEY files QC.KEY, ME.KEY, BRIEF.KEY, and EPSILON.KEY.
     These files can be used to remap the keystrokes of the QuickC
     editor so that it emulates the Microsoft Editor, Brief, and Epsilon
     editors. You also can create your own .KEY file with the MKKEY
     utility.

     You can use your own choice of editor or word processor instead of
     the QuickC Editor. However, use of other editors will not support
     the symbolic information necessary to the debugger.

     (See "Customizing the Editor" in "Up and Running," Pages 26-28.)

  4. Incremental Compiling/Linking. If you choose the incremental
     compilation option, then only those functions that have changed
     since the last compilation will be recompiled. (See section 4.3.15
     of "QuickC Toolkit.")

  5. Presentation Graphics. In addition to the existing graphics
     functions, version 2.00 offers Presentation Graphics, which is the
     name given to the library of chart-generating functions. With
     this package, you can display data as a variety of graphs such as
     pie charts, bar and column charts, line graphs, and scatter graphs.
     Fonts and font sizes are also manipulated through these routines.
     (See Chapter 13 "Presentation Graphics' in "C For Yourself.")

  6. Support for the "Olivetti Color Board" graphics card.

  7. InLine Assembly Code. QuickC has the ability to handle
     assembly-language instructions right in your C program. This
     ability is built in and does not require a separate assembler
     program. (See Chapter 15 "InLine Assembly" in "C For Yourself.")

  8. "C For Yourself" (an introduction to the C language). This book
     assumes that you have programmed before, but are not familiar with
     the C language. Topics covered are as follows:

     a. Functions and data types.

     b. Input/output and graphics.

     c. QuickC implementation of the C Language.

     d. Summaries of common run-time functions. (Details of all run-time
        functions are available in the OnLine Help facility.) (See the
        "C For Yourself" manual.)

  9. NMAKE (program maintenance utility). NMAKE is similar to the MAKE
     utility and helps automate software development and maintenance.
     NMAKE is typically used in the following situations:

     a. Updating an executable file whenever any of the source or object
        files has changed

     b. Managing libraries, to rebuild a library whenever any of the
        modules in the library has changed

     c. In a networking environment, to update the local copy of a
        file that is stored on the network whenever the master copy
        has changed


 14. Graphic Routines Fail to Use Active Card when Two are Present

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 17-NOV-1988    ArticleIdent: Q38154

 On machines with two graphics cards, the graphics package shipped
 with QuickC and the C Versions 5.00 and 5.10 optimizing compiler will
 use only the higher-resolution card for graphic output, regardless of
 which is the active card. The only solution is to remove the second
 card. However, this is a particular problem with machines such as the
 PS/2 model 30, which has a built-in MCGA card.

 QuickC will recognize an add-on VGA card, which has higher resolution
 than MCGA; however, it will not recognize an add-on EGA card, which,
 although it provides lower resolution than the MCGA, is considered by
 many to be a superior card for graphic output. If an attempt is made
 to use _setvideomode to set the system into an EGA mode, _setvideomode
 will return an error.

 The graphics routines do not rely solely on the bios. Issuing a bios
 call (Int 10, Function 0FH - Get Video Mode) to determine whether or
 not the bios recognizes the EGA as the active card will return the
 value for an EGA-only mode. However, the graphics routines will
 continue to use the MCGA card.



 15. Mouse Cursor Disappears on Monochrome Displays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q38159

 Question:

 Why does my mouse cursor disappear in the text area of QuickC 2.00's
 screen? The cursor appears in the menu areas but nowhere else.

 Response:

 If you have a monochrome monitor, you should make sure that QuickC is
 aware of this behavior and that it is not trying to display the screen
 in a color mode. You can set QuickC in a black and white mode in one
 of the following two ways:

 1. Invoke QuickC from the DOS command line with the "/b" option
    as follows:  (The filename is optional.)

    QC /b [filename]  <hit enter>

 2. Once in the QuickC environment, do the following:

    a. Pull down the Options menu.

    b. Choose the Display selection.

    c. Under the "Display Options" section, choose the
       option labeled LCD.

    d. Choose "OK" to save this selection.

 QuickC will now display its output (including the mouse cursor) in
 black and white mode. This setting will remain in effect throughout
 this QuickC session and all subsequent sessions until you change it.


 16. Sample Program SAMPLER.C Does Not Work Correctly

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr s_c
 Last Modified:  1-FEB-1991    ArticleIdent: Q68911

 The sample program SAMPLER.C, included in the Microsoft QuickC "C for
 Yourself" manual that shipped with QuickC version 2.50, is incorrect
 and will always exit with the following message:

    Error:  can't set font

 The correction listed below is also documented in the README.DOC
 shipped with QuickC version 2.50.

 The problem is on line 58 of SAMPLER.C, where the return value for the
 _setfont() function is checked. The sample program uses the logical
 not operator "!" to determine if an error code was returned. The
 problem with this method is that _setfont() returns a negative number
 to signify an error, or the font index number, if successful. Previous
 implementations of _setfont() returned 0 (zero) if successful, or -1
 if unsuccessful. The online help for C version 6.00 still documents
 the old return values, as noted in the README.DOC shipped with C
 version 6.00:

    The return values for _setfont as described in on-line help are
    incorrect. The _setfont function returns the font index number if
    successful, or a negative number if unsuccessful.

 The same error exists in the Microsoft Press book "Microsoft C
 Run-Time Library Reference" for C version 6.00. However, the return
 values for _setfont() are documented correctly in the online help for
 QuickC version 2.50.

 To correct the problem, change line 58 from

    if(!_setfont( list ))

 to the following:

    if( _setfont( list ) >= 0 )

 As stated above, this correction is noted in the README.DOC that
 shipped with QuickC version 2.50.

 Also note that the return value of _setfont() (as documented above) is
 valid only for C versions 6.00 and 6.00a and QuickC versions 2.50 and
 2.51. The _setfont() function in the libraries shipped with QuickC
 versions 2.00 and 2.01 (as well as C version 5.10) use the previous
 implementations' return codes; therefore, the program will run
 correctly when compiled using those versions.

 The program SAMPLER.C can be found on page 302 of the "C for Yourself"
 manual. It can also be found in the QuickC online help by selecting
 the Help menu, choosing Contents, choosing "C for Yourself Sample
 Programs", and finally, choosing SAMPLER.C.

 The correct version of SAMPLER.C can be found on page 242 of the
 "Microsoft C Advanced Programming Techniques" manual that shipped with
 C versions 6.00 and 6.00a.


 17. Fatal Compile Time Error C1008 No Input File Specified

 Product Version(s): 1.00   | 1.01
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-NOV-1988    ArticleIdent: Q38192

 The following error occurs in the QuickC environment when the
 compiler is not given a file to compile:

 Fatal error C1008: no input file specified

 This information is not documented in the "Microsoft QuickC
 Programmer's Guide" for Versions 1.00 and 1.01 and on-disk
 documentation. The error is produced in the QuickC environment
 when the compiler is not given a file to compile.  It does not
 occur with QCL.



 18. Even and Align Directives Are Ignored in Inline Assembly

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c buglist2.00 buglist 2.01 buglist2.50 buglist2.51
 Last Modified:  6-FEB-1991    ArticleIdent: Q69067

 The use of the align and even directives in inline assembly blocks in
 QuickC should generate NOP instructions so that the code that follows
 the directive will reside on the specified byte boundary. However,
 these directives never generate any NOP instructions.

 The quick compile (/qc) feature of C versions 6.00 and 6.00a also
 performs incorrectly. The align and even directives will work properly
 under C versions 6.00 and C 6.00a if the /qc option is not used.

 Sample Code
 -----------

 void main (void)
   {
   _asm
     {
     even
     push ds
     even
     pop  ds
     }
   }

 Microsoft has confirmed this to be a problem in QuickC versions 2.00,
 2.01, 2.50, 2.51 and C versions 6.00, and 6.00a (buglist6.00 and
 buglist6.00a). We are researching this problem and will post new
 information here as it becomes available.


 19. QuickC: Cannot Watch Variable with Dollar Sign ($) in Debugger

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43487

 Using the QuickC Version 2.00 debugger to watch a variable name
 containing a dollar sign will not work. The variable name will be
 displayed in the watch window, but the value will be displayed as
 "<syntax error>". There is no way to display such a variable in the
 watch window.

 Using the dollar sign in variable names is not ANSI C standard. If
 symbol names must have a dollar sign in them, the QuickC 2.00 debugger
 cannot be used to watch them. However, CodeView will display such
 variables.

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


 20. Use of RMFIXUP.OBJ

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q38854

 When using the /FPi option, the compiler will not generate true
 in-line 8087/80287 instructions. Instead, it will generate software
 interrupts to library code, which corrects the interrupts to use
 either the emulator or the coprocessor, depending on whether or not a
 coprocessor is present. The fix-ups can be removed by simply linking
 with the RMFIXUP.OBJ provided with QuickC.

 Note: Once this file has been linked in, the program can no longer be
 run on a machine without a coprocessor.


 21. Use of CRLF.EXE

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q38855

 The QuickC editor has the following restrictions on the files it
 can edit:

 1. All lines must be terminated by a carriage return (CR) followed
    by a line feed (LF)--ASCII codes 0x0D/0x0A.

 2. Character 0 is not allowed. All other characters in the
    range 1 to 255 are allowed.

 The editor specifically handles CR (0x0D), LF (0x0A), and HT (0x09).
 Because other control characters may be undesirable, CRLF allows you to
 optionally change control characters to a specified character
 or to simply remove them. The syntax is as follows,

    crlf <infile> <outfile> [/c<ascii>]

 where <infile> is the file to be translated, <outfile> is the new
 translated file, and <ascii> is the ASCII code for the character
 to which control characters (except CR, LF, and HT) will be translated.
 The ASCII code may be entered in decimal (ddd), octal (0ddd), or
 hexadecimal (0xddd).

 For example, /c32 will translate all control characters to spaces. If
 <ascii> is given as 0, control characters will be removed rather than
 translated. If /c is not given, the program will prompt for
 translation characters.


 22. "Invalid Object Module" with Indirection Problem

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01
 Last Modified: 13-DEC-1988    ArticleIdent: Q38857

 QuickC Versions 1.00 and 1.01 generate an "L1101: Invalid Object
 Module" when a program containing a statement of the following syntax
 is placed into a program, and the program is compiled inside of the
 environment (regardless of warning level):

 #include <stdio.h>

 char greeting = "hello";

 main()
  {
  }

 The program will appear to compile correctly, however, it should be
 generating the following warning:

    Warning C4047: 'initializing': different levels of indirection

 Microsoft has confirmed this to be a problem in Versions 1.00 and 1.01.
 We are researching this problem and will post new information as it
 becomes available.

 This confusing lack of any compile-time warning only occurs inside of
 the QuickC environment. If the linker version is correct, and you
 suspect that this is the problem, quit QuickC and compile on a QCL or
 CL command line. If there is an indirection problem, either of the
 command line drivers will generate the above warning message at
 Warning Level 1 or above. The QCL driver will also generate the
 "Invalid Object Module" error at link time, in addition to the
 indirection warning. The CL driver will generate the correct
 indirection warning, then link successfully.

 To correct the error, modify your code in one of the following two
 ways:

 char greeting[5]="hello";
 char* greeting="hello";

 The program should then compile and link successfully.



 23. QuickC Version 2.00 Supports CodeView Information

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |  s_codeview
 Last Modified: 31-OCT-1989    ArticleIdent: Q38951

 QuickC Version 2.00 contains support for CodeView's symbolic
 information in the QuickC environment. If you choose the Options
 menu and the "Make" selection, you will get a pop-up menu that will
 allow you to choose the compilation flags. Once you have chosen the
 <compiler flags> selection, you can set the Option for CodeView
 information. This process will allow you to use the debugger within
 QuickC as well as using the same executable in CodeView, thus
 eliminating a required recompilation by the QCL command line compiler.

 If you intend to use CodeView on your QuickC executable, you will have
 to ensure that you have disabled the Incremental Compile and the
 Incremental Link options. The Incremental Compile option is found
 under <compiler flags> selection. The Incremental Link option can be
 found under <linker flags> selection.

 The current CodeView release is unable to understand Incrementally
 compiled/linked executables. If you try to use CodeView on an EXE file
 that was Incrementally compiled and/or linked, you will be unable to
 trace through the code. The trace will "fall" through to the end of
 your program.



 24. Unresolved External _main in crt0.asm when Compiling with /P

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 docerr
 Last Modified: 12-JAN-1989    ArticleIdent: Q39137

 The "Microsoft QuickC Programmer's Guide" explicitly states that
 invoking QCL with the /P, /E, or /EP switches produces a preprocessor
 listing file but no .OBJ file, even if /Fo is also specified. This is
 incorrect. A 524-byte .OBJ will be produced.

 QCL will not link when one of these switches is specified; however,
 when a make file or batch file that calls the linker is used in the
 compilation process, the following error is generated:

    LINK : error L2029 : Unresolved externals:
    _main in file(s):
    c:\qc\lib\slibce.lib (dos\crt0.asm)

 C Version 5.10 handles these switches as documented.

 Microsoft has confirmed this to be a problem in Versions 1.00 and 1.01.
 We are researching this problem and will post new information as it
 becomes available.



 25. QuickC Incorrectly Issues a C4051 Data Conversion Warning

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q39145

 The Microsoft Quick C Compiler generates a "C4051: data conversion"
 warning message for the following code when compiled with warning
 level 3. This occurs in the integrated environment QC as well as
 the command line compiler, QCL.

 The following is a code example:

 void main()
 {
   char temp ;
   temp = 0xff ;
 }

 The warning is noting that the variable "temp", which is a signed
 char, is being initialized with a value that is larger than a signed
 char can represent. The bit pattern is not affected in this example
 since 0xff can be represented by an unsigned char.

 This warning does not affect how the bits are stored in the byte
 of storage.  The message is informing you that this bit pattern
 will not be interpreted as expected in a signed character
 translation.

 This is expected behavior for the QuickC compiler Versions 1.00 and
 1.01.

 This warning is not produced in QuickC Version 2.00.


 26. Error C2086: Redefinition Caused by Forward Reference

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1989    ArticleIdent: Q39852

 When compiled with any version of the QuickC compiler, the program
 below will produce (at warning level 0) the fatal error.

      C2086:
      'foo': redefinition.

 This error will occur if foo() is typed as being of any class other
 than int, the default return type.

 The following program demonstrates this situation:

     main()
         {
         int i;
         i = foo();
         }

     static int foo()
         {
         return(1);
         }

 This is expected behavior for the following reason. The following
 information is from the ANSI draft standard (13 May 1988):

     I. If the declaration of an identifier for an object or a function
        contains the storage class specifier "extern", the identifier
        has the same linkage as any _visible_ declaration of the
        identifier with file scope.

    II. If the declaration of an identifier for a function has no
        storage class specifier (as is the case with implicit [first
        use] function uses), its linkage is determined exactly as if it
        were declared with the storage class specifier "extern".

   III. If the declaration of an identifier for an object or a function
        has file scope and contains the storage class specifier
        "static", the identifier has internal linkage.

    IV. If, within a translation unit, the same identifier appears with
        both internal and external linkage, the behavior is undefined.

 A forward reference to a function not yet visible to the compiler will
 be treated as of type EXTERN because the compiler is unaware of its
 storage class. Because it is of type EXTERN, it has external linkage,
 i.e., it is an identifier associated with a function defined
 outside the current module. When the compiler then encounters the
 definition of this function with the STATIC storage class, it
 interprets it as a redefinition of that function. Code has already
 been generated treating it as EXTERN; now it has been declared as
 STATIC. Being STATIC, it then has internal linkage. At this point, the
 identifier has both internal and external linkage and behavior is,
 according to the draft standard, undefined.

 The following information is also from the draft standard:

    Undefined behavior - behavior, upon use of a nonportable or
    erroneous construct of erroneous data, or of indeterminately-valued
    objects for which the standard imposes no requirements.
    Permissible undefined behavior ranges from ignoring the situation
    completely with unpredictable results, to behaving during
    translation or program execution in a documented manner
    characteristic of the environment (with or without the issuance of
    a diagnostic message), to terminating a translation or execution
    (with the issuance of a diagnostic message).

 QuickC's behavior conforms precisely to this guideline. Page 172 of
 the "Microsoft C Language Reference Guide" states that a function
 definition without a storage class specifier defaults to EXTERN.
 QuickC issues a diagnostic message and terminates translation (fatal
 compiler error). Being a one-pass compiler, QuickC has no way of
 determining the storage class of a forward-referenced function,
 unlike C Versions 5.x, and thus deals with it in the manner described.

 This behavior also applies to QuickC Version 2.00.


 27. Use of Wrong Library Causes Unresolved External on __aDBused

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUN-1989    ArticleIdent: Q40182

 Question:

 I just ported my code over from QuickC Version 1.01 to QuickC Version
 2.00. When I try to build my program, I get an unresolved external on
 __aDBused at link time. What's wrong?

 Response:

 You are using the wrong libraries. QuickC 2.00 libraries are
 incompatible with Version 1.01 libraries. Make sure your lib path is
 pointing to your QuickC Version 2.00 libraries, and not to any older
 libraries, such as those with C Version 5.10. To do this, follow these
 steps:

 1. Press (inside the QuickC environment) ALT+O to pull down the
    Options Menu.

 2. Press "E" for Environment.

 3. Press TAB once to go to the libraries setting.

 4. Type in the path for the proper libraries, and press ENTER.

 You now can recompile.

 The exact error message will be as follows:

    filename.obj(filename.c) : error L2029 : '__aDBused' : unresolved external

 With linker versions later than 3.65, this message will occur for each
 module in the program list.


 28. QuickC 2.00 Libraries Incompatible with Windows SDK 2.10

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | appnote
 Last Modified: 11-OCT-1989    ArticleIdent: Q40194

 QuickC Version 2.00 was designed to support Windows programming with
 the QCL command-line compiler. The QuickC environment does not support
 this. However, the libraries that are shipped with the Version 2.00
 package are incompatible with Windows SDK Versions 2.10 and earlier.
 This problem was confirmed before Version 2.00 went to manufacturing;
 the planned resolution is to make a patch to the libraries available
 through Microsoft Product Support Services.

 The problem is the result of the fact that the current Windows SDK
 assumes that the libraries are from C Versions 5.10 or earlier.
 QuickC Version 2.00's libraries are more current than C Version
 5.10's libraries and pose problems to the Windows SDK.

 There is a patch available that modifies the SLIBCEW.LIB and
 MLIBCEW.LIB libraries to be compatible with the Windows SDK. Currently
 the patch addresses the small and medium memory model libraries, but
 not the compact or huge models. Since true windows applications do not
 use the compact or huge models Microsoft has made the patches to the
 small/medium models available now, rather than wait for all the
 patches to be completed. If you require the compact and/or large
 memory please contact Microsoft Product Support.

 Note: The initial patch that was sent out contained a flaw that
 allowed an external to remain unresolved. If you have the patch and
 still have the following error, then you should contact Product
 Support at (206) 454-2030 to obtain the current corrected patch:

    L2029: Unresolved external: '__aDBswpchk'



 29. "*\" Viewed as Continuation Character in Comment

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40196

 In C, comments are delimited by /*  and */. If the closing delimiter
 is typed as *\ instead of */, then the backslash will be viewed as a
 continuation marker. As a result, the compiler considers everything up
 to the next */ as a comment. This behavior has the potential to
 comment out executable instructions and data declarations, which may
 not be your intent.

 The following code example illustrates this situation and potential
 implications:

 void main()
 {
   /* this is a comment, but the end delimiter is incorrect *\

   int  temp ;
   printf ("hello") ;

   /* and will be interpreted as a continuation marker so the
      initial comment will be viewed as ending here. */

   /* This will eliminate the printf() and
      the declaration of 'temp'. */
 }

 This is expected behavior for QuickC Version 2.00. The interpretation
 of the backslash as a continuation character is similar in the
 following printf() code:

     printf ("Donde esta \
              el bano") ;

 The parsing of the string literal for this printf() will view the
 backslash, "\", as a continuation marker just as the compiler will
 view the backslash in "*\" as a continuation marker.


 30. Using C within _asm Blocks of Assembly Code

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1989    ArticleIdent: Q40101

 The following elements of C may be used in in-line assembly blocks of
 code:

 1. C variable names

 2. C labels

 3. C macros

 4. C function identifiers

 5. C comments

 6. C named constants, including "enum" members

 7. C typedef names, generally used with operators, such as PTR
    and TYPE, or to specify structure or union members

 These elements of C must be used in accordance with the following
 two conventions:

 1.  Only one C symbol can be referenced for each assembly instruction,
     unless used in conjunction with the TYPE, LENGTH, or SIZE operators.

 2.  Functions referenced within an _asm block must be prototyped
     previously in the program. Otherwise QuickC cannot distinguish
     functions from labels.

 The following code illustrates the use of some the above C elements
 within an _asm block:

 void main(void) ;

 void main ()
 {
   int  result ;
   int   Count ;

   result = 0 ;
   Count = 16 ;

   /* result = count * count */

   _asm {
          mov  ax, Count
          imul ax,
          mov  result, ax
        }
 }


 31. QuickC 2.00's In-Line Assembler

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40103

 QuickC Version 2.00 has the ability to handle assembly-language
 instructions in your C program. This feature is built into QuickC
 Version 2.00 and does not require an external assembler program.

 In-line assembly instructions can appear at any place that a valid
 C statement can reside. The following is an example using in-line
 assembly:

     void main ()
     {
       .   ( C Code )
       .
       _asm {
              mov    ah, 5
              mov    al, 1
              int    10h
            }
       .
       .
     }

 The _asm designates the code that follows as assembly. QuickC uses its
 In-Line Assembler instead of the compiler. The _asm keyword can be
 applied to individual assembly statements and blocks of assembly code.
 As in the above example, the block of assembly code is delimited by
 the {} braces. If you have only one assembly statement, the {} braces
 are not required.

 If you want to place more than one assembly instruction on a single
 line, place the _asm before each instruction, as in the following code
 fragment:

     _asm    mov  ah, 5   _asm   mov  al, 1    _asm  int 10h


 32. Hardware Compatibility List for QuickC Version 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40104

 Below is a list of personal computers and video cards on which
 QuickC Version 2.00 was tested. Although not every type of machine and
 video card listed was tested, every card was at least tested on an IBM
 computer.

 The following video cards were tested:

    AST-VGA
    Compaq VGA                  Paradise VGA+
    Genoa EGA                   Paradise VGA Pro
    Hercules MONO               Quadram VGA
    Hercules Color              Sigma EGA
    IBM EGA                     Sigma VGA/H
    IBM VGA                     STB EGA
    IDS-VGA                     Tecmar VGA
    Orchid VGA                  Vega Plus EGA
    Paradise Auto               Vega Plus Vga

 The following personal computers were tested:

    Acer 710                    NCR PC-916
    Acer 910                    Olivetti PC 286
    Acer 1100                   Olivetti PC 386
    AST Premium/386             PC's Limited
    AT&T PC 6300                Sharp PC 4521
    AT&T PC 6300 Plus           Sperry PC/IT
    Compaq Deskpro 286          Tandon Targa 20
    Compaq Deskpro 386          Tandon Targa 40 Plus
    Compaq Deskpro 386/20       Tandy 1000
    Compaq Deskpro 386/25       Tandy 1000 EX
    Compaq Portable             Tandy 1000 TX
    Compaq Portable II          Tandy 1200
    Compaq Portable III         Tandy 3000
    Compaq Portable 286         Tandy 4000
    Compaq Portable 386         TI Business Pro (AT Mode)
    DataVue Snap 1+1            Toshiba TI 1200
    DEC Vaxmate                 WYSE PC 286 2108
    Dell System 200             WYSE PC 286 2112
    Dell System 310             WYSE PC 286 2200
    DG One 2T                   WYSE PC 286 2214
    Epson Equity LT             WYSE PC 386 3216
    Hewlett-Packard Vectra PC   Zenith Z-150
    IBM PC                      Zenith Z-151
    IBM PC/XT                   Zenith Z-159
    IBM PC/AT                   Zenith Z-181
    IBM PC Convertible          Zenith Z-183
    IBM PS/2 Model 30           Zenith Z-248
    IBM PS/2 Model 50           Zenith Z-248/12
    IBM PS/2 Model 60           Zenith Z-286
    IBM PS/2 Model 80           Zenith Z-286 SuperSport
    NCR PC-6                    Zenith Z-386
    NCR PC-810                  Zenith Z-286 LP
                                Zenith Turbo Sport


 33. Can't Supress References to ILINK in NMAKE File

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM S_NMAKE buglist2.00
 Last Modified: 12-FEB-1990    ArticleIdent: Q58001
 Question:

 I have seen that ILINK shows up in my NMAKE file that is created by
 QuickC Version 2.00, even after turning off the incremental linker. Is
 there any way to tell QuickC not to include ILINK in the NMAKE file?

 Response:

 The following steps will prevent the NMAKE file from referencing the
 Incremental Linker:

 1. Select Release in the "Select Build Flags" dialog box of the
    Options.Make menu. The program can no longer be debugged from within
    the QuickC environment.

 2. Build the program from within the QuickC environment.

 3. Manually edit the NMAKE file by changing the following line

       ilink -a -e "link $(LFLAGS) @$(PROJ).crf" $(PROJ)

    to read as follows:

       link $(LFLAGS) @$(PROJ).crf $(PROJ)

 Microsoft has confirmed this to be a problem with Microsoft QuickC
 Version 2.00. We are researching this problem and will post new
 information here as it becomes available.


 34. Shelling to DOS Produces "Out of Memory" Message

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40218

 In the QuickC environment, there is an option under the File menu to
 shell out to DOS. Choosing this option creates a new shell of
 command.com by using existing available memory. If there is not enough
 memory to successfully load the shell, you receive the pop-up message
 "Out of Memory." This message means that there was not enough memory
 to spawn command.com; it does not necessarily mean that QuickC itself
 is out of memory.


 35. CTRL+INS Fails after Initial Use on Some Clones

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 31-OCT-1989    ArticleIdent: Q40222

 In the QuickC editor, the CTRL+INS key combination for the PASTE
 function may fail after the first use on some clones. The major
 symptom of this problem is that the CTRL+INS will PASTE once, but will
 fail for all subsequent attempts. This failure will continue until the
 INS key is pressed outside QuickC at the DOS command prompt.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 The workaround is to use the corresponding PASTE function under the
 Edit menu.

 Note: Only the CTRL+INS combination suffers from this problem. The INS
 key alone and SHIFT+INS perform as expected.

 The following sequence of events will determine if your machine
 suffers from this problem:

 Keystrokes         Comments

  1. QC              a. Enter QuickC.

                     b. Highlight some text and choose "Cut"
                        under EDIT menu.

  2. CTRL+INS        This should work correctly the first time.

  3. CTRL+INS        This should fail (on all subsequent attempts
                     as well).

  4. ALT+F, X        Exit QuickC.

  5. QC              a. Reenter QuickC.

                     b. Highlight and Cut some text.

 6. CTRL+INS        This should fail (the BIOS bit is still set).

 7. ALT+F, X        Exit QuickC.

 8. INS             At the DOS prompt, press the INS key.
                    (This clears the BIOS bit.)

 9. QC              a. Reenter QuickC.

                    b. Highlight and Cut some text.

 10. CTRL+INS        Insertion should work.

 11. CTRL+INS        This should fail.

 The problem occurs because the BIOS bit, which indicates that the INS
 key is currently held down, is not being cleared. When this bit is
 set, the BIOS does not put a character in the keyboard queue when it
 sees the INS key go down (so that the INS key does not autorepeat).



 36. Logitech Mouse  Driver May Fail in 43/50...Line Mode

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUN-1989    ArticleIdent: Q40223

 There is a problem with the Logitec mouse driver (Version 3.42), which
 makes it incapable of dealing with screens that are 50 lines high.
 Version 3.42 of the driver correctly deals with 43-line screens;
 however, earlier versions of the Logitec driver do not work properly.

 If you invoke QuickC with the "/h" option, it will come up in the
 highest possible number of lines that your video card can support.
 Most VGA cards support a 50-line mode.

 If you are having problems with mouse support for high-resolution
 screens, and you have a Logitech mouse driver, please contact Logitec
 for an update to the driver software.


 37. Rare Problem with /Exepack Linker Option Can Hang QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser | s_link buglist2.00
 Last Modified:  3-MAR-1989    ArticleIdent: Q40224

 There is a problem in the /EXEPACK option of the linker that can hang
 programs within QuickC. This problem affects the small- and medium-memory
 models only.

 If the program's initial SS:SP is within one of two very small ranges
 of the first 312 bytes of the minalloc region, and if an interrupt
 occurs immediately before the instruction in the unpacking module that
 jumps to the original CS:IP, then the program hangs.

 The minalloc region is the start of uninitialized data at the end of a
 program, i.e., bss + stack in a non-far-data program.

 As a result, the stack must be 312 bytes or less (the size of the
 unpacking module) for the problem to occur. Even then, there is only
 an 18/312 (6 percent) chance, depending on the initial SS:SP. (18 is the
 total size of the two unsafe regions.)  Also, there must be less than
 312 bytes of near bss for this problem to occur.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.



 38. Error in Run-Time Library Examples for Font Functions

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |  fonts.c
 Last Modified: 31-OCT-1989    ArticleIdent: Q40231

 The example program for the Font functions in the graphics library
 contains the following incorrect source line:

    strcat (fondir, "\*.fon") ;

 This line should be corrected to read as follows:

    strcat (fondir, "\\*.fon") ;

 This example program is listed in the Online help facility in QuickC
 Version 2.00. This error afflicts all the Font family functions that
 consist of the following:

     _registerfonts, _setfonts, _outgtxt,
     _unregisterfonts, _getfontinfo, _gettextextent.


 39. Elaboration of Debug History in QuickC Version 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40237

 Debug history allows you to record and play back debugging session
 commands and program input that were used within the QuickC Version
 2.00 environment. This history is useful in the following situations:

 1. Recreating circumstances that led to an error

 2. Saving work from one edit/debug session to another

 3. Tracking hardware-related problems

 This history consists of the following:

 1. All commands that affect the flow of control of your program.

 2. Location programs where execution was paused and control was
    returned to you. These "history points" include breakpoints,
    watchpoints, and single steps.

 Note: Do not use a custom editor if you plan to use debug history. The
 history file denotes debugging events by source-line numbers. The
 QuickC editor can update the line numbers if you change the source
 code. Custom editors cannot. As a result, these editors may cause
 synchronization problems.

 Debug history is like a tape recorder. It controls two "tapes":
 a debug command tape and a user-input tape.

 To turn on the tape recorder, pull down the Debug menu and choose the
 History On selection.

 Debug Command Tape

 The simplest form of history allows you to browse the flow of your
 program during a debug session.

 You can also re-execute some or all of the commands on the history
 tape. The Undo selection in the Debug menu replays the tape from the
 beginning to one before the last command on the tape. You might want
 to do this if you have gone one too far in a debugging session, or
 have modified a value and regret it.

 A more general form of Undo also is available. The Replay selection
 under the Debug menu re-executes the tape from the beginning to the
 current browse point on the tape. Undo is a shorthcut method for doing
 a bunch of SHIFT+F10's to get to the end of the tape, then a SHIFT+F8
 to back up one, and then a "Replay" to replay up to that point. For
 example, you can use SHIFT+F8 to browse back eight steps, then do
 "Replay" to re-execute all but these last eight steps. You can then
 use SHIFT+F10 to browse forward two more steps, and then "Replay" to
 re-execute those two steps, etc.

 In this way, you can re-execute your debugging session as slowly or as
 quickly as you like. At each point you can perform additional
 debugging commands (watch values, view the output window, etc.) to
 find out more about your program. If you decide you don't want to
 replay the remainder of the tape, you can type new debug commands (F7,
 F10, etc.). The commands will overwrite the remainder of the tape
 (after warning you).

 If you browse to the end of the tape, the Replay selection replays the
 entire session. You might want to do this to redo all of your
 debugging commands, but use different program input, as discussed
 next.

 User-Input Tape

 The user-input tape records keyboard input to your program. When you
 type input to your program, it is recorded to the user-input tape.
 When you choose the Replay selection under the Debug menu, this
 user-input tape is used as the source of input (so you don't have
 to retype it from the keyboard). If the user-input tape runs out of
 input, it automatically reverts to the keyboard, and records the new
 input onto the end of the tape.

 The user-input tape is not affected by the browse commands
 SHIFT+F8/F10. Instead, it tracks the actual execution of your program.
 At a given point, the tape head is at the point in the user-input tape
 that will be read next by your program.

 You can truncate the user-input tape from this point to the end by
 choosing the Truncate selection under the Debug menu. If you want
 to use identical input, choose Replay. If you want to use
 entirely new input, choose Restart and then Truncate. If you
 want to use some of the input, choose Replay to the point of interest
 and then Truncate (to truncate at that point), then continue.

 Options

 Under the Options menu there is a Run/Debug selection that allows you
 to specify which tape (debug command and/or user input) you want to
 use. Turning on history turns on those tapes you have specified.

 Hints

 Use SHIFT+F8/F10 to review your debugging session results.

 Choose Undo under the Debug menu when you've run your program one step
 too far.

 If you wonder why you reached a breakpoint, turn on history, turn on
 animate, set a breakpoint, and go to the breakpoint. The tape contains
 a complete single-step record of how you got there. You can use
 SHIFT+F8/F10 to browse that record.

 To rerun your program with the same user input, but different debug
 commands, enable the user-input tape and disable the debug command
 tape.

 To rerun your program with the same debug commands, but different
 user input, enable the debug command tape and disable the
 user-input tape.


 40. QC 2.00 SAMPLES.DOC: Sample Program Descriptions

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40315

 The following information about sample programs is taken from the
 SAMPLES.DOC file included with the Microsoft QuickC Compiler Version
 2.00.

 In addition to the reference and "C For Yourself" manual examples in
 the QC Advisor, the following sample programs are provided with
 QuickC:

    Files              Description

    GRDEMO.MAK         GRDEMO illustrates general graphics techniques
    GRDEMO.C           including drawing, animation, palette
    MENU.C             switching, window adjustment, menus, and
    MENU.H             turtle graphics. The MENU and TURTLE modules
    TURTLE.C           are independent modules that could be used
    TURTLE.H           in your own programs.

    LIFE.MAK           LIFE illustrates general C and inline assembler
    LIFE.C             techniques. In particular, it shows how to write
    TOOLS.C            entire screens to the screen buffer. The TOOLS
    TOOLS.H            module contains independent functions and
                       macros that could be used in your own programs.

    CHRTDEMO.MAK       CHRTDEMO illustrates presentation graphics
    CHRTDEMO.C         techniques. You can use this program as a tool
    CHRTSUPT.C         for testing different modes and options before
    CHRTDEMO.H         building them into your own programs.

    CRLF.C             CRLF is a tool for converting certain files that
                       can not be loaded into the QC environment. It
                       removes unwanted control characters and ensures
                       that each line is terminated by a carriage-return/
                       line-feed pair. CRLF.EXE is also provided on the
                       utilities disk.


 41. QC 2.00 SAMPLES.DOC: Note on Graphics Libraries

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40316

 The following information about graphic libraries is taken from the
 SAMPLES.DOC file from Microsoft QuickC Compiler Version 2.00.

 GRDEMO and LIFE require GRAPHICS.LIB. CHRTDEMO requires GRAPHICS.LIB
 and PGCHART.LIB. If you did not request these libraries in your
 combined library files during setup, you will get "unresolved
 external" linker errors when you try to compile the programs.

 If you are using the QC environment, you must add the appropriate
 library names to the program list (.MAK) files. For example, if you
 want to compile LIFE, select Edit Program List from the Make menu. A
 dialog box will appear showing the contents of the LIFE.MAK program
 list. Enter the name GRAPHICS.LIB at the File Name prompt and select
 the Save List button.

 If you are using QCL, specify the library names on the command line.
 For example, use this command line to compile LIFE:

    QCL life.c tools.c graphics.lib


 42. QC 2.00 SAMPLES.DOC: Note on Name Convention

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40317

 The following information about name conventions is taken from the
 SAMPLES.DOC file from Microsoft QuickC Compiler Version 2.00.

 Two example programs, CHRTDEMO and GRDEMO, use a subset of the naming
 conventions used in OS/2 and Windows include files. In this
 convention, the first character of an identifier is a lowercase letter
 called a prefix. Common prefixes include p (pointer), a (array), i
 (index), and c (count). After the prefix, there may be an additional
 lowercase tag, usually indicating type. Common tags include ch (char),
 f (flag), sz (zero-terminated string) l (long), and x or y (x or y
 coordinate). Following this there may be one or more qualifiers, each
 beginning with an uppercase letter. For example, an identifier called
 achFileName is an array (a) of characters (ch) containing a file name
 (FileName).


 43. Setting Up QuickC Version 2.00 on a Two-Floppy Machine

 Product Version(s): 2.00   | 2.00
 Operating System:   MS-DOS | OS/2
 Flags: enduser |
 Last Modified: 17-JAN-1989    ArticleIdent: Q40322

 The following article contains one possible setup configuration for
 installing QuickC Version 2.00 on a two-floppy machine (360K). This is
 not the only setup configuration. Although the combination listed
 below will minimize disk swapping, it is not as practical for large
 programs as other configurations that require an additional disk(s)
 for your libraries.

 The following are the four steps to this setup:

 1. Below is a description of the distribution of QuickC Version 2.00
    files over five 360K floppies. After each disk number is a list
    of files that you need to copy to that disk. The following is the
    description:

       disk 1:   qc.exe

       disk 2:   qcc.ovl
                 c1.err
                 cl.err
                 link.exe
                 ilink.exe
                 ilinkstb.ovl

       disk 3:   qc.hlp

       disk 4:   qcenv.hlp
                 errors.hlp
                 graphics.hlp
                 notes.hlp
                 (There is plenty of room left on this disk for
                 addition help files.)

       disk 5:   \include\*.h    (It is best to copy just the header
                                  files that you require.)
                 \include\sys\stat.h
                 \include\sys\timeb.h
                 \include\sys\types.h
                 \include\sys\utime.h
                 \include\sys\locking.h
                 \lib\xlibce.lib (without graphics.lib or pgchart.lib)
                 source files

       The following are notes on disk 5:

       The notation "\include\*.h" means that you must create a
       directory named "include" on disk five, and copy the necessary
       header files (files with the .h extension) to this directory.
       "\include\sys\.." means that you must create a subdirectory
       "sys" inside the "include" directory and copy the files listed
       into it.

       If you copy all of the header files, there is room for a
       combined library without any graphics, and about 45K remains for
       your source file. Due to this behavior, it's better to only copy
       needed header files. If you want to use graphics or pgchart, in
       all practicality, you should put your library or libraries onto
       another disk, and swap when the linker asks for it.

       The notation "\lib\xlibce.lib" means you must create a "lib"
       directory and copy a combined library to this directory.
       xLIBCE.LIB is your combined library where "x" is S, M, C, or L
       (small, medium, compact, or large).

       To build the combined libraries, you can invoke the SETUP.EXE
       program to specifically build them for you. Type "setup /L" (use
       /L, not /l).

 2. Set your environment variables as follows:

       PATH=a:\;b:\
       set INCLUDE=b:\include
       set LIB=b:\lib

    You can set these variables at the DOS command prompt
    ("set path=a:\;b:\") or you can place these settings within
    a batch file. When typing these variables, it is vital that
    you do not add extraneous characters (such as spaces) to them
    because they will mislead DOS. The following lists two common
    errors when setting environment variables:

       set path = a:\;b:\ <enter>    <--spaces invalidate this setting.
       set path=a:\;b:\ <space(s)><enter>  <--spaces at the end also
                                              invalidate the setting.

 3. Add the following two lines to your CONFIG.SYS file:

       files=20
       buffers=15

    (You must reboot after this modification for the changes to take
    effect.)

 4. Make Drive B: your default drive by typing "B:".

 If you have further questions concerning Setup, libraries,
 environment variables, or specific component files of QuickC,
 please refer to the following source listings in the
 "Microsoft QuickC Up and Running" manual:

    Setup:

       1. Page 15, "Installing on a Floppy-Disk System"

       2. Page 6, "Running Setup"

    Libraries:

       1. Page 7, "Understanding Libraries"

       2. Page 8, "First Screen: The Libraries"

    Environment Variables:

       1. Page 14, "Modifying CONFIG.SYS"

       2. Page 13, "Setup Stage Three"


 44. QuickC 2.00 Does Not Automatically Change Memory Models

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40484

 On Page 15 of the January 16, 1989 edition of InfoWorld the article
 "Microsoft Offers Quick C Upgrade" appeared, which contained the
 following quote from a Microsoft marketing manager:

    "QuickC 2.00 detects when you've gotten to the end of the current
    memory model and will automatically pop to the next model."

 This is an error and is not reflective of any actual QuickC ability.
 If the current memory model is insufficient for compilation or
 linking, then error messages are produced and you have to re-examine
 the code or choose the option for a different, more adequate memory
 model.


 45. Watching Pointers in QuickC Debugger

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40494

 The QuickC debugger makes a distinction between pointers of type CHAR
 and all other types. The debugger will assume that any "char *"
 pointer will contain the address of a Null terminated string.

 The impact of this assumption can be seen when setting a WATCH VALUE
 on a specified pointer. If the pointer is declared as "char *", then
 the debugger displays the WATCH value as the string that is pointed to
 by the pointer. If the pointer is declared as any type other than
 "char *", then the WATCH value displays the address of the variable
 and not the value of the variable.

 The following code fragments illustrate this distinction:

 char *CHptr = "Faust liebt Gretchen" ;
 int  *INTptr= "Faust liebt Gretchen" ;

 A WATCH set on CHptr displays the following:

    "Faust liebt Gretchen"

 A WATCH set on INTptr displays the address of the string and not the
 string itself:

    'Faust liebt Gretchen'

 If you want to WATCH the string pointed to by INTptr, do the
 following:

 1. Pull down the DEBUG menu.

 2. Choose the WATCH VALUE selection.

 3. Type "(char *)INTptr".

 Casting INTptr to "char *" type displays the character string.

 If you want to WATCH the address of the string to which CHptr points,
 do the following:

 1. Pull down the DEBUG menu.

 2. Choose WATCH VALUE.

 3. Type "(int *)CHptr".

 Casting CHptr to a type other than "char *" (such as "int *")
 displays the address of the string to which CHptr points.


 46. QuickC 2.00 Lacks the Ability To Print Chart Screens

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40495

 Although QuickC Version 2.00 includes a Presentation Graphics library,
 PGCHART.LIB, which offers the ability to generate presentation charts,
 there is no utility to print the graphics screen to a printer.

 There are third-party utilities that are specifically designed to
 capture graphics screens and save them in printable files.

 Microsoft is actively considering the addition of this abitliy
 in a future release of QuickC.



 47. Explanation of Linkers Shipped with QuickC Version 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q40503

 There are three linkers shipped in the QuickC Version 2.00 package.
 The following information explains their abilities and their intended
 uses.

 Distribution

 Disk 2

 1. link.exe "Microsoft Segmented Executable Linker Version 5.02"

 This linker is designed for Windows and OS/2 development. Unless you
 are developing for these platforms, you should avoid this linker. It
 can be used on both the DOS and OS/2 operating systems. If you are
 programming for Windows with the SDK, then you should use this
 linker in lieu of LINK4.EXE which is shipped with the Windows SDK
 package.

 Disk 3

 1. link.exe "Microsoft QuickC Linker Version 4.06"

 This linker is designed for the majority of QuickC programs. It is an
 overlay linker and as such is restricted to DOS. This linker
 understands object modules produced by other products such as
 Microsoft C Versions 5.10 and 5.00, Microsoft FORTRAN Versions 4.10
 and 4.01, Microsoft Pascal, and the Microsoft Assembler.

 2. ilink.exe "Microsoft Incremental Linker Version 1.10"

 This is the incremental linker that links only those object modules
 that require re-linking due to code changes within them.

 The ilink linker is not designed to replace Link4.exe, which is
 shipped with the Windows SDK. If you are programming for Windows, you
 must use the linker 5.02, which is discussed above.

 The "QuickC Linker" Version 4.06 should be used unless you
 specifically require the Segmented Executable linker for Windows or
 protected-mode applications.

 If you are in doubt as to which linker to use, copy "link.exe" from
 Disk 3 into your \QC2\BIN directory (or wherever you have set up your
 QuickC executable files). You also should copy "ilink.exe" to this
 directory.

 To ensure that you have the appropriate linker, go to the directory
 where you plan to run QuickC and type "link" at the DOS command line.
 You should see the following on your screen:

    Microsoft (R) QuickC Linker  Version 4.06
    Copyright (C) Microsoft Corp 1984-1989.  All rights reserved.

    Object Modules [.OBJ]:      <press CTRL+C  to break out>

 If you get a different version number, you must check your path
 variable. You may have an additional linker on your disk that was
 found in your path before DOS reached the \QC2\BIN directory. Changing
 your path so that \QC2\BIN is the first directory in your path is the
 easiest and quickest way to correct this problem.


 48. Types And Variations of Charts That Can Be Produced by QC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1989    ArticleIdent: Q40504

 QuickC Version 2.00 can produce the following types of charts and
 their variations.

 1. Pie Charts

    a. Exploded (one or more pieces ) or Not Exploded.

    b. Values with percentage labels or unlabeled.

 2. Bar Charts

    Plain or Stacked Bars

 3. Column Charts

    Plain or Stacked columns

 4. Line Charts

 5. Scatter Charts

 The following additional options also are available:

 1. Grid Lines

    Solid, dotted, dashed, or a combination of these

 2. Autoscaled Axis, logarithmic axis, or user-defined scale

 3. Legends

 4. Text labels

 5. Chart and legend size, screen position, and border type

 6. Background, foreground colors, and fill patterns

 7. Selectable point marker characters (for line and scatter charts)


 49. Compaq ADAPT.COM TSR Is Not Compatible with QC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1989    ArticleIdent: Q40519

 The Compaq Computer Corporation produces a memory-resident tool called
 ADAPT.COM that is used to change the manner in which intensified
 characters are displayed on the screen. It is used most often for
 liquid crystal displays (LCDs) and plasma screens on portables.

 Invoking ADAPT.COM (CTRL+SHIFT) while inside the QuickC Version 2.00
 environment will hang the computer; you will need to reboot your
 machine. The typical symptom of this hanging is that the
 terminate-and-stay-resident program (TSR) will adamantly refuse to
 release your computer and allow a return to QuickC.

 Version 2.00 of the Microsoft QuickC compiler is not compatible with
 this TSR. To avoid this conflict, you must adhere to the following:

 1. Do Not invoke ADAPT.COM within the QuickC 2.00 Environment.
 2. Execute ADAPT.COM before or after QuickC Editing Sessions.

 Microsoft has confirmed this problem with Version 2.00 of the QuickC
 compiler. Microsoft will post new information as it becomes available.



 50. Norton's Guide Hangs QuickC Version 2.00

 Product Version(s): 2.00   | 2.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.00
 Last Modified: 24-JAN-1989    ArticleIdent: Q40575

 Peter Norton Computing produces a TSR called The Norton Guides
 (NG.EXE) that provides online help for many programming issues.
 Pressing the hotkey to invoke this utility, while you are in the
 QuickC Version 2.00 environment, activates Norton's pop-up window.
 However, further keystokes are futile. Your system hangs and rebooting
 is the only solution.

 The workaround is to avoid invoking the Norton Guide from within
 QuickC 2.00.  Invoking the Guide outside of QuickC 2.00's environment
 is not a problem.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.



 51. Compiling Windows Programs with QuickC Requires 640K

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JAN-1989    ArticleIdent: Q40576

 The command line compiler for QuickC Version 2.00, QCL, generates code
 for Microsoft Windows. However, the command line options for producing
 this code are not available within the QuickC environment.

 Due to the size of WINDOWS.H, the include file necessary for
 Windows programming, 640K is required to compile any source file
 using the file.

 On a 512K machine, QCL fails with the following error when you compile
 the WINDOWS.H header file:

    C1002 : Out of heap space


 52. Why #ifdef and #ifndef Are Used in PGCHART.H

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q40680

 The header file PGCHART.H, which is required for programs using QuickC
 2.00's Presentation Graphics, contains many #ifdef and #ifndef
 preprocessor commands. This include file has these commands so you
 will not get warnings or errors if you happen to include the file more
 than once.

 These commands are provided in all of the include files where
 structures (or types) are typedef'ed; it is just a little more obvious
 in PGCHART.H because it defines so many structures.


 53. Using _dos_setdrive and _searchenv to Open a File

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41025

 Question:

 How can I open a file on a floppy drive without explicitly specifying
 a full path in the fopen statement?

 Response:

 You can use the run-time function _dos_setdrive to set the current
 drive to floppy Drive A. Then use the function _searchenv to search
 for the filename on a floppy disk in Drive A. The full path to the
 specified file will be copied to the buffer. Then you can use fopen to
 open the file specified by the buffer.

 Note: _searchenv works properly using QuickC Version 2.00. This
 program will not work correctly under the earlier versions of QuickC
 or C Version 5.10.

 The following is a sample code:

 #include <dos.h>
 #include <stdio.h>
 #include <stdlib.h>

 main()
 {
     FILE *stream;
     unsigned drive;
     char buffer[40];

     /* set default drive to be drive A */
     _dos_setdrive (1, &drive);
     _dos_getdrive (&drive);
     printf( "Current drive: %c:\n", 'A' + drive - 1 );

     /* Search for file at root level */
     _searchenv("data","",buffer);
     printf("path: %s\n", buffer);

     if ((stream = fopen(buffer,"r")) == NULL)
        printf ("Could not open file\n");
     else
        printf("File opened for reading\n");
 }


 54. Failure to Set Video to Text Mode When Swapping to Environment

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 apnote buglist2.01 s_quickasm
 Last Modified: 11-OCT-1989    ArticleIdent: Q41078

 QuickC Version 2.00 and QuickAssembler 2.01 do not run properly
 on some computers equipped with CGA and Olivetti graphics adapters.
 When the display is in a graphics mode when QuickC swaps in the
 integrated environment screen, the video is not set to color text
 mode as it should be. The result is an unreadable graphics screen.
 The QuickC environment is still operable, but movement through
 the menus must be done by memory.

 Microsoft has confirmed this to be a problem in Versions 2.00 and
 2.01. There is a patch available that corrects the QC.EXE file in both
 QuickC 2.00 and QuickAssembler so that they properly switch video
 modes when swapping the QuickC screen and the program's output screen.

 Please contact Microsoft Product Support Services at (800) 454 2030 to
 obtain this patch.

 This problem can be observed in the following three ways:

 1. If the display is in a graphics mode when QuickC is invoked, QuickC
    remains in graphics mode. To work around this problem, use the DOS
    command MODE CO80 to set your display to text mode prior to invoking
    QuickC.

 2. Use the following program:

       #include <graph.h>
       void main (void)
       { _setvideomode (_MRES4COLOR);
       }

    When the above program is executed within the QuickC environment
    (with F5) and a key is pressed to return back to QuickC, QuickC
    remains in graphics mode. The workaround is to add the following
    line:

       _setvideomode (_DEFAULTMODE);

 3. Given the above program, press F8 twice to single step past the
    _setvideomode function. The video will remain in graphics mode
    when swapping back to the environment.

    This scenario is the most severe. This prohibits one from debugging
    a program that uses any graphics mode within the QuickC environment.

 This problem has been observed on the following equipment:

    AT&T 6300 (8086, ROM-BIOS Version 1.43, MS-DOS Version 3.30)
    Compaq Portable (8088, MS-DOS Version 3.30)
    IBM PS/2 Model 80 (8514 Monitor, MS-DOS 3.30)

 The following are videomodes with which this has been observed:

    _MRES4COLOR
    _HRESBW
    _ORESCOLOR



 55. Huge Arrays Not Allowed in QuickC 2.00, But Huge Pointers Are

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890209-11614 buglist2.00
 Last Modified: 28-FEB-1989    ArticleIdent: Q41094

 The program below produces the following errors when compiled with
 QuickC Version 2.00, even when using huge-memory model (/AH):

    prog.c(4) : error C2125: a : allocation exceeds 64K
    prog.c(8) : error C2125: b : allocation exceeds 64K

 The following is the program:

 #include <stdio.h>

 short a[64000];

 main()
 {
 static short b[64000];
 }

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 "Huge support" for QuickC means that we perform proper arithmetic for
 huge items. It does not mean that we allow huge items to be
 declared -- only pointers to them.

 To work around this problem, declare the pointer, then use halloc to
 allocate the memory. The pointer will be addressed properly. Note: C
 Version 5.10 does allow declarations of huge items.

 Below is a sample program that demonstrates the workaround. Once
 memory for the array has been allocated, the pointer to the base type
 of the array may be treated exactly as you would have treated an
 array.

 The following is the program:

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

 #define MAX 33000L

 unsigned huge *a;

 void main(void)
 {
 unsigned huge *b;
 unsigned i;

     a = halloc(MAX, sizeof(unsigned));  /* allocate "global" array */
                 /* IMPORTANT--make sure the allocations worked! */
     if (!a) { puts("a is NULL");  exit(1);  }
     b = halloc(MAX, sizeof(unsigned));  /* allocate "local" array */
         if (!b) { puts("b is NULL");  exit(1);  }

     for (i = 0; i < MAX; i++)  {    /* access memory as arrays */
                 a[i] = i;
                 b[i] = (unsigned)MAX - i - 1;
         }

     for (i = 0; i < MAX; i++)  {    /* check to make sure it's OK */
                 if (a[i] != i)  {
                         printf("a[%u] is %u rather than %u\n",
                                 i, a[i], i);
                         exit(2);
                 }
                 if (b[i] != (unsigned)MAX - i -1)  {
                         printf("b[%u] is %u rather than %u\n",
                                 i, b[i], (unsigned)MAX - i -1);
                         exit(2);
                 }
         }
         puts("Test passed");
         exit(0);
 }


 56. The Steps Required to Create a Chart in QuickC Version 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q41105

 The following steps provide a guideline for creating a simple chart
 with QuickC Version 2.00:

 1. Include all necessary header files. These will include PGCHART.H,
    GRAPH.H, and any other include files required by other routines in
    your program.

 2. Assemble the chart data in arrays, one single-dimensioned
    array per axis. (More for the value axis if creating a chart
    of a type that supports multiple series).

 3. Set the video mode to graphics with _setvideomode().

 4. Initialize the presentation graphics environment with
    _pg_initchart() and _pg_defaultchart().

    _pg_initchart() initializes the chart linestyle set, default
    palettes, screen modes and character fonts. It must be called
    before any other charting function.

    _pg_defaultchart() initializes all necessary variables in the chart
    environment for the specified default chart and chart style.

 5. (optional) Customize your chart with the structures defined in
    PGCHART.H. Add grid lines, size the chart, change colors, etc.

 6. Call the presentation graphics function that actually creates
    the screen image, using your customized-charting environment.

    _pg_chart:          creates a column, bar, or line chart for a
                        single series of data.

    _pg_chart:          creates a column, bar, or line chart for
                        multiple series of data. All series must be
                        the same length.

    _pg_chartpie:       creates a pie chart for a single series of
                        data.

    _pg_chartscatter:   creates a scatter chart for a single series
                        of data.

    _pg_chartscatterms: creates a scatter chart for a single series
                        of data.

 7. Pause while the chart is on the screen. Wait for a keystroke with
    getch() or kbhit(), or add a timing loop.

 8. Reset the video mode with _setvideomode(_DEFAULTMODE).

 The following program illustrates the above steps, and creates a line
 chart with grid lines from a single data series:

 /*create line chart with grid lines from one data series*/

 #include <conio.h>
 #include <string.h>
 #include <graph.h>                 /* required include files */
 #include <pgchart.h>

 #define MONTHS 12

 typedef enum {FALSE, TRUE} boolean;

 float far value [MONTHS] =          /*value (series) data array */
 {
  75.00, 50.00, 100.00, 45.00, 25.00, 10.00,
  80.00, 5.00, 10.00, 15.00, 14.00, 55.00
   };

 char far *category[MONTHS] =         /* category data array */
   {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   "Jly", "Aug", "Sep", "Oct","Nov", "Dec"
   };

 main()

 {
 chartenv env;                /* define chart environment variable */

 _setvideomode(_ERESCOLOR);   /* set to graphics mode */
      /* initialize chart library and a default line chart */
  _pg_initchart();
  _pg_defaultchart(&env, _PG_LINECHART, _PG_POINTANDLINE);

  /*add titles and some chart options -- customize the chart */

  strcpy(env.maintitle.title,"Generic Analysis "); /* title text */
  env.maintitle.titlecolor = 6;                  /* set title color */
  env.maintitle.justify= _PG_RIGHT;              /* and position */
  strcpy(env.subtitle.title, "Year End Report"); /* subtitle text */
  env.subtitle.titlecolor+6;                     /* subtitle color  */
  env.subtitle.justify=_PG_RIGHT;                /* subtitle position */
  strcpy(env.yaxis.axistitle.title, "Month");    /* y-axis title */
  strcpy(env.xaxis.axistitle.title, "Amount");   /* x-axis title */
  env.xaxis.grid = TRUE;                         /* x-axis grid lines */
  env.yaxis.grid = TRUE;                         /* y-axis grid lines */
  env.xaxis.axiscolor = 2;                       /* color for x-axis */
  env.yaxis.axiscolor = 5;                       /* color for y-axis */
  env.xaxis.autoscale = FALSE;                   /* turn off autoscaling */
  env.xaxis.scalemax = 100.00;                   /* max x-axis value */
  env.xaxis.scalemin = 0.00;                     /* min x-axis value */
  env.xaxis.ticformat = _PG_DECFORMAT;   /* format for x-axis tick-marks*/
  env.yaxis.ticinterval = 1.00;          /* interval for y-axis tickmarks*/
  env.xaxis.ticinterval = 5.00;          /* interval for x-axis tickmarks*/

 /* display the chart on the screen */

 if(_pg_chart (&env,category,value, MONTHS)) /* call to charting routine*/
     {_setvideomode(_DEFAULTMODE);       /* error trap...*/
      _outtext("error, can't draw chart");
      }
      else
     {
      getch();                          /* wait for a keystroke */
      _setvideomode( _DEFAULTMODE);     /* restore the video mode */
      }
     return(0);
 }


 57. No Registration Card Included in Upgraded Products

 Product Version(s): 1.01 1.00 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | update s_pascal s_c
 Last Modified: 28-FEB-1989    ArticleIdent: Q41127

 If you upgrade your products, you do not receive a new registration
 card in the upgrade package. Update notices are sent only to
 registered users. Once you have registered for a particular product,
 there is no reason to register again.



 58. Meaning Of "ILINK: ERROR: Invalid Flag Z"

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41128

 Summary

 If the QuickC environment is configured for incremental linking and
 for CodeView information, the error below occurs if the incorrect
 version of the Microsoft Incremental Linker is found along the search
 path. The message flashes quickly in the upper left-hand corner of the
 screen, then disappears. To determine the exact message text, it may
 be necessary to reproduce the error a few times, or use SHIFT+PRTSCRN
 to capture the error message. The error is as follows:

    Microsoft (R) Incremental Linker Version 1.00
    Copyright (C) Microsoft Corp 1988.  All Rights Reserved.

    ILINK:ERROR: invalid flag Z

 The correct version of the Microsoft Incremental Linker is 1.10 for
 QuickC Version 2.00; if the path is reconfigured to place the QuickC
 linker before the older linker (probably from C Version 5.10 or MASM
 Version 5.10), the error will not occur.

 The problem lies in the fact that the older Incremental Linker does
 not recognize the CodeView information switch.


 59. Mixing Memory Models with QuickC 2.00 and QCL 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 28-FEB-1989    ArticleIdent: Q41161

 If the memory models are incorrectly mixed within the QuickC Version
 2.00 environment (i.e., the compilation is done in small model, and
 the resulting .OBJ is linked to MLIBCE.LIB), the program appears to
 compile and link correctly. However, when QuickC tries to run the
 file, the program name echoes, the screen flickers, and you are
 returned to the QuickC Version 2.00 environment where an error-message
 dialog box says "Cannot find current location in source file."

 If the same make file is run outside of the QuickC environment, the
 program compiles, links, and runs successfully, as the linker uses the
 default library for the memory model that was used to compile.
 However, if a library for another memory model is explicitly added to
 the link line, for example, if the following line is executed,

    qcl /AS test.c /link mlibce.lib

 it will compile and link with no errors, and the resulting .EXE file,
 free from the error-recovery abilities of the QuickC environment,
 hangs the computer.

 This frequently happens with programs that are being ported from
 QuickC Version 1.01 to QuickC Version 2.00 because they are built with
 existing make files that specify the external library MLIBCE.LIB or
 MLIBC7.LIB explicitly. However, the default for the QuickC Version
 2.00 integrated environment is small model, and not medium, as was the
 case with QuickC Version 1.00 and Version 1.01.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.


 60. QCL Default Compile Options

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47781

 The QuickC defaults when compiling at the command line with QCL are as
 follows:

    /AS      - small memory model
    /F2048   - stack size of 2K
    /FPi     - inline 8087/80287 instructions
    /G0      - 8086/8088 instruction set
    /Gt32767 - data size threshold (compact, large, huge models only)
    /Ot      - optimize for speed
    /W1      - warning level
    /Ze      - enable Microsoft extensions

 To view the full list of command-line compiler options, type the
 following at the DOS prompt:

    QCL /help

 You can find detailed information about all the compiler options in
 the "Microsoft QuickC Tool Kit," Chapter 4, QCL command reference.


 61. QuickC Version 2.00 Supports Coprocessor Libraries

 Product Version(s): 1.x 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41195

 In QuickC Version 2.00 it is now possible to use the coprocessor
 libraries from within the QuickC environment.

 As documented in the QuickC Version 2.00 README.DOC file, you need to
 set the CL environment variable to use the co-processor libraries, as
 follows:

    CL=/FPi87

 When you compile within the environment, QuickC invokes the QCL
 command-line compiler that looks at the CL environment variable for
 any options that are set. When it sees the /FPi87 switch, it knows to
 invoke the co-processor libraries.

 This was not possible in QuickC Version 1.x because of the core
 library needing the emulator math package. In QuickC Version 2.00,
 the core library is gone so there is no restriction to the emulator
 math package.


 62. QCL 1.01 Can Bring Up QuickC 2.00 Integrated Environment

 Product Version(s): 2.00   | 2.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41196

 Problem:

 When I exit the environment, the process runs to completion
 with no errors, but no .OBJ file is built if I do the following:

 1. Type "QCL <filename>" at a DOS prompt to invoke the QuickC
    command-line driver. The copyright notice appears on the screen.

 2. The filename is echoed, and I load the QuickC Version 2.00
    environment.

 Response:

 This can only happen on a machine that has previously had QuickC
 Version 1.01 loaded. It demonstrates a path problem, and a conflict
 between the QuickC Versions 1.01 and 2.00. Type the command again, and
 the QCL copyright notice appears for Version 1.01.

 The QCL command line driver for QuickC Version 1.01 brings up the
 QuickC Version 2.00 Integrated Environment under the following
 conditions:

 1. The directory containing the file QCL.EXE from Version 1.01 is on
    the DOS path prior to the directory containing QC.EXE from Version
    2.00.

 2. You invoked QCL from a directory other than the /BIN directory
    for QuickC Version 2.00.

 3. The file QC.EXE for QuickC Version 1.01 is not present on the path.

 The QCL command line driver requires the file QC.EXE. The QCL driver
 for Version 1.01 uses QC.EXE from Version 2.00 if it does not first
 find the appropriate version along the path. However, the two are not
 compatible, and instead of compiling, the QuickC Version 2.00
 environment is brought up.

 This situation is the result of using QuickC Version 2.00 in an
 improper environment. The solution is to correct the path environment
 variable and/or remove all remnants of previous versions of the QuickC
 package.


 63. QuickC 2.00 Sporadically Fails to Exec Linker in 3.x BOX

 Product Version(s): 2.00
 Operating System:   0S/2
 Flags: ENDUSER | buglist2.00
 Last Modified: 29-MAR-1989    ArticleIdent: Q41197

 QuickC Version 2.00 appears to have sporadic problems exec'ing the
 linker in the OS/2 Version 1.10 DOS compatibility box.

 This problem has been shown to be related to the existence of the
 APPEND path.  If there is an APPEND path designated then this problem
 can occur.  If this problem, which is described in detail below, is
 encountered removing the APPEND, and then rebooting will alleviate
 this problem.

 The problem occurs when the QuickC Version 2.00 integrated environment
 is started in the 3.x box and a trivial program (e.g. "main()  { }" )
 is loaded. Small model is selected and you attempt a "rebuild all."
 The program compiles successfully, but fails in the link stage with one
 of the following two error messages:

 If the "Make" option is set to "debug", the following error message
 flashes quickly in the upper left-hand corner of the screen, and
 then disappears:

    R6005: Not Enough Memory On Exec

 If the Make option is set to "release", the following error message
 appears:

   MAKE:ERROR:

 However, shelling out of the QuickC environment reveals that the system
 has 280K available with QuickC loaded, and if an attempt is made to link
 the program while shelled out of the environment, it links with no
 errors.



 64. QuickC 2.00 README.DOC: Using QuickC on a Floppy System

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JAN-1990    ArticleIdent: Q41364

 The following information is taken from the QuickC 2.00 README.DOC
 file, Part 1, "Notes on 'Up and Running.'" The following notes refer
 to Page 16 of "Up and Running": Using QuickC on a Floppy-Disk System.

 QuickC requires certain files. One arrangement that works well for
 dual- floppy systems is this:

      disk 1:   qc.exe

      disk 2:   qcc.ovl
                c1.err
                link.exe
                ilink.exe
                ilinkstb.ovl

      disk 3:   qc.hlp

      disk 4:   qcenv.hlp
                errors.hlp
                graphics.hlp
                notes.hlp
                *.hlp (any additional help files)

      disk 5:   \include\*.h
                \lib\xlibce.lib (x = S, M, C, or L)
                your source files

 Set your environment as follows:

      PATH=A:\;B:\
      SET INCLUDE=B:\INCLUDE
      SET LIB=B:\LIB

 Make the B drive the default. This is by no means the only setup. It
 helps to minimize the swaps but may not be practical for large
 programs.


 65. TURTLE.C, MENU.C, TOOLS.C Not Stand-Alone Programs in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42848

 The sample source files TURTLE.C, MENU.C, and TOOLS.C included with
 the QuickC Version 2.00 compiler are not stand-alone programs. They
 are modules used by the programs GRDEMO.C, LIFE.C and CHRTDEMO.C.
 Attempting to compile and link one of these modules by itself will
 result in the following error message:

 xLIBCE.LIB(dos\crt0.asm) : error L2029 : '_main' : unresolved external

 In the above error message, "x" stands for the (S, M, C, L) memory
 model.

 Use the supplied NMAKE files to compile and link each of these three
 demo programs. To perform this procedure inside the QuickC 2.00
 environment, load the desired demo source file and set the program
 list to the corresponding NMAKE file (GRDEMO.MAK, LIFE.MAK, or
 CHRTDEMO.MAK). Outside the environment, you only need to type NMAKE
 followed by the desired NMAKE file name.


 66. Floppy Setup Only Installs the Libraries

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41248

 Page 15 of the "Microsoft QuickC Up and Running" manual incorrectly
 implies the setup program completely installs QuickC. The floppy setup
 is intended to install the C run-time libraries and allow you to
 manually configure QuickC to your system.

 There are too many variables involved for one generic setup to install
 QuickC effectively on all possible floppy systems.


 67. QuickC 2.00 README.DOC: ESC Key Does Not Stop Linker

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41249

 The information below is from "Part 1: Notes on 'Up and Running'" of
 the QuickC Version 2.00 README.DOC file.

 The following notes refer to specific pages in the QuickC Version 2.00
 "Up and Running" manual:

 A Brief Guide to the Keystrokes

 The chart on the inside front cover says that the ESC key "stops the
 compiler and linker from continuing." ESC stops the compiler but NOT
 the linker. Press CTRL+BREAK to stop both the compiler and the linker.

 If you are using the debugger and running a program that expects
 keyboard input, pressing either CTRL+C or CTRL+BREAK and then ENTER
 allows you to exit.


 68. How to Manually Setup QuickC Version 2.00 on a Hard Drive

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41250

 The following information explains how to manually set up Microsoft
 QuickC Version 2.00 for a hard disk. It will show you how to set up in
 the same way as the SETUP.EXE program.

 This information demonstrates how to set up QuickC Version 2.00 under
 the directory "QC2" on Drive C. You may change the name of any
 directory or the drive.

 1. Create the following directories:

    C:\QC2\BIN
    C:\QC2\LIB
    C:\QC2\TMP
    C:\QC2\SAMPLES
    C:\QC2\INCLUDE
    C:\QC2\INCLUDE\SYS

 2. Add the following to your AUTOEXEC.BAT file:

    SET LIB=C:\QC2\LIB
    SET INCLUDE=C:\QC2\INCLUDE
    SET TMP=C:\QC2\TMP
    SET PATH=C:\QC2\BIN

    (You may place this in a separate batch file if you prefer.)
    Note: It is important that you do NOT add spaces in or after these
    variables. For example, "SET LIB = C:\QC2\LIB" does not work
    correctly; neither does "SET LIB=C:\QC2\LIB  " because it has
    trailing spaces at the end.

 3. Add the following to your CONFIG.SYS file:

    FILES=20
    BUFFERS=20

    (You must reboot after this step for these changes to take effect.)

 4. Copy the following files into C:\QC2\BIN:

                               Distribution Disk Title
    File                  5.25-Inch Disk      3.5-Inch Disk

    HELPMAKE.EXE          Setup               Setup/Learning QC
    README.DOC            Setup               Setup/Learning QC
    MSHERC.COM            Setup               Setup/Learning QC
    FIXSHIFT.COM          Setup               Setup/Learning QC
    LINK.EXE              Learning QC         Setup/Learning QC
                          & Utilities         Utilities/QC Advisor
    QCL.EXE               Command Line Comp.  Command Line Comp/Lib 1
    QC.EXE                Integrated Env 1    Integrated Dev. Env.
    QCENV.HLP             Integrated Env 1    Integrated Dev. Env.
    NMAKE.EXE             Integrated Env 2    Integrated Dev. Env.
    QCC.OVL               Integrated Env 2    Integrated Dev. Env.
    C1.ERR                Integrated Env 2    Integrated Dev. Env.
    ILINK.EXE             Utilities           Utilities/QC Advisor
    CRLF.EXE              Utilities           Utilities/QC Advisor
    LIB.EXE               Utilities           Utilities/QC Advisor
    ERRORS.HLP            Utilities           Utilities/QC Advisor
    QCC.DAT               Utilities           Utilities/QC Advisor
    MOUSE.COM             Utilities           Utilities/QC Advisor
    QC.KEY                Utilities           Utilities/QC Advisor
    ME.KEY                Utilities           Utilities/QC Advisor
    EMACS.KEY             Utilities           Utilities/QC Advisor
    EPSILON.KEY           Utilities           Utilities/QC Advisor
    BRIEF.KEY             Utilities           Utilities/QC Advisor
    ILINKSTB.OVL          Utilities           Utilities/QC Advisor
    QC.HLP                MS QC Advisor       Utilities/QC Advisor
    QCCOM.EXE             Command Line Comp.  Command Line Comp/Lib 1
    GRAPHICS.HLP          Command Line Comp   Command Line Comp/Lib 1
    QCL.HLP               Command Line Comp   Command Line Comp/Lib 1
    CL.ERR                Command Line Comp   Command Line Comp/Lib 1

 5. Copy the following files into C:\QC2\INCLUDE:

    *.H       (All files with the .H extension except the following:
              TYPES.H, LOCKING.H, STAT.H, TIMEB.H, UTIME.H)

    These are located on the 5.25-inch disk labeled Integrated
    Development Environment 2 and the 3.5-Inch disk labeled Integrated
    Development Environment.

 6. Copy the following files into C:\QC2\INCLUDE\SYS:

    STAT.H
    UTIME.H
    TIMEB.H
    TYPES.H
    LOCKING.H

    (You will find these five files on the same disk as the other
    include files in a subdirectory called SYS.)

 7. Copy the following files into C:\QC2\SAMPLES:
    (Note: This step is optional. Copy these files only if you want the
    sample programs on your hard disk.)

    CFLOW.DOC
    *.FON     (All files with the .FON extension. These are on the
              3.5-inch disk labeled Libraries 3/Fonts and the 5.25-inch
              disk labeled Fonts.)

    *.C       (All files with the .C extension. This is optional. Copy
              these files only if you want the sample programs. These
              are on the 5.25-inch disk labeled Setup and the 3.5-inch
              disk labeled Setup/Learning the MS QC Environment.

    Now you must build the combined libraries that you want to use.
    QuickC Version 2.00 supports all memory models within the
    environment.

 8. Copy the following files to C:\QC2\LIB from the disk labeled
    Libraries (1, 2, 3):

    xLIBC.LIB           ("x" can be S, M, C, or L)
    xLIBFP.LIB          ("x" can be S, M, C, or L)
    EM.LIB
    LIBH.LIB
    GRAPHICS.LIB
    *.OBJ               (Any file with the .OBJ extension)

    Note: For example, if you were to build the Medium Library,
    MLIBCE.LIB, you would substitute xLIBC.LIB with MLIBC.LIB and
    xLIBFP.LIB with MLIBFP.LIB. If you wanted to build the Small
    Library, SLIBCE.LIB, you would substitute xLIBC.LIB with SLIBC.LIB
    and xLIBFP.LIB with SLIBFP.LIB. QuickC defaults to small-memory
    model, but supports Small, Medium, Compact, and Large if so
    specified. At least one library must be built.

    Assuming that you are building the Medium Library, MLIBCE.LIB, you
    would now combine these copied files using the Library Manager,
    LIB.EXE, as follows in the next step.

 9. Change the directory so that you are in C:\QC2\LIB. Type the
    following at the DOS prompt:

    LIB  MLIBCE.LIB  <press ENTER>
    [Operations]:  +MLIBC.LIB +MLIBFP.LIB +EM.LIB&  <press ENTER>
    [Operations]:  +LIBH.LIB +GRAPHICS.LIB +PGCHART.LIB <press ENTER>
    [List file]:   <press ENTER>

 Note: The "[Operations]:" and "[List file]:" are prompts from the
 Library Manager so they are not something you type in. The "&" is a
 continuation mark that can be used if your line grows too long.

 Including the Graphics Library, PGCHART.LIB and GRAPHICS.LIB
 in the combined library is optional. If you choose not to include
 these libraries here, you will need to create Program Lists when
 you are in the QuickC environment.

 If you run into any errors using LIB.EXE, make sure you are using the
 correct version. The version of the Library Manager that was shipped
 with QuickC Version 2.00 is Version 3.14.

 If you are having problems, try step 9 again with one change: instead
 of "LIB MLIBCE.LIB", type "C:\QC2\BIN\LIB MLIBCE.LIB" and then press
 ENTER.

 The Library Manager, LIB.EXE, now builds the Medium library,
 MLIBCE.LIB. You can delete MLIBC.LIB, MLIBFP.LIB, EM.LIB, and LIBH.LIB
 from C:\QC2\LIB because they are no longer necessary. Do NOT delete
 them from your distribution disks.

 You now are finished setting up QuickC Version 2.00 on your hard disk.
 If you would like to build other combined libraries in the future,
 then you can either use the SETUP.EXE program with the /L options

    setup /L

 or follow the recipe listed above for manually building them with
 the Library Manager.


 69. Error in "C For Yourself," Page 294

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890208-11455 docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41254

 In the manual "C for Yourself," provided with QuickC Version 2.00,
 there are two errors on Page 294.

 Both the example for the break statement, and the example for the
 continue statement contain the same error. In both examples, the
 following line is incorrect:

    while ( c != "Q" )

 The line should appear as follows:

    while ( c != 'Q' )


 70. QuickC 2.00 README.DOC: Installing on a Floppy-Disk System

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41366

 The following information is taken from the QuickC 2.00 README.DOC
 file, Part 1, "Notes on 'Up and Running.'" The following notes refer
 to Page 15 in "Up and Running": Installing on a Floppy-Disk System.

 Note: This information applies only to those using dual floppy
 systems.

 The description of the first screen says you are asked if you want to
 include PGCHART.LIB in the combined libraries. This is incorrect.
 There isn't enough room on the scratch disk for PGCHART.LIB and all of
 the other component libraries. If you want to use presentation
 graphics, you have two choices. You can link PGCHART.LIB separately,
 using the Make menu Edit Program List command, or you can use the LIB
 program to add PGCHART to the combined library after you finish
 installing QuickC.


 71. QuickC 2.00 README.DOC: Changing AUTOEXEC.BAT

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41367

 The following information is taken from the QuickC 2.00 README.DOC
 file, Part 1, "Notes on 'Up and Running.'" The following notes refer
 to Page 13 of "Up and Running": Changing AUTOEXEC.BAT.

 The headline "Changing NEW-VARS.BAT" should read "Changing
 AUTOEXEC.BAT," and the following paragraph should be added:

    If you want to use the 8087 math library instead of the emulator
    library, use the /FPi87 option when you compile from the command
    line (using QCL). If you compile and link from the QuickC
    environment, either add the line below to your AUTOEXEC.BAT file
    or type it at the command line:

    set cl=/FPi87


 72. QuickC 2.00 README.DOC: Using QC 2.00 With C 5.10

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41368

 The following information comes from the QuickC 2.00 README.DOC file,
 Part 1, "Notes on 'Up and Running,'" and refers to Page 12 in the
 file: Third Screen: The Directories (C 5.10 Compatibility).

 The following explanation applies only to those who want to use QuickC
 in conjunction with the Microsoft C Optimizing Compiler.

 QuickC complements and augments Versions 5.00 and 5.10 of the
 Microsoft C Optimizing Compiler. If you own one of these compilers,
 choose the directories where the Optimizing Compiler stores executable
 files, libraries, and header files: /BIN, /LIB, and /INCLUDE, for
 example, instead of /QC2/BIN, /QC2/LIB, and /QC2/INCLUDE. QuickC's
 programs, libraries, include files, and other files are the latest
 versions available. They are fully compatible with the Optimizing
 Compiler.

 To maintain compatibility between the two compilers, both QuickC and
 the Optimizing Compiler use the CL environment variable. If you
 include options that the Microsoft Optimizing Compiler recognizes but
 QuickC does not, QuickC issues an error message. You will have to edit
 the CL environment variable to eliminate this error.

 The CodeView debugger cannot handle files that have been incrementally
 compiled or incrementally linked. If you plan to examine QuickC
 programs with CodeView, be sure that these two options (incremental
 compile and incremental link) are turned off. From the command line,
 use QCL without the /Gi or /Li option. From the QuickC environment,
 use the Options menu Make command to turn off incremental compile and
 link and to turn on CodeView Info. This warning applies only to
 CodeView. QuickC's built-in debugger can handle incrementally compiled
 and linked programs.

 The -qc option allows you to run the QuickC compiler from the
 Microsoft Optimizing Compiler Version 5.00 or 5.10. If you own C 5.00
 or 5.10, and want to call QuickC Version 2.00, use this command line:

    cl -B1 qccom -qc

 In addition, if your hard disk already contains a version of LINK.EXE,
 you are asked if you want to delete the old linker. Answer yes. QuickC
 ships with Version 4.06 of LINK.EXE. It is fully compatible with
 Versions 5.00 and 5.10 of the Microsoft Optimizing Compiler.

 If you are writing Windows or OS/2 applications, you should use
 Version 5.02 of the Microsoft Segmented-Executable Linker.


 73. The Meaning of "ILINK:Fatal Error L1266: Invalid .EXE File"

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41370

 When the incremental linker option /Gi is used in compiling a file
 with the QCL command-line driver, the following message may appear
 after the program has been compiled:

    ILINK:fatal error L1266: invalid .EXE file
    ILINK: performing full link

 At this point, the incremental linker calls the QuickC 4.06 linker,
 and performs a full link.

 This behavior is to be expected whenever the incremental linker
 encounters a file that requires a full link -- typically, files for
 which there is no current .OBJ or .EXE file. There is nothing to be
 saved by performing an incremental link, so the incremental linker
 calls the 4.06 linker to do a full link.



 74. QuickC 2.00 README.DOC: Creating Your Own Key File

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41432

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" These notes
 refer to specific pages in "Up and Running."

 Page 31 Creating Your Own Key File

 If you customize the QuickC editor by creating a key file, you are not
 allowed to assign functions to CTRL+@ or CTRL+\.


 75. ESC Key Aborts Only the Compile Process in QC Environment

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41435

 The inside cover of the "Microsoft QuickC Up and Running" manual
 states that the ESC key stops the compiler and linker from continuing.
 This is only partially correct. The ESC key only aborts the compile
 stage of the QuickC compiler. During the link stage, the ESC key is
 ignored.

 Also pressing CTRL+BREAK aborts the compile process, but it will
 not abort link step as stated in the README.DOC. Pressing CTRL+BREAK
 during the linking process may hang your machine if you try executing
 your application program immediately after the linking is completed.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.


 76. QuickC 2.00 README.DOC: Command-Line Options

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41442

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 21  Command-Line Options

 Add the following note to the description of "QC /h":

 EGA cards can display 43 lines of text, VGA cards can display 50.
 You may use a Microsoft (or fully compatible) mouse with this option.
 If you encounter problems, please contact the manufacturer of the mouse.
 For example, early versions of the Logitech(TM) mouse driver do not
 support 43- or 50-line mode. Later versions support 43-line mode, but
 not 50.


 77. QuickC 2.00 README.DOC: Using the Mouse and the Keyboard

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41443

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" These notes
 refer to specific pages in "Up and Running."

 Page 21  Using the Mouse and the Keyboard

 Add the following note:

    If you own a COMPAQ(R) SLT/286 Laptop, run the MOUSE.COM program
    before running QuickC. This workaround corrects a problem in the
    COMPAQ BIOS.


 78. QuickC 2.00 README.DOC: Closing Windows

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41444

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 23 Closing Windows

 Closing a window with the close button does NOT clear its contents.
 For example, if you load a file into the Notepad window, close the
 window and then try to load the same file into the Source window,
 (either explicitly, or by pressing F2), QuickC will give you the
 error "File Already Loaded". To clear the contents of the Notepad
 window, you must choose the File menu New command while the Notepad
 window is active.


 79. QuickC 2.00 README.DOC: The DOS Shell Command

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41445

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 25 The DOS Shell Command

 The File menu DOS Shell command lets you exit to DOS. To return to the
 QuickC environment, type EXIT. Do NOT type "QC". If you type "QC" from
 the shell, you load a second copy of QuickC into memory. This might
 cause you to run out of memory when you try to compile a program. Even
 if you don't run out of memory, compiling will slow considerably as
 portions of QuickC are swapped in and out of memory.


 80. QuickC 2.00 Does Not Debug KBHIT() Correctly

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 31-OCT-1989    ArticleIdent: Q41469

 The following code shows an error in the Microsoft QuickC Version
 2.00's Run-Time function KBHIT(). The problem is that this function
 effectively ignores some keystrokes, yet these bypassed keystrokes are
 placed in your source file (if you are in the QC environment) or on
 the DOS command line (if you run the code from DOS).

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 The workaround is to define your own KBHIT() function and link it
 in as an .obj file.  This will override the KBHIT() routine in
 the library.  An example of this user define kbhit() routine
 follows the code example below which demonstrates the problem.

 MoreInfo:

 The following source code illustrates the problem:

 To duplicate the error in the QC environment, do the following:

 1. Turn debugging on.

 2. Compile and link the program.

 3. Set a breakpoint on the second printf statement and start the
    program.

 4. When you press a key you will notice that it take a few keystrokes
    before any action is taken by the program.

 When you return to the QC environment, the keystrokes that were not
 noticed by KBHIT() are now in your source file.

 The following is the sample program:

 #include <conio.h>
 #include <stdio.h>

 main()
 {
   printf("waiting\n");
   while ( !kbhit() );
   printf(" key struck was '%c'\n",getch() );
 }

 A workaround to this problem is to link in a KBHIT() routine
 as an .obj file.  The following is an example of such
 a routine:

 int kbhit(void) ;    /* prototype */

 int kbhit ()
 {
   int key ;

   _asm
    {
            mov  ah, 0Bh        ;setup for function 0Bh
            int  21h        ;call DOS interrupt
            and  ax, 0001h    ;Determine if Key was hit
            mov  key, ax        ;Initialize Key
                 ;0 = no key   1 = a key was hit
    }
   return (key) ;
 }

 You can either place this routine in one of your existing
 source modules, or in a separate module.



 81. QuickC 2.00 README.DOC: Error Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41470

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 52  Error Help

 Delete the paragraph that begins with "Move the the Errors window..."


 82. QuickC 2.00 README.DOC: Help On Help and TSRs

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41471

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 53  Help on Help and TSRs

 SHIFT+F1 is the shortcut key for Help on Help. If you have a
 terminate-and-stay resident (TSR) utility such as the Norton Guides
 installed, and you invoke that program with SHIFT+F1, then you can't
 use the SHIFT+F1 shortcut to QuickC's Help on Help. Choose Help on
 Help from the menus instead. Or change the key that triggers the TSR.


 83. QuickC 2.00 README.DOC: Using Another Editor

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41477

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The notes refer
 to specific pages in "Up and Running."

 Page 32  Using Another Editor

 The instructions for using another editor are not complete. You can
 add any other editor to the menu. To use "Brief(R)," "Epsilon(TM)," or
 the Microsoft "M" Editor, follow these steps:

 Open the Utility menu and choose Customize Menu. Highlight "Custom&
 Editor" and choose the <Edit> button. In the text box for Path Name,
 list the path and the name of the editor. For example, \BIN\B,
 extension. Next, follow the appropriate steps below:

 Brief

 1. Set the Arguments command line to:
     -m"editat $LINE $COL" $FILE

 2. Add the macro below to your Brief macro file:

      ; *** editat -- interface to QC Utility.Edit menu
      ; SYNOPSIS
      ; b -m"editat $LINE $COL" $FILE
      ; DESCRIPTION
      ; editat positions Brief at the specified line and column in the
      ; current file. It is invoked from the command line (i.e. -m )
      ; *
         (macro editat
          (
            (int line col)

            (get_parm 0 line)
            (get_parm 1 col)
            (move_abs line col)
          )
        )

 Epsilon

 Set the Arguments command line to:

      $FILE +$LINE

 M Editor

 Set the Arguments command line to:

    /e "Arg \"$LINE\" Mark" $FILE


 84. Library Sizes for QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | SLIBCE MLIBCE CLIBCE LLIBCE SLIBC7 MLIBC7 CLIBC7 LLIBC7
 Last Modified: 28-FEB-1989    ArticleIdent: Q41478

 The following are sizes for QuickC Version 2.00 libraries, as created
 by LIB.EXE 3.14:

                                           Standard
                                Standard   +Graphics
    Library        Standard    +Graphics    +Pgchart

    SLIBCE.LIB     206343       279679       331119
    MLIBCE.LIB     208391       282239       333679
    CLIBCE.LIB     216635       290483       341923
    LLIBCE.LIB     219195       293043       344483

    SLIBC7.LIB     193543       267391       318831
    MLIBC7.LIB     196103       269439       320879
    CLIBC7.LIB     204347       278195       329635
    LLIBC7.LIB     206907       280755       332195

 Standard libraries are combined component libraries, where "x" is any
 of the memory models S, M, C, or L, as follows:

    xLIBC.LIB + xLIBFP.LIB + [ EM.LIB | 87.LIB ] + LIBH.LIB



 85. QuickC 2.00 README.DOC: About Directories

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41479

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 37  About Directories

 When you're opening or saving a file, you can move to subdirectories
 by double-clicking (mouse) or pressing ENTER (keyboard) on the name
 of the directory in the Drives/Dirs list (see figure 3.4). To move
 to the parent directory, select the two periods ("..") at the top
 of the list.

 When you exit QuickC, you return to the directory where you started
 (the "default directory"), regardless of how many other directories
 you may have accessed.

 QuickC puts all .OBJ object files and .EXE executables in the default
 directory. For example, if you run QuickC from the /ZEBRA directory
 and open the file TAPIR.C from the /AARDVARK directory, the files
 TAPIR.OBJ and TAPIR.EXE are created in the ZEBRA (NOT the AARDVARK)
 directory when you compile the program because ZEBRA is the default
 directory. If you'd prefer to keep all related files in the same
 place, choose RUN DOS Command from the Utility menu and type CHDIR
 AARDVARK. The "change directory" command redirects the object and
 executable files to the other directory.


 86. QuickC 2.00 README.DOC: Error Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41480

 The following information is taken from the QuickC 2.00 Version
 README.DOC file, part 1, "Notes on 'Up and Running.'" The following
 notes refer to specific pages in "Up and Running."

 Page 51   Error Help

 Add this note to the section on Error Help:

 Note: You can ask for help on all error messages and dialog boxes
 except this one:

                   Warning!
            Too many open help files
 Backtrace list and bookmarks will be invalidated
 ------------------------------------------------

 Choosing <OK> lets you access the new help files, invalidating the
 backtrace list and bookmarks. Choosing <Cancel> aborts the request
 for Error Help, leaving the backtrace commands and bookmarks intact.

 This warning appears only when you have 20 files open at the same time,
 which is unlikely to occur. You can't ask for help about the message
 because the help system is unable to open any help files.


 87. QuickC 2.00 README.DOC: The LEARN.COM Program

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41550

 The following information is taken from the QuickC Version 2.00
 README.DOC file, Part 1, "Notes on "Up and Running." " The following
 notes refer to specific pages in "Up and Running."

 55  The LEARN.COM Program

 The \QC2\TUTORIAL directory holds the LEARN.COM program. You can run
 it from the command line or choose the "Learn QuickC" command from
 QuickC's Utility menu. QuickC searches the current path and runs the
 first LEARN.COM program that it finds, which means that users of
 Microsoft Word may see the MS-Word tutorial instead of the QuickC
 tutorial if the Word directory is first in the path. If this happens
 to you, either switch to \QC2\TUTORIAL directory and type LEARN, or
 run the NEW-VARS.BAT batch file.


 88. QuickC 2.00 README.DOC: Passing By Value

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41551

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on "C for Yourself." " The following
 notes refer to specific pages in "C for Yourself."

 Page 19  Passing By Value

 In the third paragraph on Page 19, the following phrase is incorrect:

    Since the variables in the factor function are local

 The phrase should read as follows:

    Since the variables in the showme function are local


 89. scanf, sscanf, fscanf Fail on the Regular Expression

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 28-FEB-1989    ArticleIdent: Q41553

 The scanf() function fails when the left bracket ([) and caret (^) are
 immediately followed by a right bracket (]) in a regular expression.
 This problem also occurs in the scanf and fscanf functions.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 Consider the following program:

    #include <stdio.h>

    void main (void)
     { char string[20];

       sscanf ("Blibbet Fever!", "%9[^]", string); /* Does not Work */

       printf ("string=%s\n", string);
     }

 The sscanf function fails to parse the buffer correctly and so the
 output of this program is unpredictable. The output should be as
 follows:

    string=Blibbet F

 The workaround to this problem is to follow the caret with a character
 you know will not be in the string you are scanning. A working version
 of the above program follows:

    #include <stdio.h>

    void main (void)
     { char string[20];

       sscanf ("Blibbet Fever!", "%9[^\xff]", string); /* Does work */

       printf ("string=%s\n", string);
     }

 Note: The format string "%9s" is not adequate because it stops
 scanning when white space is encountered.



 90. QuickC 2.00 README.DOC: Example Program PARRAY.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41569

 The information below is taken from the QuickC Version 2.00 README.DOC
 file, Part 2, "Notes on 'C for Yourself.'" The following notes refer
 to specific pages in "C for Yourself":

 Page 105  Example Program PARRAY.C

 Change the line

     printf("array[%d] = %d", count, *ptr);

 to

     printf("i_array[%d] = %d\n", count, *ptr);

 The PARRAY.C program in on-line help already contains the correction,
 but you may want to correct the printed listing, also.


 91. QuickC 2.00 README.DOC: Pragmas

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41570

 The information below is taken from the QuickC Version 2.00 README.DOC
 file, Part 2, "Notes on 'C for Yourself.'" The following notes refer
 to specific pages in "C for Yourself":

 Page 96   Pragmas

 QuickC supports 4 (not 15) pragma directives. The two examples listed
 -- "#pragma skip" and "#pragma title" -- are not supported. The QuickC
 pragmas (message, pack, check_stack, and check_pointer) are documented
 in on-line help.


 92. QuickC 2.00 README.DOC: The "defined" Operator

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41571

 The information below is taken from the QuickC 2.00 README.DOC file,
 Part 2, "Notes on 'C for Yourself.'" The following notes refer to
 specific pages in "C for Yourself":

 Page 95  The "defined" Operator

 The last sentence should read:

    In this example the conditional block executes if DEBUG is not
    currently defined.


 93. QuickC 2.00 README.DOC: Floating-Point Values

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41573

 The information below is taken from the QuickC Version 2.00 README.DOC
 file, Part 2, "Notes on 'C for Yourself.'" The following notes refer
 to specific pages in "C for Yourself":

 Page 72  Floating Point Values

 The float data type contains four bytes, not six.


 94. QuickC 2.00 README.DOC: Declaring and Initializing Arrays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41577

 The information below is taken from the QuickC Version 2.00 README.DOC
 file, Part 2, "Notes on 'C for Yourself.'" The following notes refer
 to specific pages in "C for Yourself."

 Page 54  Declaring and Initializing Arrays

 You can always initialize an array with constants. If you initialize
 an automatic (local) array with variables or addresses that are
 unknown to the compiler at compile time, you must include the size of
 the array. For example:

 #define FIVE 5
 main()
 {
   int i = 5;
   int abc[] = { 5, FIVE};  /* constants always work */
   int def[] = { i, i }     /* ERROR: variables in unsized array */
   int ghi[2] = {i, i }     /* sized array works */

 Warning: The first edition of "The C Programming Language" by
 Kernighan and Richie did NOT allow you to initialize automatic arrays.
 The ANSI standard and the second edition of K&R make provision for
 initialization by constants. Initializing an automatic array with
 variables is a Microsoft extension to ANSI. If you plan to port your
 program to another computer or operating system, these constructs may
 not be portable. QuickC will issue a warning about initializing
 automatic arrays at warning level three. The requirement for sized
 arrays is unique to QuickC -- unsized arrays are accepted by the
 Microsoft C Optimizing Compiler.


 95. "st" Is the Floating Point Stack Register in In-Line Assembly

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41578

 Question:

 Why can't I use the variable "st" in a block of in-line assembly code?

 Response:

 The "st" variable is the floating point stack register and as such is
 a reserved name. If you attempt to use this name in an LES or LDS
 instruction, you will receive the following error:

    error C2415 : improper operand type

 You should not use "st" as a variable name. Choose another name
 instead.

 The following code generates error C2415 when compiled under any
 memory model, at any warning level, and with MS EXTENSIONS enabled:

 char * st;           /* st is the floating point stack register */
 main() {
   _asm  {
       les  di, st    /* generates the error */
       lds  si, st    /* generates the error */
   }
 }

 Changing "st" to any other nonreserved name will resolve this
 situation.


 96. C2073 When Porting Code from QuickC 2.00 to C 5.10

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 28-FEB-1989    ArticleIdent: Q41579

 QuickC Version 2.00 allows arrays to be initialized within functions.
 This procedure is not supported in C Version 5.10. Therefore, code
 that utilizes this added facility of QuickC Version 2.00 will not port
 directly to C Version 5.10.

 An attempt to compile the code that initializes arrays declared within
 functions under Version 5.10 of the C optimizing compiler will result
 in the following error message, even though the code compiles with no
 errors and no warnings under Version 2.00 of QuickC:

    C2073: "Cannot Initialize Array In Function"

 The following code will compile without error and execute as expected
 when compiled under QuickC Version 2.00, but will fail with the
 compile time error C2073 when compiled under C Version 5.10:

 #include <stdio.h>
 void main(void)
  {
    char s[10] = "Hello";
  }

 To work around this problem, initialize the array outside of any
 function, as in the following modification of the above example:

 #include <stdio.h>
 char s[10] = "Hello";

 void main (void)
    {
    {


 97. Graphics Lib. Ref. Incorrectly References Optimizing Compiler

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41580

 Page 3, "PART 1 Overview," of the Microsoft QuickC 2.00 "Graphics
 Library Reference" incorrectly states the following:

    The first part of this manual provides an overview of the graphics
    functions provided with the Microsoft C 5.2 Optimizing Compiler.

 It should read as follows:

    The first part of this manual provides an overview of the graphics
    functions provided with the Microsoft QuickC 2.0 Optimizing
    Compiler.


 98. QuickC 2.00 README.DOC: Example Program GRAPHIC.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41590

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2 "Notes on "'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 209   Example Program GRAPHIC.C

 The declaration at the beginning of GRAPHIC.C should be

    struct videoconfig screen;

 Also, change the seventh constant in the array 'modes' to _ERESNOCOLOR
 and remove the semicolon at the end of line that begins the "while"
 loop.

 The GRAPHIC.C program in on-line help already contains these
 corrections, but you may want to correct the printed listing, too.


 99. QuickC 2.00 README.DOC: Vector-Mapped Fonts

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41597

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2 "Notes on "'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 264   Vector-Mapped Fonts

 Add this note to the description of vector mapping:

 If a vector-mapped font is selected in graphics mode, any function
 affecting "_moveto" or "_lineto" will also affect the font
 ("_setlinestyle" and so on) when "_outgtext" is called.


 100. QuickC 2.00 README.DOC: Example Program GRAPHIC.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41598

  Summary:

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2 "Notes on "C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 209   Example Program GRAPHIC.C

 The declaration at the beginning of GRAPHIC.C should be

    struct videoconfig screen;

 Also, change the seventh constant in the array 'modes' to _ERESNOCOLOR
 and remove the semicolon at the end of line that begins the "while"
 loop.

 The GRAPHIC.C program in on-line help already contains these
 corrections, but you may want to correct the printed listing, too.


 101. Error L2003 When Linking with Wrong Libraries

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41613

 When compiling and linking inside of the QuickC Version 2.00
 integrated environment, the following error can occur if the memory
 model is set to "Large" (under "Options"-->"Make"-->"Compiler Flags"),
 and the make file links in "SLIBCE.LIB" or "MLIBCE.LIB". The error
 message is as follows:

    LIB\SLIBCE.LIB(dos\crt0.asm) : error L2003: intersegment
    self-relative fixup at pos: 3D6 Record type: 9C.
    target external '_main'

 To correct this behavior, do the following:

 1. Change either the make file or the memory-model choice so they are
    consistent.

 2. Recompile the program.


 102. QuickC 2.00 README.DOC: Example Program FOR.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41616

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 33 Example Program FOR.C

 If you compile the program FOR.C and run it from the DOS command line,
 it conflicts with the DOS FOR command. To eliminate the conflict,
 rename the file FOR.EXE AS QCFOR.EXE.


 103. QuickC Err Msg C2086: Redefinition Caused by Forward Reference

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42110

 The program below will produce (at warning level 0) the following
 fatal error in QuickC Version 1.0x if language extensions are
 disabled, and in QuickC Version 2.00 whether extensions are enabled or
 not:

     C2086:
     'foo' : redefinition

 The warning message will be generated in QuickC Version 1.0x if
 language extensions are enabled:

     C4074:
     non standard extension used - 'redefined extern to static'

 The program is as follows:

     main()
         {
         int i;
         i = foo();
         }

     static int foo()
         {
         return(1);
         }

 This error will occur if foo() is typed as being of any class other
 than int, the default return type. This is expected behavior.

 Microsoft has implemented ANSI compatibility as well as a number of
 extensions to the C Language. The extensions allow for more flexible
 compilation. The following is included in the ANSI draft standard (13
 May 1988):

 I.

 If the declaration of an identifier for an object or a function
 contains the storage class specifier 'extern', the identifier has the
 same linkage as any _visible_ declaration of the identifier with file
 scope.

 II.

 If the declaration of an identifier for a function has no storage
 class specifier [as is the case with implicit (first use) function
 uses], its linkage is determined exactly as if it were declared with
 the storage class specifier 'extern'.

 III.

 If the declaration of an identifier for an object or a function has
 file scope and contains the storage class specifier 'static', the
 identifier has internal linkage.

 IV.

 If, within a translation unit, the same identifier appears with both
 internal and external linkage, the behavior is undefined.

 This explanation means that a forward reference to a function not yet
 visible to the compiler will be treated as of type EXTERN because the
 compiler is unaware of its storage class. Because it is of type EXTERN
 it has external linkage, meaning that it is an identifier associated
 with a function defined outside the current module. When the compiler
 then encounters the definition of this function with the STATIC
 storage class it interprets it as a redefinition of that function --
 code has already been generated treating it as EXTERN; now it has been
 declared as STATIC. Being STATIC it then has internal linkage. At this
 point, the identifier has both internal and external linkage and
 behavior is, according to the draft standard, undefined.

 The following information also is from the draft standard:

 Undefined behavior: Behavior, upon use of a nonportable or erroneous
 construct of erroneous data, or of indeterminately-valued objects for
 which the standard imposes no requirements. Permissible undefined
 behavior ranges from ignoring the situation completely with
 unpredictable results, to behaving during translation or program
 execution in a documented manner characteristic of the environment
 (with or without the issuance of a diagnostic message), to terminating
 a translation or execution (with the issuance of a diagnostic
 message).

 QuickC's behavior conforms perfectly to this guideline. Page 172 of
 the "Microsoft C Language Reference Guide" states clearly that a
 function definition without a storage class specifier defaults to
 EXTERN. QuickC issues a diagnostic message and either terminates
 translation with a fatal compiler error if language extensions are
 disabled, or produces a warning message in QuickC Version 1.0x if
 language extensions are enabled.

 Being a one-pass compiler, QuickC has no way of determining the
 storage class of a forwardly referenced function, unlike C 5.xx, and
 thus deals with it in the manner described.

 The language-extensions switch makes a difference because of the
 extension that allows for benign type redefinitions within the same
 scope. While the QuickC Compiler programmer's guide (page 171) only
 mentions that benign TYPEDEF redefinitions will be allowed, this
 behavior also applies to benign function type redefinitions in QuickC
 Version 1.0x. QuickC Version 2.00 does not allow this type of
 redefinition.


 104. On New Build with No Changes, QC Environment Changes Size

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified: 17-JUL-1990    ArticleIdent: Q60607

 The QuickC Version 2.00 environment may sporadically change its size
 in memory if you make no changes to your source code and recompile or
 rebuild the program.

 If you choose the DOS Shell command from the File menu and then run
 CHKDSK, the last line of information returned tells you the amount of
 free memory available to DOS on your system. If you check this amount,
 exit back into QuickC, select Rebuild All from the Make menu, and
 repeat the memory check, you may find that your free memory size has
 changed.

 This problem seems to appear sporadically and without a pattern. The
 memory in use may shrink to a very small amount, or it may return to
 the original value. It never seems to grow past the original amount.
 Microsoft is researching this problem and will post new information
 here as it becomes available.


 105. QuickC 2.00 README.DOC: Example Program INPUT.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41620

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 176  Example Program INPUT.C

 The "do" loop at the end of the INPUT.C program should read:

    do
    {
     c = getch();
     c = tolower( c );
    } while ( c != 'y' && c != 'n');

 The INPUT.C program in on-line help already contains this correction,
 but you may want to correct the printed documentation, too.


 106. The Amount of Memory That Is Required for Registered Fonts

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | graphics
 Last Modified:  7-MAR-1990    ArticleIdent: Q58246

 The _registerfonts() function requires a block of 516 bytes of memory
 for font header information.

 The "Microsoft QuickC Graphics Library Reference" states on Page 170
 that the header information for each font is approximately 140 bytes.
 This is true; however, the _registerfonts() function will pre-allocate
 516 bytes and then use the allocated space to store information for
 each font header. This technique of memory management is similar to
 the way malloc allocates memory using the _amblksiz global variable.


 107. QuickC 2.00 README.DOC: The _fontinfo Structure

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41647

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page  267  The _fontinfo Structure

 Change "filename[66]" to "filename[81]".


 108. QuickC 2.00 README.DOC: Using Braces in _asm Blocks

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41648

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page  273  Using Braces in _asm Blocks

 Disregard the part that explains how to use a backslash to continue a
 line. The opening brace may appear on the same line or on the
 following line. The backslash is never needed.


 109. QuickC 2.00 README.DOC: Limits on _asm Identifiers

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41649

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page  273  Limits on _asm Identifiers

 Never use reserved assembly words as labels, variable names, or other
 identifiers within an _asm block. This includes words in the following
 categories:

    ASM Opcodes such as CMP or MOV
    Opcodes new to the 80186, 80286, and 80386 such as ARPLS or CLTS
    Reserved operand words such as WORD or PARA
    C library functions such as "exit" or "time".

 For example, the following code is not permitted:

    main()
    {
      int word;
      _asm{mov WORD PTR [word], ax }
    }

 The variable "word" can be used in the C part of the program, but not
 within the assembly block.


 110. QuickC 2.00 README.DOC: /F (Set Stack Size)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41650

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 75  /F (Set Stack Size)

 The number following /F must be hexadecimal; decimal and octal are not
 allowed.


 111. QuickC 2.00 README.DOC: /Gi (Use Incremental Compilation)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41651

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 87  /Gi (Use Incremental Compilation)

 Note: This information applies only to the Microsoft C Optimizing
 Compiler versions 5.1 and earlier.

 If you use QuickC's /Gi or /Li options to compile incrementally or
 link incrementally, you may debug the files with QuickC's integrated
 debugger.

 If you own Microsoft C version 5.1 or earlier and want to use the
 CodeView debugger, do NOT use the /Gi or /Li options.


 112. QuickC 2.00 README.DOC: /Li (Link Incrementally)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41652

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 94  /Li (Link Incrementally)

 This section should say that if you change the command line options
 that relate to linking, you must delete the .EXE file. For example, if
 you try this:

    QCL /Gi TEST.C /link SLIBCE.LIB

 you must delete TEXT.EXE before you link with the large library:

    QCL /Gi TEST.C /link LLIBCE.LIB

 The incremental linker would look at the time and date stamp of
 TEST.EXE and do nothing (because the file would be up to date).
 Whenever you change linker options, delete the .EXE file or use
 LINK.EXE instead of ILINK.EXE.

 This condition does not apply if you compile ("build") within the
 QuickC environment. It affects only the QCL program that you run from
 the DOS prompt and only when you change a linker-related option.


 113. QuickC 2.00 README.DOC: /Li Option and Expanded Memory

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41653

 The following information is taken from the QuickC version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'". The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 94  /Li Option and Expanded Memory

 Note: Incremental linking uses expanded memory (as defined by the LIM
 specifications, versions 3.2 and higher) if it is available.

 WARNING: If you have installed additional memory on an 80286 or 80386
 system, you may encounter problems when linking incrementally,
 especially if you have configured the board to use both expanded AND
 extended memory. In particular, your computer may lock up if you use
 incremental link in conjunction with a Talltrees AT3 expanded memory
 board. (Other boards may or may not be subject to this problem.) If
 this happens, you have five choices:

 1. Contact the manufacturer of the memory board for information on
    solving this problem.

 2. Remove the Expanded Memory Manager (EMM) device driver and continue
    to link incrementally.

 3. Disable extended memory (used by VDISK) and continue to link
    incrementally.

 4. Leave the memory and device driver in place, but turn off
    incremental linking. From the QuickC environment, choose the
    Options menu Make command and then choose the Linker Flags button.
    From the command line, avoid the /Zi option.

 5. Contact Microsoft Product Support for additional information on
    ways to work around the problem.


 114. QuickC 2.00 README.DOC: /Ze, /Za (Enable/Disable Extensions)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41654

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 101  /Ze, /Za (Enable or Disable Language Extensions)

 Add the following notes to the explanation of /Ze and /Za:

 In extremely rare cases, you may want to cast a function pointer to a
 data pointer. QuickC uses the code segment (cs:), while Microsoft C
 5.1 uses the data segment (ds:). The program below attempts to cast a
 function pointer (pfunc) to a pointer to an int (pdata):

     main()
     {
       int (*pfunc)();
       int *pdata;

       pdata = (int *) pfunc;
      }

 The ANSI standard does not permit such casts. When you use /Za to
 enforce ANSI compatibility, this program triggers error C2068. When
 you use /Ze and /W3, this program generates a warning C4074.

 To maintain ANSI and C 5.1 portability, cast the function pointer to
 an int before casting it to a data pointer. The following line is
 perfectly acceptable. It generates to errors or warnings.

    pdata = (int *) (int) pfunc;

 A second method is to declare pfunc as a union that can act as a
 function pointer or a data pointer.


 115. QuickC 2.00 README.DOC: Creating a .COM File (/BI)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41655

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  122  Creating a .COM File (/BI)

 Delete this section (5.4.2). The linkers that shipped with QuickC 2.00
 do not support the /BI option.


 116. QuickC 2.00 README.DOC: The $(MAKEFLAGS) Macro

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41656

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  165  The $(MAKEFLAGS) Macro

 If you call NMAKE recursively with "$(MAKE) $(MAKEFLAGS)", the
 following flags are NOT preserved: A, C, D, F, P, R, S, X.


 117. QuickC 2.00 README.DOC: /Gi (Use Incremental Compilation)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41657

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 87  /Gi (Use Incremental Compilation)

 Note: This information applies only to the Microsoft C Optimizing
 Compiler versions 5.1 and earlier.

 If you use QuickC's /Gi or /Li options to compile incrementally or
 link incrementally, you may debug the files with QuickC's integrated
 debugger.

 If you own Microsoft C version 5.1 or earlier and want to use the
 CodeView debugger, do NOT use the /Gi or /Li options.


 118. QuickC 2.00 README.DOC: /Li (Link Incrementally)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41658

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 94  /Li (Link Incrementally)

 This section should say that if you change the command line options
 that relate to linking, you must delete the .EXE file. For example, if
 you try this:

    QCL /Gi TEST.C /link SLIBCE.LIB

 you must delete TEXT.EXE before you link with the large library:

    QCL /Gi TEST.C /link LLIBCE.LIB

 The incremental linker would look at the time and date stamp of
 TEST.EXE and do nothing (because the file would be up to date).
 Whenever you change linker options, delete the .EXE file or use
 LINK.EXE instead of ILINK.EXE.

 This condition does not apply if you compile ("build") within the
 QuickC environment. It affects only the QCL program that you run from
 the DOS prompt and only when you change a linker-related option.


 119. QuickC 2.00 README.DOC: Differences Between NMAKE and MAKE

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41659

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 174   Differences between NMAKE and MAKE

 Note: If you don't own QuickC Version 1, skip this section.

 Section 7.5 explains how to convert DOS MAKE files for use with NMAKE.
 Section 7.6 explains how to interchange QuickC 2.0 Program Lists (.MAK
 files) with NMAKE description files. The discussion below covers
 conversion of QuickC Version 1 program lists to NMAKE files.

 It's fastest and easiest to delete the old .MAK files and create new
 ones from within QuickC. However, if you wish to alter a Version 1
 program list by hand, follow these instructions:

 Converting to NMAKE Format

 To use QuickC 1.00 and 1.01 program lists (.MAK files) with the
 stand-alone NMAKE utility, follow these steps:

 1. Make a backup copy of the .MAK file.

 2. Delete or comment out (precede with a #) the first two lines of
    the .MAK file. These lines define inference rules.

 3. Add the following as the first target in the file:

       all : target.exe

 (Replace "target.exe" with the name of the final target in the file.)
 Spell the target name with lowercase characters only.

 4. Change the initial capital letter of the final target in the file
    to a lowercase letter.

 Converting to 2.0 Format

 If you want to use the resulting file within the QuickC 2.0
 environment, you must also follow these steps:

 1. Run QuickC.

 2. Choose Set Program List from the Make menu. Specify the .MAK file
    you just edited as the program list file.

 3. Choose Edit Program List from the Make menu and immediately choose
    <Save List>.


 120. QuickC 2.00 README.DOC: Help File Formats

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41660

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  179  Help File Formats

 In the section on QuickHelp, add this sentence:

 Note: The QuickHelp format supported by QuickC is a subset of the
 format supported by the OS/2 QuickHelp utility. QuickC does not
 support the complete set of OS/2 QuickHelp dot commands.


 121. QuickC 2.00 README.DOC: /K

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_helpmake
 Last Modified: 24-JAN-1991    ArticleIdent: Q41661

 The following information is taken from the QuickC version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 182   /K[filename]

 Add this description to the table:

 Optimizes .HLP file sizes. The /K option specifies a file that
 defines keyword separator characters. These characters separate words
 in the file before HELPMAKE compresses it.

 The file used to create QC.HLP is listed below. (The first space is
 a blank character and it indicates that a space separates words.)

   "&'()*+,.-/:=?@[\]^_`{|}~\177

 The other characters specify other separators. The angle brackets and
 pound sign are excluded, which gives a slightly better compression of
 phrases such as "#include <stdio.h>".

 Without the /K option, HELPMAKE sees these tokens to compress:

         #
         include
         <
         stdio
         .
          h
          >

 With the /K option, HELPMAKE sees the following tokens to compress:

         #include
         <stdio
         .
          h>

 Repeated over the entire QC.HLP file, the small savings add up.


 122. QuickC 2.00 README.DOC: Creating a Help Database

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41662

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  185  Creating a Help Database

 Add these paragraphs to step 4 at the top of the page:

 If you would prefer not to append the new file to QC.HLP, you may set
 the environment variable HELPFILES to equal the help files you've
 created. For example, to force on-line help to search HANSEL.HLP and
 GRETEL.HLP (in addition to the standard help files), enter this
 command line or add it to your AUTOEXEC.BAT.

    SET HELPFILES=HANSEL.HLP;GRETEL.HLP

 QuickC's on-line help system can search up to 10 files. This includes
 the four standard help files (QC.HLP, OCENV.HLP, ERROR.HLP and
 GRAPHICS.HLP) and up to six user-defined files.


 123. QuickC 2.00 README.DOC: Page 190 Example

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41663

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 190 Example

 Delete the characters "@EX =" from the example.


 124. QuickC 2.00 README.DOC: Appendix D, Error-Message Reference

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41664

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 225   Appendix D, Error-Message Reference

 Appendix D lists the following errors that the compiler never
 generates:

    page 229     C1026
    page 229     C1027
    page 233     C2002
    page 234     C2011
    page 240     C2083
    page 244     C2135
    page 252     C2428
    page 253     C4001
    page 255     C4025
    page 257     C4052

 In addition, some error numbers have changed.  The on-line help
 descriptions are correct, but Appendix D is incorrect.  Insert the
 following notes:

    page 228     C1011    See C1065.
    page 232     C1064    See C1067.
    page 235     C2027    See C2088.
    page 237     C2041    See C2020.
    page 249     C2201    See C2073.
    page 249     C2202    See C2183.
    page 249     C2203    See C2184.
    page 249     C2204    See C2186.

 C5.1 users may notice slight changes to these error messages: C2035,
 C2077, C2095, C2133, C2174, C2182


 125. QuickC 2.00 README.DOC: Error Message C1025

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41665

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 229  Error Message C1025

 The error message below is new and should be added to Page 229:

    C1025   compiler terminated by user

    The compiler was stopped by the user.


 126. QuickC 2.00 README.DOC: Error Message C2176

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41666

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  248  Error Message C2176

 The message and explanation for error C2176 should read:

    C2176  static huge data not supported

    You cannot declare data items with the huge attribute in the QuickC
    environment. Declare a huge pointer to the data item instead.


 127. QuickC 2.00 README.DOC: Error Message C2177

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41667

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 248   Error Message C2177

 Add the following note to error C2177:

 This error may occur when you attempt to assign to an unsigned long
 integer a decimal constant in the range +2147483647 to +4294967295.

 For example, the following line generates an error:

    unsigned long debt = 3000000000;

 but either of these lines works:

    unsigned long debt = 2000000000 + 1000000000;
    unsigned long debt = 0xB2D05E00;


 128. QuickC 2.00 README.DOC: Error Message C2418

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41668

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  252  Error Message C2418

 The following error message is new and should be added to Page 252:

   C2418  'identifier': not in a register

   This error occurs when an in-line assembler instruction
   references a variable with register storage class that has not
   actually been allocated in a register. To correct this, remove the
   register keyword from the variable definition and make sure that
   this instruction is legal with a memory operand.

 For Example:

   main()
   {
    register long regvar1;   /* _asm references are illegal */
    register int regvar2;
    register int regvar3;
    register int regvar4;

    _asm
    {
     les regvar2, regvar1;    /* error */
     mov regvar2, regvar4;    /* error */
    }
   }


 129. QuickC 2.00 README.DOC: Error Message C2429

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41669

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page 252  Error Message C2429

 The following error message is new and should be added to Page 252:

 C2429  <label> : illegal far label reference

 This error effects only people using in-line assembler. It is illegal
 to do a far call or a far jump to a label. It should never be
 necessary to do this, since labels have function scope and a function
 cannot be larger than a segment.


 130. QuickC 2.00 README.DOC: Warning Message C4118

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q41670

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  298  Warning Message C4118

 The QuickC preprocessor accepts but ignores the following pragmas:

    #pragma comment (compiler)
    #pragma comment (lib)
    #pragma comment (exestr)
    #pragma comment (user)

 Using these pragmas results in warning message C4118, but only at
 warning level 3. In all other cases, C4118 is a level-1 warning.


 131. QuickC 2.00 README.DOC: Warning Message C4407

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41671

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  264  Warning Message C4407

 Warning C4407 (operand size conflict) has been changed from level 1 to
 level 2.


 132. QuickC 2.00 README.DOC: Error Message U1051

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41672

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 3, "Notes on 'QuickC Tool Kit.'" The following
 notes refer to specific pages in "QuickC Tool Kit."

 Page  308  Error Message U1051

 The word "[targets]" should be on the same line as the rest of the
 message.


 133. QuickC 2.00 README.DOC: Linking QC 2.00 Programs for Windows

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER| |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41673

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 4, "Notes For Windows and OS/2 Programmers."

 The following is for Windows Programmers:

 1. Special Instructions for Linking

    If you own the Windows Software Development Kit (SDK) and want to
    use QuickC 2.00 to write Windows programs, you cannot use either
    the standard QuickC linker or the SDK linker. Instead, replace the
    QuickC linker LINK.EXE (version 4.06, which is installed by the
    SETUP program), with the 120K LINK.EXE file (version 5.02 of the
    Microsoft Segmented-Executable Linker for MS-DOS, Windows, and
    OS/2). You can find it on the distribution disk labeled "Learning
    the Microsoft QuickC Environment". This linker works with QuickC,
    C 5.10, and the Software Development Kit. It replaces all earlier
    versions of the linker.

 2. Linker Warning Message L4042

    L4024  name : multiple definitions for export name

    This warning occurs if you declare a name exported in both the
    .DEF file and with the _export keyword in a .C file. It can be
    safely ignored. You can eliminate it by removing one or the other
    of the export declarations for the name.


 134. QuickC 2.00 README.DOC: QCL Command-Line Options for OS/2

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41674

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 4, "Notes for Windows and OS/2 Programmers."

 Page    1   QCL Command Options

 QCL supports several command options for compatibility with OS/2.
 These options may not work correctly if you have not installed OS/2
 or the Microsoft C Optimizing Compiler, Version 5.1 or later:

 The /Fb Option

 If you have installed the C Optimizing Compiler, you can use the /Fb
 option to create bound applications. See Section 4.3.8 of the
 "Microsoft QuickC Tool Kit" or your Microsoft C Optimizing Compiler
 documentation for details.

 If the Optimizing C Compiler is not installed, using /Fb causes QCL
 to prompt you to insert BIND.EXE into drive A. BIND.EXE is not
 shipped with QuickC.

 The /Lp Option

 The /Lp option links programs for OS/2 protected mode. If you have
 installed the C Optimizing Compiler, you can use /Lp to create
 protected mode applications. See Section 4.3.21 of the "Microsoft
 QuickC Tool Kit" or your Microsoft C Optimizing Compiler
 documentation for details. Note that you should not use the standard
 QuickC linker. Instead, use the alternate Windows-compatible linker
 mentioned at the beginning of Part 4 of README.DOC or use the linker
 from the Optimizing Compiler.

 If you do not have the C Optimizing Compiler, QCL accepts the /Lp
 option without error. At link time, however, QCL fails because it
 cannot find the OS/2 protected mode library.

 The /Zr Option

 If you own the Microsoft C Optimizing Compiler, Version 5.1, and
 you're writing OS/2 Protected Mode applications, do not use the
 QuickC /Zr option.


 135. QuickC 2.00 README.DOC: Searching for OS/2 Include Files

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41675

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 4, "Notes for Windows and OS/2 Programmers."

 Searching for Include Files

 The following command line is valid even if you do not have the OS/2
 software, as described previously:

    QCL /Lp /c myfile.c

 If myfile.c includes an OS/2 include file, however, QCL returns the
 following error:

    C1068  Cannot open file 'name.h'

 where 'name.h' is the name of the OS/2 include file.


 136. QuickC 2.00 README.DOC: Linker Warning L4024

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41676

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 4, "Notes for Windows and OS/2 Programmers."

 Linker Warning L4024

 L4024 name : multiple definitions for export name

 This warning occurs if you declare a name exported both in the .DEF
 file and with the _export keyword in a .C file. It can be safely
 ignored. You can eliminate it be removing one or the other of the
 export declarations for the name.


 137. QuickC 2.00 README.DOC: Spurious Error: __aDBused...

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-FEB-1989    ArticleIdent: Q41677

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 4, "Notes for Windows and OS/2 Programmers."

 Spurious Error: __aDBused Referenced But Not Defined

 To eliminate this error, link with the DBUSED.OBJ file. Or use the LIB
 utility to add DBUSED.OBJ to your combined libraries.


 138. Filenames Starting with "-" Cause ILINK Errors

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q41699

 Building programs under QuickC Version 2.00 can result in errors when
 filenames begin with the dash character "-".  These same programs
 compile under Version 1.0x and under Version 2.00 when incremental
 link is turned off.

 This behavior is caused by ILINK interpreting the dash of the
 filename as the beginning of a switch argument. A filename with a dash
 in the middle of it avoids the problem because ILINK interprets the
 entire filename as a single argument.


 139. #define Source-Code Line Error in Manual

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 28-FEB-1989    ArticleIdent: Q41702

 The following documentation error occurs on Page 173 of the "Microsoft
 QuickC 2.00 Graphics Library Reference" manual. The source-code line
 reads as follows:

    #define RGB(r,g,b) (((long) ((b) < 8 | (g)) < 8) | (r))

 The line should read as follows:

    #define RGB(r,g,b) (((long) ((b) << 8 | (g)) << 8) | (r))

 The bit-shift operator should replace the logical less than
 sign.


 140. QuickC 2.00, Watch Statement on Implicit Length Arrays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 28-FEB-1989    ArticleIdent: Q41704

 When the array is initialized and declared in C at the same time, the
 length does not need to be specified as the compiler counts the
 elements in the array and allocates enough memory to store the array.

 The following is an example of an array with implicit length:

    int x[] = {1,2,3,4,5};

 The compiler would allocate the space for a five-integer array. When
 the length of an array is stated implicitly, the QuickC Version 2.00
 debugger is not able to set a watch-value debug statement on the array
 correctly. A watch value debug statement on "x" would result in the
 following

    x  { },

 not the following, as expected:

    x {1,2,3,4,5}

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 To work around this problem, state the length explicitly in the array
 declaration.

 The following is an example:

    int y[5] ={1,2,3,4,5};

 A watch value debug statement on "y" would now result in the
 following, as expected:

    y {1,2,3,4,5}



 141. Watching a Character Array in QuickC Version 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  6-JUN-1989    ArticleIdent: Q41713

 The program below declares six different character type variables.
 Watching each variable in QuickC Version 2.00 as a string might not
 have the desired effect.

 Watching any of the three arrays with explicit sizes displays all
 eight elements as an array of characters, as follows:

    array1 : { 'A', 'r', 'r', 'a', 'y', '1', '\0', '\0' }

 Watching either of the two arrays with implicit sizes reveals a
 problem with QuickC Version 2.00: nothing is displayed between the
 curly braces. The following is an example:

    array4 : {  }

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 Watching the pointer displays the contents of array1 as follows (as
 expected):

    pointer : "Array1"

 Watching any of the arrays with an "s" formatter also gives results
 that probably are unwanted. The arrays with explicit sizes show eight
 different strings; strings that are pointed to by the character
 elements of the array. The array with implicit sizes again shows an
 empty set of braces.

 Watching the pointer with an "s" gives the expected results, as
 follows:

    pointer,s : "Array1"

 All six variables can be watched as strings, and not as arrays of
 characters, with the following watch format:

    &array1[0],s : "Array1"

 The first element of any of the variables is a character, the address
 of which is a character pointer. This pointer can then be cast to a
 string.

 The following sample program is an example of watching string
 variables in QuickC Version 2.00:

 #include <string.h>

 char array1[8];
 char array2[8] =  "Array2";
 char array3[8] = {'A', 'r', 'r', 'a', 'y', '3', '\0'};
 char array4[]  =  "Array4";
 char array5[]  = {'A', 'r', 'r', 'a', 'y', '5', '\0'};

 char *pointer  = array1;

 void main( void )
 {
     strcpy( array1, "Array1" );
 }



 142. Initialized Local Arrays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42073

 Microsoft QuickC Version 2.00 now allows you to have initialized local
 arrays.

 For example, the following program generates the following message if
 compiled under C Version 5.10 or QuickC Version 1.01.

    error C2073 - cannot initialize array in function

 However, if the program is compiled under QuickC Version 2.00 it works
 correctly with no errors. This is the correct behavior, and is a new
 feature of Microsoft QuickC Version 2.00.

 The following is an example:

 void main(void)
 {
     int test[5] = { 1, 2, 3, 4, 5 };
 }


 143. ESC Key Aborts Only the Compile Process in QC Environment

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q42074

 The inside cover of the "Microsoft QuickC Up and Running" manual
 states that the ESC key stops the compiler and linker from continuing.
 This is only partially correct. The ESC key only aborts the compile
 stage of the QuickC compiler. During the link stage, the ESC key is
 ignored.

 Pressing CTRL+C or CTRL+BREAK aborts the compile or link (or ilink)
 processes, though it may take repeated attempts. However, pressing
 CTRL+C or CTRL+BREAK during the compile process can result in an
 incomplete object file that will not link properly. Pressing CTRL+C or
 CTRL+BREAK during the link process may result in a bad executable
 file. Attempting to run the bad .EXE may hang your machine.


 144. Errors C1059, C1060, D2027 Can Be Caused by Not Enough Memory

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-OCT-1989    ArticleIdent: Q42076

 The Microsoft QuickC Version 2.00 command-line compiler QCL may
 generate the following fatal-errors when there is not enough memory:

    C1059  out of near heap space

    C1060  out of far heap space

    D2027  could not execute 'qccom.exe'

 QuickC requires a minimum of 448K of available conventional DOS memory
 (512K recommended for larger applications) for proper operation.

 To check your available memory, use the DOS "chkdsk" program. The last
 number on the screen is your available memory.

 Note: If there is only a small amount of RAM available (less than 40K)
 QCL may hang.



 145. QuickC 2.00 README.DOC: Example Program PARRAY1.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42077

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 110  Example Program PARRAY1.C

 Change the following line:

    printf("array[%d]  = %d\n", count, *ptr++);

 to:

    printf("i_array[%d] = %d\n", count, *ptr++);

 The PARRAY1.C program in on-line help already contains this
 correction, but you may want to correct the printed listing, too.


 146. QuickC 2.00 README.DOC: Example Program SORT.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42078

 The following information is taken from the QuickC Version 2.00
 README.DOC file, part 2, "Notes on 'C for Yourself.'" The following
 notes refer to specific pages in "C for Yourself."

 Page 118  Example Program SORT.C

 If you compile the program SORT.C and run it from the DOS command
 line, it conflicts with the DOS SORT command. To eliminate the
 problem, rename the file SORT.EXE as QCSORT.EXE.


 147. Only One Scaletitle May Appear in Bar, Column, and Line Charts

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q47660

 Question:

 When using Presentation Graphics to display bar charts, I cannot get
 the scaletitle to display for both axes. I have set up titles exactly
 as in the examples, and I have done everything the same for both axes.
 Yet, when I run my program, I get both axistitles and only one of the
 scaletitles. What am I doing wrong?

 Response:

 When you are displaying bar, column, or line charts, you may only have
 a scaletitle on one axis. Scaletitles can be used only on a value axis
 to describe value data; that is, the data must be numeric data that
 can have a scalefactor applied to it. In a bar, column, or line chart,
 one axis has value data and the other has category data that the
 values fit into; therefore, only one axis can have a scaletitle.

 A scaletitle is defined as "a string of text that describes the value
 of scalefactor."  For example, the scaletitle "(x 1000)" signifies
 that the units of this particular axis are "times 1000". Thus,
 scaletitles are useful only for charts with large units, such as
 millions, where you would not want to crowd your axis with something
 similar to the following:

 1000000 2000000 3000000 4000000 5000000 6000000 7000000 8000000

 Instead, using  "1   2   3   4   5   6   7   8" (without the quotation
 marks) on the axis ticks, with a scaletitle of "(x 1000000)", is a
 much neater way of presenting the chart.

 The scaled data in a chart is relevant only when it is viewed in the
 context of some category that gives it a frame of reference. For
 instance, categories could be the months of the year or the sales
 regions for a company to which the data pertains. Thus, one axis must
 contain categorical information (nonvalue data) that serves as the
 comparison basis for the numeric value data. The categorical axis is
 the one where you cannot have a scaletitle.

 In a bar chart, the x-axis contains the numeric data, and therefore,
 may have a scaletitle. In a column or line chart, the y-axis is the
 value axis that can have the scaletitle. Only in a scatter chart,
 where both axes may contain numeric values, are you allowed to put
 scaletitles on both axes.

 The scaletitle variable is part of the chart environment (chartenv)
 variable "env". To modify the scaletitle variable, you must copy a
 string into one of the axis variables in the chart environment as
 depicted in the following source line:

    strcpy(env.xaxis.scaletitle.title,"x 10000");

 Scaletitle is of type "titletype", which has the following structure
 definition:

 typedef struct {
   char    title[_PG_TITLELEN];     /* Title text */
   short   titlecolor;              /* Palette color for the title */
   short   justify;                 /* _PG_LEFT, _PG_CENTERAL or
   _PG_RIGHT */
 } titletype;

 If you want to put other information alongside an axistitle that is
 not scalefactor information, then you should use the _pg_hlabelchart
 and _pg_vlabelchart functions. These functions allow you to output
 text anywhere on a chart in either a horizontal or vertical
 orientation. All you need to specify with these functions is the
 starting screen coordinates, the length of the output string, and the
 text to output.

 For more information on these functions, or to learn more about
 chartenv types, axistypes, and titletypes, see the Presentation
 Graphics chapter in "C for Yourself," the QuickC on-line help, or the
 "Microsoft QuickC Graphics Library Reference."


 148. Memory Model Stored in Both QC.INI and .MAK Files

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42363

 QuickC Version 2.00 stores the most recently used memory model in the
 QC.INI file; the memory model being used for a project in the .MAK
 file for that project also is stored there. If the model is changed
 for a single file in the project, then the model specification changes
 for the entire .MAK file.

 When the QuickC environment is invoked, the memory model will be set
 to whatever was saved in the QC.INI file. If a program list is set,
 the memory model saved in the .MAK file overrides the QC.INI memory
 model. Whenever the model changes, it first tries to save this in the
 .MAK file; if there is no .MAK file, it is saved in QC.INI.

 To avoid multiple QC.INI's on your disk you can place the initial
 QC.INI in the directory where QC.EXE resides.  QuickC will find
 QC.INI if it is in the path.

 Note that if the .MAK file exists for the file in which the memory
 model was changed, the memory model is not saved to the QC.INI. The
 manner in which this works is important to consider in order to avoid
 mixing .OBJ files compiled under different memory models.


 149. Eliminating Extra QC.INI Files

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42415

 Question:

 Why does QuickC 2.00 create a new QC.INI file in every directory that
 I compile in?  How can I get QuickC to generate only one of these
 files and then always use it?

 Response:

 When QuickC is started, it looks first in the default directory and
 then along the PATH environment variable for QC.INI. If it doesn't
 find this file, it will start with its default configuration. Making
 any changes to QuickC's configuration will cause it to create a QC.INI
 file in the default directory.

 To keep QuickC from creating multiple QC.INI files, start it from the
 directory where QC.EXE is found and make a change to its
 configuration. This will create a QC.INI file in that directory. This
 .INI file then will be found in the PATH when QuickC is started from
 any other directory.


 150. How to Get Help on Errors in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42420

 Question:

 How can I get help on the error messages without actually getting the
 errors?

 Response:

 You can get help on all compiler errors, compiler warnings, and link
 errors in the following way:

 1. Inside the QuickC environment, in the Edit window type "e." and
    then the error number. For example:

       e.c1015

 2. Highlight the error number including the "e.". Make sure NOT to
    highlight anything before "e" or after the error number.

 3. Press F1 or pull down the Help menu and choose Topic. The topic
    will be e.c1015.

 Help on the error will now be displayed.


 151. Unwanted R6013: Illegal Far Pointer Use

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42448

 Problem:

 When I set a far pointer to an absolute address, such as Video memory,
 I get a run-time error "R6013 Illegal far pointer use".

 Response:

 To set pointers to an address below your program's data segment(s),
 you must first disable pointer checking in Compiler Flags, which can
 be accessed from Make Option under the Options menu; or use the
 check_pointer pragma to turn pointer checking on and off.

 QuickC 2.00 has a feature that adds code to the executable to check
 for null pointer assignments and out-of-range pointers. Any attempt to
 store data into a pointer that points into the program's code
 segment(s) or any place before the data segment(s) produces this
 run-time error. This information is documented in the "Microsoft
 QuickC Tool Kit Version 2.0" manual, Section 4.3.34 /Zr (Check
 Pointers), Page 104-105.


 152. Linker Error Message L4004: Possible Fixup Overflow...

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_LINK
 Last Modified: 31-MAY-1989    ArticleIdent: Q44926

 The following linker warning is undocumented with QuickC 2.00. This
 warning can occur when making a near call to a far function.

    Warning: L4004  Possible fixup overflow at addr in segment name

 This warning is issued for DOS programs when a near call/jump is made
 to another segment that is not a member of the same group as the
 segment from which the call/jump was made. This call/jump can cause an
 incorrect real-mode address calculation when the distance between the
 paragraph address (frame number) of the segment group and the target
 segment is greater than 64K, even when the distance between the
 segment where the call/jump was actually made and the target segment
 is less than 64K.


 153. QuickC Tool Kit Manual: Document Transfer Formatting Error

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q42560

 Page 196 of the "Microsoft QuickC Tool Kit" manual for Version 2.00
 incorrectly states the following:

    It allows documents to be transferred from one application to
    another WITH losing any formatting information.

 The line should read as follows:

    It allows documents to be transferred from one application to
    another WITHOUT losing any formatting information.


 154. SAMPLE.TXT Not Distributed with QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q42561

 Page 184 of the "Microsoft QuickC Tool Kit" manual for Version 2.00
 incorrectly states that a sample help file called SAMPLE.TXT is
 included on the QuickC distribution disks.

 SAMPLE.TXT was not included in QuickC Version 2.00.


 155. Solutions to QuickC 2.00 Color Problems on Isolated Machines

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | appnote
 Last Modified:  2-MAY-1989    ArticleIdent: Q42581

 QuickC Version 2.00 has been shown to have a problem on TANDY 1000s
 and PCjrs that causes the colors of the QuickC environment to be
 unreadable. There are two solutions to this:

 1. TANDY DOS has an extended MODE command that allows the palette to
    be remapped. The format of this command is as follows:

       MODE  COLORMAP <color to be changed>  <desired color>

    For more details on this command and its usage, refer to the TANDY
    DOS reference manual. To resolve the color problem in QuickC 2.00,
    you should follow these steps:

    a. Enter QuickC (the color problem will present itself).

    b. Exit QuickC (exit, not DOS shell; the poor color choice will
       remain).

    c. Use the MODE command to remap the colors. The following single
       remapping will resolve the majority of the color conflict:

          MODE COLORMAP  MAGENTA GRAY

    Further remappings can be used to tailor the colors to your liking.

 2. The above resolution assumes that you have TANDY DOS. If you do not
    have TANDY's DOS, there is a similar patch that Product Support has
    made available in an application note. This application note is
    available from Product Support by calling (206) 454-2030.



 156. RDFILE.C And WRFILE.C Are Incorrect in QuickC's On-Line Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | langdoc docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q42598

 The sample programs WRFILE.C, on Page 179, and RDFILE.C, on Page 181,
 in the "C for Yourself" manual that comes with Microsoft QuickC
 Version 2.00 are correct. However, when you pull up those examples
 from the on-line help, you will notice that the fopen() function calls
 are incorrect. The single backslash ("\") should be replaced by a
 double backslash ("\\").

 To access the on-line examples, do the following:

 1. Enter the QuickC environment.

 2. Choose the Help menu.

 3. Choose Contents.

 4. Choose C for Yourself Programs.

 You should see quite a few files listed. To bring up the file WRFILE.C
 or RDFILE.C, move the cursor to that file and press ENTER, or double
 click the right mouse button. In both files, you need to change the
 line containing the fopen() function. Change the first parameter in
 the function call from

    c:\testfile.asc

 to

    c:\\testfile.asc

 Now the file will compile, link, and run correctly.


 157. QuickC 2.00 README.DOC: Type Quantifiers

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42687

 The following information on type quantifiers is taken from the QuickC
 2.00 README.DOC file, Part 2, "Notes on 'C for Yourself'". The
 following notes refer to specific pages in "C for Yourself".

 Page 48   Type Quantifiers

 The fourth paragraph in this section is incorrect. A long double value
 is the same size as a double. It contains 8 bytes, not 10. It
 expresses a floating point number with at least 15 digits of
 precision, not 19.

 Table 4.1 on Page 49 should also be corrected.


 158. QuickC 2.00 README.DOC: Example Program IF.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42689

 The following information on Example Program IF.C is taken from the
 QuickC 2.00 README.DOC file, Part 2, "Notes on 'C for Yourself'". The
 following notes refer to specific pages in "C for Yourself".

 Page 37   Example Program IF.C

 If you compile the program IF.C and run it from the DOS command line,
 it conflicts with the DOS IF command. To eliminate the conflict,
 rename the file IF.EXE as QCIF.EXE.


 159. QuickC: Local Contexts Fail in HELPMAKE

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 18-MAY-1989    ArticleIdent: Q42767

 Local contexts do not function properly under HELPMAKE Version 1.00,
 which is supplied with QuickC Version 2.00. The example on Page 189 of
 the "Microsoft QuickC Tool Kit Version 2.00" manual demonstrates this
 problem. If this file is encoded into a .HLP file and you request help
 on "normal", the correct help text is displayed. However, if you
 request help on "button", the printf format specifier table is
 displayed. The problem that help is having is that it indexes only
 from the top of the help file QC.HLP.

 To work around this problem, do not use local contexts. Instead, use
 the format "filename!context_string" as described on the top of Page
 189. Assuming the name of the encoded source file on Page 189 is
 NORMAL.HLP, the following modified version of this example illustrates
 this workaround:

    .context normal
    This is a normal topic, accessible by the context string
    "normal."
    [button\vnormal.hlp!local\v] is a cross-reference to the following
    topic.

    .context local
    This topic can be reached only if the user browses
    sequentially through the file or uses the cross-reference
    in the previous topic.

 The two changes made are in both references to "@local". The first
 reference (line 4) is replaced with "normal.hlp!local". The second
 reference (line 7) is replaced with "local".

 The drawback to this workaround is that if help is requested on
 "local", the associated text will be displayed. This is a minor
 nuisance, however. Thus, the text under ".context local" would now be
 accurate if it read as follows:

    This topic can be reached if the user browses sequentially
    through the file, uses the cross-reference in the previous
    topic, or requests help on "local".

 If the above help source is in a file named NORMAL.SRC, the following
 command will encode this file to NORMAL.HLP:

    helpmake /A: /W128 /Onormal.hlp /E15 normal.src /V >normal.dgn

 At this point you may perform one of the following two operations:

 1. Append ";normal.hlp" to the DOS environment variable HELPFILES.

 2. Append NORMAL.HLP to an existing .HLP file, as in the following
    example:

       copy qc.hlp /b + normal.hlp /b

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.


 160. QuickC 2.00 Editor Function: ResetState

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | editor
 Last Modified:  2-MAY-1989    ArticleIdent: Q42772

 Question:

 Pages 61 and 63 of the "Microsoft QuickC Up and Running" manual
 mention a function called "ResetState." What does this function do,
 and how is it used?

 Response:

 The ResetState command is used to cancel prefix tables. A prefix table
 is a table used by QuickC to store multiple keystroke editor commands.

 ResetState will cancel the functions that have multiple keystrokes,
 for example: BegLine, BegPgm, Change, and Endline. The invocation of
 these functions always begins with CTRL+K or CTRL+Q; thus, ResetState
 is invoked with CTRL+K followed by CTRL+U, CTRL+Q followed by CTRL+U,
 or simply CTRL+U.

 Example of Use

 Suppose that the SetBookMark function was invoked with the intention
 of setting bookmark 0. This keystroke combination would be CTRL+K
 followed by 0. There are two methods of completing this command after
 having pressed CTRL+K. The 0 key could be used to set the bookmark, or
 CTRL+U could be used to cancel the SetBookMark function.


 161. QuickC 2.00 Maximum Identifier Length Is 30 Characters

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 docerr
 Last Modified: 31-MAY-1989    ArticleIdent: Q42775

 Contrary to what is stated on Page 24 of the "Microsoft QuickC
 Language Reference" manual, QuickC Version 2.00 will truncate
 identifiers of 31 characters or more to a length of 30 characters.
 QuickC 1.01 and C 5.10 properly truncate identifiers to a length of 31
 characters. The incorrect truncation performed by QuickC 2.00 results
 in the following linker error when linking with .OBJ files or
 libraries in which referenced symbols have names of 31 characters or
 more:

    L2029: Unresolved externals:

 This may also be the case with code compiled with other versions of
 the Microsoft C compiler. Multiple definition errors may also result
 if identifiers with the first 30 characters in common differ only from
 the 31st character onward.

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.


 162. mkdir() Followed by chdir() Causes QuickC Debugging Problem

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q42777

 The program below demonstrates a problem with the QuickC 2.00
 debugger. Creating a directory with the mkdir() function and making it
 the current working directory with the chdir() function will, under
 certain conditions, produce the following error:

    File not found: D:\NEW_DIR\BIFF.C

 This error will be produced if a breakpoint is set at a line after the
 one in which the chdir() function is called. NEW_DIR is the directory
 that was created and made the current working directory. BIFF.C is the
 current module being executed in the debugger.

 Setting a breakpoint on the getch() line in the following sample
 program will demonstrate this problem:

 #include <direct.h>
 #include <conio.h>

 void main()
 {
     if( !mkdir( "NEW_DIR" ) )
     {
         chdir( "NEW_DIR" );
         getch();                    /* Set breakpoint here */
     }
 }

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.


 163. QuickC: Tracking Down Null Pointer Assignments

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42791

 When a program modifies memory at location 0 (NULL) in the small or
 medium memory models, the following error message is reported at
 program termination:

    run-time error R6001
    - null pointer assignment

 You can find the location of null pointer assignments in the small and
 medium memory models using either the debugger in QuickC Versions 2.00
 and later or the CodeView debugger.

 To detect null pointer assignments in QuickC 2.00 and later, do the
 following:

 1. Select the Watchpoint option under the Debug menu.

 2. Input the following:

       * (long *) 0

 This watchpoint will cause QuickC to stop executing your program when
 the memory location 0 (NULL) is modified. QuickC will immediately
 display the following pop-up and will highlight the line of code
 directly following the line that modified memory location 0:

    Watchpoint reached:
        * (long *) 0

 The null segment is 66 bytes long, and only four (4) bytes are watched
 with the above watchpoint. However, most cases of null pointer
 assignment occur when the first four bytes of the null segment are
 modified. Those cases will be caught with this watchpoint.

 Note that this technique does not apply to the compact, large, and
 huge memory models because their data pointers are far, by default.

 Information for using the CodeView debugger is provided in the
 "Microsoft CodeView and Utilities Software Development Tools for the
 MS-DOS Operating System" manual.



 164. DOS Redirection and QuickC Environment Command Line

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42802

 In Microsoft QuickC Versions 1.00 and 1.01, the command line can be
 entered from the RUN menu, "Set Runtime Options" screen. Version 2.00
 has the command-line screen on the OPTIONS menu, "Run / Debug" screen.

 The Microsoft Quick C Versions 1.00, 1.01, and 2.00 integrated
 environments do not allow DOS's "<input.fil >output.fil" redirection
 commands when they are entered in the "enter command line" portion of
 QuickC. They become normal arguments to the application program.

 In QuickC 2.00, you can achieve redirection of input and output by
 entering their commands in the "Run DOS command..." screen in the
 UTILITY menu. The disadvantage is the loss of the debugger.

 For redirection to be initiated, a new command process must be
 invoked. Since QuickC spawns the application program directly, no new
 COMMAND.COM is loaded. Thus, the redirection commands become arguments
 to the application.

 Input and output can be redirected at the execution of QuickC.

 For input redirection, the following command will use the contents of
 PROG.IN as the input data for the application:

    qc prog.c <prog.in

 The input will be consumed as the program requests input. When the
 input is depleted, subsequent requests for input will not be
 satisfied. Thus, the program waits forever. CTRL+BREAK or CTRL+C will
 take you back to the environment in Versions 1.00 and 1.01. Version
 2.00 does not return control back to the environment.

 For Version 2.00, if output is redirected on the invocation of Quick
 C, as in the following example, all of the output from the application
 program, including PROG.EXE, is sent to the file PROG.OUT at the
 beginning; and "Elapsed time 00:00:08.97. Program returned (-1). Press
 any key." is sent at the end:

    qc prog.c >prog.out

 Quick C Versions 1.00 and 1.01 will send the string "Program returned
 (-1). Press any key." to the output file after your application has
 completed.

 Note: DOS redirection will affect the DOS shell. If input was
 redirected, you will not be able to type "exit" in order to get back to
 QuickC.



 165. Use QuickC Environment and Compile with QCL or NMAKE

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q42926

 To compile with QCL or NMAKE and use the environment for development,
 add QCL or NMAKE to the "Utility" menu.

 The following example adds QCL to the "Utility" menu:

 1. Select "Utility" menu.

 2. Select "Customize Menu".

 3. Select "Add" to add a new option to the menu.

 4. Fill in the template with appropriate information, such as the
    following:

      Menu Text:                    Compile Program
      Path Name:                    qcl
      Arguments:                    /Zi /Od /qc $FILE
      Initial Directory:            <directory for .EXE file>
      Prompt Before Returning:      X (Yes)
      Accelerator Key:              Alt-F[5  ]

 The information you fill in is dependent on the command you wish
 to add. The accelerator key is the hot key which allows you to
 perform the command without having to pull down the "Utility/
 Customize Menu" menu.

 You can add NMAKE or other commands to the "Utility" menu in the
 same manner. For further help, use the F1 key in QuickC on the
 option you need help with.



 166. Parameter Order Incorrect for _pg_chartms, _pg_charscatterms

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr S_QuickAsm
 Last Modified: 10-OCT-1989    ArticleIdent: Q49315

 Pages 322 and 323 of the Microsoft QuickC "C for Yourself" reference
 incorrectly states the order of the parameters for _pg_chartms() and
 _pg_chartscatterms().

 The variables "n" and "nseries" are not in their correct order for the
 _pg_chartms() and _pg_chartscatterms() functions to properly plot the
 data values. The two variables, "n" and "nseries", must be switched
 for the functions to work correctly.

 The correct documentation for _pg_chartms() and _pg_chartscatterms() can
 be found in the on-line help for QuickC and QuickC with QuickAssembler
 integrated environment, and on Pages 144 and 145 of the "Microsoft
 QuickC Graphics Library Reference" manual.

 The incorrect functions are as follows:

    _pg_chartms (chartenv far *env, char * far *categories,
                 float far *values, short n, short nseries,
                 short arraydim, char far *serieslabels);

    _pg_chartscatterms (chartenv far *env, float far *valuesx,
                        float far *valuesy, short n, short nseries,
                        short arraydim, char * far *serieslabels);

 The correct parameters should read as follows:

    _pg_chartms (chartenv far *env, char * far *categories,
                 float far *values, short nseries, short n,
                 short arraydim, char far *serieslabels);

    _pg_chartscatterms (chartenv far *env, float far *valuesx,
                        float far *valuesy, short nseries, short n,
                        short arraydim, char * far *serieslabels);


 167. Problem with Floats in While Loop

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q42943

 The program below will execute the while loop once when it should not
 execute it at all, when compiled in either the QuickC environment or
 using the QCL command. The workaround is to replace the "while"
 statement with the following:

    while (test < 1.0)

 In C Version 5.00 or 5.10, the program works correctly without
 modification.

 The problematic program is as follows:

 #include <stdio.h>

 void main (void)
 {
     static float test = 4276.0;

     while (test < (float) 1)
        printf("Should not have entered loop, but did\n");
 }


 168. Missing Semicolon in GRAPHIC.C

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q42981

 On Pages 209 and 210 of "Microsoft QuickC: C For Yourself" is a
 listing of the program GRAPHIC.C. In addition to the misspelling
 pointed out in README.DOC (i.e., _ERESNOCOLOR spelled incorrectly as
 _ERESNOLOR), this program is missing a semicolon after the definition
 of modes.

 This definition should read as follows:

    int modes[12] =
    {
       _MRES4COLOR, _MRESNOCOLOR, _HRESBW,
       _HERCMONO,
       _MRES16COLOR, _HRES16COLOR, _ERESNOCOLOR, _ERESCOLOR,
       _VRES2COLOR, _VRES16COLOR, _MRES256COLOR, _ORESCOLOR
    };

 If this code is compiled without the trailing semicolon, it will
 produce the following error:

    error C2062: type 'void' unexpected

 This error will occur on the prototype to print_menu as follows:

    void print_menu( void );



 169. Altering BP Register in In-Line Assembly Block

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | inline
 Last Modified:  2-MAY-1989    ArticleIdent: Q42982

 In Microsoft QuickC Version 2.00, altering BP register in an in-line
 assembly block is not recommended. BP is used to reference the
 variables on the stack. If, for some reason, the BP register has to be
 modified, it should be pushed on the stack first. Before the BP
 register is popped back, referencing stack variables should avoided.
 The following is an example:

 /* sample program */
 #include <stdio.h>

 int nGlobal = 10 ;
 void main (void)
 {
 int nStackVar = 1 ;

 /* open the register window to observe the registers.
 ** open the debug window to observe the variables */
 _asm {
         mov ax, nStackVar   ; nStackVar is referenced correctly
         push bp
         mov bp, sp          ; change bp
         mov ax, nStackVar   ; nStackVar is not right
         mov bx, nGlobal     ; nGlobal is OK
         pop bp
         mov ax, nStackVar   ; nStackVar is OK again
         }
 }


 170. Fopen() Description Is Incomplete in On-Line Help of QC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q43001

 The information given in the Microsoft QuickC Compiler Version 2.00
 on-line help for the fopen() function is incomplete. The following is
 a more complete description of the "type" parameter, taken from Page
 274 of the "Microsoft QuickC Version 2.00 Run-Time Library Reference"
 manual.

 The character string "type" specifies the type of access requested for
 the file, as follows:

 Type     Description

 "r"      Opens for reading. If "r" is the first character in type, and
          the file does not exist or cannot be found, the fopen call
          will fail.

 "w"      Opens an empty file for writing. If the given file exists,
          its contents are destroyed.

 "a"      Opens for writing at the end of the file (appending); creates
          the file first if it doesn't exist.

 "r+"     Opens for both reading and writing. (The file must exist.)

 "w+"     Opens an empty file for both reading and writing. If the
          given file exists, its contents are destroyed.

 "a+"     Opens for reading and appending; creates the file first if it
          doesn't exist.

 Please note: Use the "w" and "w+" types with care, as they can destroy
 existing files.


 171. Debug Does Not Display Changes Made by _dos_setvect()

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |  buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43008

 The QuickC Version 2.00 debug window will not update the display of an
 entry in the interrupt vector table after _dos_setvect is used to
 change that entry. The program below will reproduce the problem.

 To demonstrate the problem, do the following:

 1. Start QuickC.

 2. Load the program below.

 3. Open the debug window and set watches on the following:

     hptr
     saveint
     ptr
     *ptr (use hex format)
     lp (use hex format)

 Use the F8 key to step into the program. Saveint contains the address
 of the old interrupt handler. Hptr contains the address of the new
 interrupt handler. Ptr points to the interrupt vector, thus *ptr shows
 the address of the interrupt handler and should be different after the
 call to _dos_setvect. However, it is not. Notice that lp does contain
 the correct address, demonstrating that internally all addresses are
 being held correctly. The watch window is simply not displaying the
 altered interrupt vector properly.

 The following sample program will demonstrate the problem:

 #include <stdio.h>
 #include <dos.h>
 #define THE_INT 0x12

 void interrupt far handler() ;

 void (interrupt far *hptr)() ;
 void (interrupt far *saveint)() ;
 long far* ptr ;
 unsigned long lp ;

 void main ( void )
 {
 hptr = handler ;
 saveint = _dos_getvect ( THE_INT ) ;

 FP_SEG ( ptr ) = 0 ;
 FP_OFF ( ptr ) = 0x48 ;    /* make ptr point to where the interrupt
                             * THE_INT is in interrupt vector table
                             */

 /* following will do the same thing by searching for the address
  * rather than setting ptr directly:
  */
 FP_SEG ( ptr ) = 0 ;
 FP_OFF ( ptr ) = 0 ;
 while (*ptr++ != (long) saveint) ;
 ptr -- ;
 */

 _dos_setvect ( THE_INT, hptr ) ;   /* set to new handler */
 lp = *ptr ;

 _dos_setvect ( THE_INT, saveint ) ; /* reset handler */
 }

 void interrupt far handler()
 {
 }



 172. Offsetof() Macro Gives Incorrect Results or C1045

 Product Version(s): 1.00 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_quickasm
 Last Modified: 13-FEB-1990    ArticleIdent: Q58533

 The offsetof() macro, defined in stddef.h, does not work correctly
 with doubles or floats. It either gives incorrect results or it gives
 a C1045, floating-point overflow error. It is possible to work around
 this problem by defining your own macro to get the offset of a field
 in a structure.

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

 Typically, you get the offset of a structure by issuing the following
 statement

    off = offsetof (struct foo, bar) ;

 where off is an unsigned integer (size_t), foo is a structure, and bar
 is a field in the structure foo. The difficulties occur when the field
 to which the offsetof() macro refers is a double or a float.

 The compiler generates the C1045 floating-point overflow error in some
 cases. It is possible to work around this by rearranging the contents
 of the structure to which offsetof() is referring.

 If the program compiles without giving fatal error C1045
 (floating-point overflow), then it will return zeros for all
 offsetof() references to the doubles or floats.

 Currently, the only way to work around the problem is to redefine the
 macro in the following way:

 extern int __zero ;

 #define NEWOFFSETOF(str,field)  (size_t)&(((str *)__zero)->field)

 The variable __zero should be set to 0 (zero) before any NEWOFFSETOF
 code is executed.

 As you can see, this method does work for statically initialized data.
 Because the new macro references a variable, the compiler cannot know
 what to initialize the data to. It is impossible to replace the
 variable __zero with an actual 0 (zero) because that is what the
 original macro is defined as.

 Defining the new macro to reference NULL allows you to statically
 initialize data, but it also gives the "floating-point overflow"
 error.

 Following is a sample program, which causes the error to occur:

 #include <stdio.h>
 #include <stddef.h>

 struct s
 {
     short   a ;
     double  b ;
 } ;

 void main (void)
 {
     printf ("The offsets are %u and %u\n",
             offsetof (struct s, a),
             offsetof (struct s, b)) ;
 }

 The results of the program should be as follows:

    The offsets are 0 and 2

 In fact, the output is (if it does compile) as follows:

    The offsets are 0 and 0

 The program can be rewritten in the following manner:

 #include <stdio.h>
 #include <stddef.h>

 struct s
 {
     short   a ;
     double  b ;
 } ;

 #define NEWOFFSETOF(str,field)  (size_t)&(((str *)__zero)->field)

 int __zero = 0 ;

 void main (void)
 {
     printf ("The offsets are %u and %u\n",
             NEWOFFSETOF (struct s, a),
             NEWOFFSETOF (struct s, b)) ;
 }

 The results are as follows:

    The offsets are 0 and 2


 173. CL Environment Variable in QuickC Err Msg: Object Not Found

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43045

 Including the /c on your CL environment variable when compiling inside
 the QuickC Version 2.00 environment can cause the following error
 message:

 L1093 : SOURCE.OBJ : object not found

 This problem can be corrected by removing the /c from the CL
 environment variable and erasing the .OBJ file which the compiler has
 generated for the source program.

 Oddly enough, this option will not cause a problem unless it is
 followed by another valid option, i.e., cl=/c will not cause the link
 failure.

 The CL environment variable is used by CL.EXE and QCL.EXE for setting
 default compiler options. While working inside the QuickC 2.00
 environment, it is a good idea to be conscious of which environment
 variables are set by CL.

 Utilizing the CL environment variable usually facilitates programming
 within the QuickC 2.00 environment. For example, the following line
 will tell the QuickC compiler to always use the coprocessor library:

 SET CL=/FPi87

 This can be very useful for programming inside the QuickC environment
 as well as outside of it.


 174. Calls Stack Is Sometimes Incomplete

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43063

 In QuickC Version 2.00, the calls stack is incomplete under specific
 circumstances. When you select Debug menu, Calls option, and the
 current statement is the opening brace of a function, the calls stack
 omits the second function that should be in the list. This is the only
 function omitted and can be restored to the list by using F8 to trace
 one line further into the code.

 The calls stack is complete in QuickC Versions 1.00 and 1.01.

 The calls stack lists all function calls that led to the current
 function. It is used for repositioning the cursor to a calling
 function by selecting that function from the calls stack. This is
 useful because it allows you to press F7 to execute the code necessary
 to return to a calling function.

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

 To demonstrate the problem, consider the following program:

    void A (void);
    void B (void);

    void main (void)
     {
       A ();
     }

    void A (void)
     {
       B ();
     }

    void B (void)
     {
     }

 1. Press F8 once. Selecting menu Debug, option Calls will result in the
    following display:

       main()

    This is correct.

 2. Press F8 twice. This procedure will trace into function A and
    highlight the opening brace. Selecting Calls will now list the
    following:

       A()

    This is incorrect. In addition to A(), main() should be listed.

 3. Press F8 again. Selecting Calls will now correctly list the
    following:

       A()
       main()

    Tracing past the initial brace of function A corrected the calls
    stack.

 4. Press F8 again. Selecting Calls now lists the following:

       B()
       main()

    This is once again incorrect. Between B() and main(), A() should be
    listed.


 175. QuickC 2.00 Editor Err Msg: Cannot Load Binary File

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43071

 Problem:

 When I try to load my file into the Microsoft QuickC Compiler Version
 2.00 editor I get the error message "Cannot load binary file." My
 program works properly when I use QCL to compile.

 Response:

 The QuickC 2.00 editor will load standard ASCII files. However, it
 will not load .EXE, .COM, or ASCII files containing certain control
 characters.

 The QuickC 2.00 editor assumes that a file is a binary file if it
 contains a null (ASCII 0) control character.

 To remove control characters from a file, use the CRLF.EXE utility
 provided on the QuickC 2.00 utilities disk.

 The syntax for the command is as follows :

    crlf <infile> <outfile> [/c<ascii>]

 The /c option allows you to specify what ASCII character the control
 characters will be converted to. This switch is optional.


 176. Font Files Cannot Be Broken Apart

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUN-1989    ArticleIdent: Q45603

 The bit-mapped font files (HELVB.FON, TMSRB.FON, COURB.FON) contain
 various scales of their fonts. It is currently not possible to remove
 one particular font size from the file to create a single-size font
 file. To work around this, you must create your own font
 file via the use of the Windows font editor.


 177. Select Whole Word Search to Find Linker Errors

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43125

 QuickC Version 2.00 locates linker errors in a C source file. Because
 the linker passes identifiers (not line numbers) back to QuickC,
 QuickC performs a text search on the identifier. This technique is not
 foolproof. For example, QuickC may point the cursor inside a comment
 if it finds a matching identifier there. Bypass this occurrence of the
 identifier by pressing F3 to search for the next occurrence.

 QuickC uses the same search flags that you defined through the search
 menu. When the "Whole Word" option is not selected (off is the
 default), you may receive superfluous information.

 For example, in the following program, the identifier '_outtext' would
 be highlighted as an unresolved external. The real culprit is
 'outtext'. To produce the expected results, do the following:

 1. Select the Search menu.

 2. Select the Find option from the Search menu.

 3. Select the "Whole Word" option and recompile. The "Whole Word"
    option remains in effect until you exit from QuickC.

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

 The following example demonstrates searching with "Whole Word" off:

 /* Press F3 to bypass this occurrence of 'outtext'. */

 #include <graph.h>

 void main (void)
  {
    /* Select "Whole Word" search to bypass this. */
    _outtext ("Wombat hats");

    /* This is the only line we want to find.   */
    outtext ("and widgets");
  }

 Common linker errors that will exhibit these problems are:

 error L2029 : <name> : unresolved external
 error L2025 : <name> : symbol defined more than once
 error L2044 : <name> : symbol multiply defined, use /NOE



 178. QuickC: Locating a Corresponding Brace

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43141

 To get QuickC Version 1.00 and 1.01 to show the corresponding closing
 brace of an opening brace and vice versa, position the cursor on any
 closing or opening brace, bracket, parentheses, or less-than or
 greater-than signs, and then press "CTRL+{" or "CTRL+}" (without the
 quotes). QuickC will now position the cursor on the corresponding
 character.

 In QuickC Version 2.00 the same functionality is provided, although
 only CTRL+} will invoke the function. CTRL+{ will not have any effect.


 179. QuickC: The Inline Assembler Generates 3-Byte JMP Instructions

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43142

 The following instruction will assemble, link, and run correctly in
 the Microsoft Macro Assembler Version 5.10:

    JMP  $+2

 However, the Microsoft QuickC Compiler Version 2.00 inline assembler
 will generate code that hangs the machine when executed.

 This is expected behavior and is due to the fact that the inline
 assembler must generate code as assembly mnemonics are encountered.
 Therefore, it cannot tell that the instruction is a SHORT jump. The
 Microsoft Macro Assembler will optimize the code into a 2-byte jump
 instruction while QuickC will generate a 3-byte jump instruction. To
 achieve the desired result either change the instruction to the
 following:

    JMP  $+3

 or

    JMP SHORT $+2

 The desired result of this instruction is to simply jump to the
 instruction located at the address pointed to by the instruction
 pointer, plus the number of bytes specified.

 The following MASM program will have the effect of skipping the second
 instruction:

                                     TITLE  test
                                     DOSSEG
                                     .MODEL SMALL
                                     .CODE
  0000                           start:
  0000  EB 02                        jmp  $+4
  0002  EB 00                        jmp  $+2
  0004  EB 00                        jmp  $+2
  0006  B8 4C00                      mov  ax,4c00h
  0009  CD 21                        int  21h
                                 END start

 Clearly, the Assembler is producing a 2-byte JMP instruction. The
 following is the code compiled with QuickC Version 2.00 which will
 have the same effect:

 void main(void_ {
      _asm {
           jmp $+6
           jmp $+3
           jmp $+3
      }

 Upon viewing the mixed C/assembly in CodeView 2.20, it is clear that
 QuickC is generating a 3-byte JMP instruction:

 1:      void main(void) {
 /* startup code here */
 3:                      jmp $+6
 6DD8:002B E90300         JMP       _main+11 (0031)
 4:                      jmp $+3
 6DD8:002E E90000         JMP       _main+11 (0031)
 5:                      jmp $+3
 6DD8:0031 E90000         JMP       _main+14 (0034)
 7:         }
 /* exit code here */


 180. QuickC: MATH.C Sample Program Contains Incorrect Expressions

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c docerr
 Last Modified:  6-JUN-1989    ArticleIdent: Q43217

 The sample program MATH.C found in the QuickC Version 2.00 on-line
 help system contains the following two statements, which do
 not produce the intended results:

    printf( "Mantissa: %2.2lf\tExponent: %d\n", frexp( x, &n ), n );
    printf( "Fraction: %2.2lf\tInteger: %lf\n", modf( x, &y ), y );

 The last parameter passed to printf() in each of these statements will
 not be displayed correctly when the program is compiled under QuickC
 because "n" and "y" are pushed onto the stack before they are altered
 in the calls to frexp() and modf().

 This example illustrates the danger of relying upon the order of
 expression evaluation. When compiled under Microsoft C 5.10 with
 default optimizations or optimizations disabled, these statements
 function as desired; that is, n and y are altered by frexp() and
 modf() before they are pushed onto the stack and displayed by
 printf(). When compiled under C 5.10 with maximum optimization,
 however, the statements will be pushed before being changed, just as
 in QuickC.

 Correcting this problem is simply a matter of ensuring that frexp()
 and modf() execute prior to the use of n and y, as follows:

    double r;

    r = frexp( x, &n );
    printf( "Mantissa: %2.2lf\tExponent: %d\n", r, n );
    r = modf( x, &y );
    printf( "Fraction: %2.2lf\tInteger: %lf\n", r, y );

 The MATH.C program is associated with the following functions:

    exp     pow      sqrt     frexp     log     log10
    ldexp   modf     ceil     floor     fabs    fmod


 181. scanf, sscanf, fscanf Functions Fail When Scanning All Zeros

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43219

 The functions scanf, sscanf, and fscanf fail when all of the following
 conditions are satisfied:

 1. The format specifier for a field is any of the following, where "w"
    is the maximum input field width:

       %wX    %wI    %wD
       %wx    %wi    %wO
       %wlx   %wli   %wU

 2. The field being scanned is all zeros and has a length of w.

 3. The field being scanned is immediately followed by a valid digit
    (no intervening white space).

 Under the above conditions, these functions read one extra digit from
 the input buffer as if the "skip leading zeros" routine doesn't
 realize that it is scanning past the maximum length specified (w).

 To work around this problem, for the format specifiers %wD, %wO, and
 %wU, use %wld, %wlo, and %wlu, respectively. For the remaining
 specifiers, there is no workaround other than to scan the buffer
 character by character.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 The following program demonstrates this problem:

 #include <stdio.h>

 void main (void)
  { int a, b;

    /* There are 2 zeros, and w=2. */
    sscanf ( "0012", "%2x%d", &a, &b );

    /* This should output:   a=0 b=12
     * Instead, it outputs:  a=1 b=2
     */
    printf ( "a=%x b=%d\n", a, b );
  }



 182. strspn() Function Not Directly Available in On-line Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q43258

 The function strspn() cannot be found in the QuickC Advisor (on-line
 help for QuickC Version 2.00), even though it is listed in the index.

 The information for "strspn" can be found under "strcspn".

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching the problem and will post new information as it becomes
 available.


 183. Presentation Graphics Allows Only One Color Per Data Series

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JUL-1989    ArticleIdent: Q46803

 Question:

 Can the colors of individual bars (or columns) on a single-series bar
 (or column) chart be changed?

 Response:

 No; the only way to change colors is to change the color for the
 entire series, and therefore for all of the bars (or columns). This is
 done by modifying the "paletteentry" structure, which is assigned to
 the series. The paletteentry structure is defined as follows:

 typedef struct
 {
     unsigned short          color;
     unsigned short          style;
     fillmap                 fill;
     char                    plotchar;
 } paletteentry;

 An array of paletteentry types is predefined as

    typedef paletteentry palettetype[_PG_PALETTELEN];

 where _PG_PALETTELEN is the number of series defined.

 When using a single-series chart, only palettetype[0] is defined,
 giving you the ability to assign one color, one style, one fillmask,
 and one plot character to the series. This is by design and
 cannot be changed.


 184. QuickC: Version 2.00 Search and Replace Problem

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43375

 The QuickC Version 2.00 editor will appear to crash when a search and
 replace is done under the following conditions:

 1. Replace an uppercase string with a lowercase string of the same
    name.

 2. The cursor must be placed one character after the word being
    replaced.

 To duplicate this behavior perform the following steps inside the
 editor:

 1. Type the following (leave the cursor after the "S"):

       REPLACETHIS

 2. Use the command CONTROL+Q and set the following:

       Find What = REPLACETHIS
       Change to = replacethis

 3. Leave the other options at their default values and select "find
    and verify" or "change all".

 The search and replace seems to go into an infinite loop. If you
 select the "find and verify" option you can cancel to get out of the
 loop.

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


 185. No Explicit Limit on Length of Literal Strings In QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 12-NOV-1990    ArticleIdent: Q43393

 A string literal more than 512 characters long will compile, link, and
 execute correctly with the Microsoft QuickC Compiler, Version 2.00.
 However, the Microsoft C Optimizing Compiler, Version 5.10, gives the
 following error message:

    filename.c(line #) : warning C4009 : string too big, trailing chars
                         truncated

 This is expected behavior. The maximum length of a string literal
 under C 5.10 is 512 bytes, including the terminating null character.
 This is documented on Page 280 of the "Microsoft C 5.10 Optimizing
 Compiler User's Guide". In C 6.00, this limit was increased to 2048
 bytes. Lastly, in QuickC 2.00 and 2.50 there is no explicit limit on
 the length of string literals. This is documented on Page 266 of the
 "Microsoft QuickC 2.00 Compiler Toolkit" manual.

 The limit on the size of a string literal under QuickC 2.00 is
 dependent on available memory. When there is not enough space, the
 compiler gives the following error message:

    filename.c(line #) : fatal error C1059 : out of near heap space

 This means that the compiler ran out of room in the near heap for
 storing the string literal. In this case, store the string literal in
 a file and read it into a character array at run time.


 186. Bad Code Produced for specific source when optimizations used

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 buglist2.00
 Last Modified: 18-MAY-1989    ArticleIdent: Q43175

 When compiling the source code below, the QuickC and QCL compilers
 will produce incorrect code if any optimizations other than loop
 optimization are enabled. If optimizations are disabled or only loop
 optimization is used, the compilers will generate correct code.

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

 This program will demonstrate the problem when compiled with
 optimizations enabled (/O):

 #include <stdio.h>

 void main( void )
 {
     int a, b, c;

     a = 0;
     b = 2 - ( 63 * a );
     c = ( b % 31 );       /* c should be 2
                              (the remainder of 2/31) */

     if( b != c )
     {
          printf( "FAILED\n" );
          exit( 1 );
     }
     else
     {
          printf( "PASSED\n" );
          exit( 0 );
     }
 }

                   Laguna Beach, CA 92651


 187. QuickC: GRDEMO Sample Program Gives Run-Time Error R6003

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 18-MAY-1989    ArticleIdent: Q43488

 In the sample program GRDEMO.C, which is provided with QuickC Version
 2.00, changing the aspect ratio of the window to zero will cause the
 following run-time error to occur:

    R6003: Integer divide by zero

 A simple bounds check may be added to the program to prevent the
 error.



 188. QuickC: Small and Medium Model Optimization Error

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 buglist2.00
 Last Modified:  2-MAY-1989    ArticleIdent: Q43507

 When compiling the source code below, the QuickC and QCL compilers
 will produce incorrect code if any optimizations except loop
 optimization are enabled.

 If optimizations are disabled or only loop optimization is used, the
 compilers will generate correct code. This problem only occurs in the
 small and medium memory models (near data pointers).

 The program shown below will demonstrate the problem when compiled
 with optimizations enabled under the small or medium memory models.

 When optimization is enabled,

    ps_ppr->ptr2

 is converted to

    *(ps_ppr->ptr2)

 The following code demonstrates this problem:

 #include <stdio.h>

 char *ppr1;
 struct ps
         {
           char blank;
           char *ptr2;
         } p_s,*ps_ppr;

 void main(void)
 {
   char d = 'A';
   ppr1   = &d ;
   ps_ppr = &p_s;

   ps_ppr->ptr2 = ppr1;

   if( ppr1 != ps_ppr->ptr2)
     {
       printf("Optimization test..........Failed\n");
       printf("%Np does not equal %Np \n",ppr1,ps_ppr->ptr2);
       exit(1);
     }
   else
     {
       printf("Optimization test..........Passed\n");
       printf("%Np  = %Np \n",ppr1,ps_ppr->ptr2);
       exit(0);
     }
  }

 Microsoft has confirmed this to be a problem in Versions 1.00, 1.01,
 and 2.00. We are researching this problem and will post new
 information as it becomes available.


 189. Assert Macro Causes Warning C4074 with /W3 in QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified:  2-MAY-1989    ArticleIdent: Q43513

 When compiled at warning level three, both QuickC Version 2.00 and C
 Version 5.10 will produce the following warning when the assert macro
 provided with QuickC 2.00 is used (the assert macro from C 5.10 does
 not cause the error):

    C4074: non standard extension used - 'function given file scope'

 The warning is due to a function, _assert, being prototyped within a
 statement block in the macro. A simplified example of this is shown
 below. The problem is caused by the first line after the opening
 brace. A function is defaulting to local scope when it needs a scope
 of file or global. The following is an example:

     #define assert(exp)                         \
     {                                           \
         void _assert( char *, char *, int );    \
         _assert( #exp, __FILE__, __LINE__ );    \
     }

 A simple modification can be made to ASSERT.H from QuickC 2.00 to
 avoid this warning. There are two lines that must be deleted from the
 include file and one line that needs to be added. Lines 33 and 45
 should be removed and one of them should then be inserted, excluding
 the trailing slash, at line 28, between the "#else" and "#ifdef _QC".
 The line that will be deleted and moved is as follows:

     void _CDECL _assert(void *, void *, unsigned); \



 190. 'strerror' Example in QuickC Manual May Yield Error

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q43535

 The 'strerror' example given at the top of Page 582 of the "Microsoft
 QuickC Run-Time Library Reference" may yield the following error:

    error C2086: 'errno' : redefinition

 Two conditions are required to produce this error:

 1. Compile for the compact- or large-memory model (/AC or /AL).

 2. Compile without ANSI compatibility enforced (no /Za).

 This error occurs because, under the above conditions, the external
 reference has an implied 'far cdecl' and contradicts the external
 reference in the include file ERRNO.H, as follows:

    extern int errno;

 The external reference in the include file ERRNO.H is as follows:

    extern int near cdecl errno;

 To correct this example, remove the following line:

    extern int errno;

 This line is not necessary in any case because the external reference
 to errno has already been made in ERRNO.H.

 Only QuickC Version 2.00 will produce the above error as it is the
 first Microsoft compiler to declare errno to be external in the
 include file ERRNO.H.


 191. NMAKE Example Incorrect in QuickC Manual; Should Be Lowercase

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q43538

 The example given on Page 169 of the "Microsoft QuickC Tool Kit
 Version  2.0" is
 incorrect: the inference rule is ignored because its dependent (.OBJ)
 is not in the .SUFFIXES list. (NMAKE is case sensitive and will not
 match ".OBJ" to ".obj".)

 To correct this example, put the entire example in lowercase letters.

 Please note that the inference rule given on Page 168 of the same
 manual makes the same mistake. This example should also be in all
 lowercase letters.

 If NMAKE is invoked on this example with no switches, no diagnostics
 are given; however, the command is not performed. To reveal the
 problem, invoke NMAKE with the /p switch, which will yield the
 following message:

    NMAKE : warning U4017: Ignoring rule .OBJ.EXE
                           (extension not in .SUFFIXES)

 Another workaround is to append .OBJ to the suffixes list by placing
 the following pseudotarget at the top of the NMAKE description file:

    .SUFFIXES: .OBJ


 192. _outtext() Expects an Unsigned Character Pointer as Parameter

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr outtext
 Last Modified:  2-MAY-1989    ArticleIdent: Q43554

 Page 449 of the "Microsoft QuickC Version 2.00 Run-Time Library
 Reference" manual incorrectly states that the _outtext() function
 expects a "char far *" as the parameter.

 The _outtext() function in Microsoft QuickC Version 2.00 actually
 expects an "unsigned char far *" as the parameter. The correct
 information is available in the on-line help and the include file
 GRAPH.H.

 This is a change between QuickC Version 2.00 and those versions
 earlier than 2.00. Earlier versions did expect a "char far *" as the
 parameter for the _outtext() function.


 193. How to Get HELPMAKE to Understand $INCLUDE

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43634

 Question:

 How do I get HELPMAKE to recognize the $INCLUDE environment variable
 while searching for a cross-referenced text file?

 Response:

 By default, HELPMAKE is not case sensitive. All context strings are
 translated into lowercase letters during the encoding process. Because
 the $INCLUDE environment variable is part of a context string, it is
 also translated to lowercase.

 DOS, on the other hand, translates all environment variables into
 uppercase letters as they are entered. This obviously presents a
 conflict when trying to resolve environment variables within HELPMAKE.

 HELPMAKE Version 1.00 provides a way to make context strings case
 sensitive. As documented on Page 181 of the QuickC Tool-Kit, the /C
 option must be given on the HELPMAKE command line to retain the case
 of the context strings.

 The following command will build a help file called OUTFILE.HLP from
 the text file INFILE.TXT, preserving case:

 helpmake /E /C /Ooutfile.hlp infile.txt

 QC.HLP was initially encoded with case-sensitive context strings; so,
 if you decode QC.HLP, you must remember to give the /C option when you
 encode it to preserve case. If you fail to do this, the resulting
 help file will be unable to search the INCLUDE environment variable
 for cross-reference text files.

 Some of the cross-reference text files used by QC.HLP are the C header
 files and the README.DOC(s).



 194. QuickC: Dual Floppy Compile/Link Procedure

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified:  2-MAY-1989    ArticleIdent: Q43702

 The following list details the steps used to compile and link with a
 Microsoft QuickC Version 2.00 dual-360K floppy setup. This procedure
 assumes that source files are stored on disk 5, which also contains
 the include and library files. This also assumes that no errors are
 encountered during the process. Remember to use backup disks, not
 your original disks.

 Instructions for the compile/link process with no errors during the
 compile phase are described below.

 Note: Drive A will be used to hold disks 1 and 2. Drive B will hold
 your work disk and disk 5. During the process, you will start with
 disk 1 in Drive A and your work disk in Drive B. You will swap between
 disks 1 and 2 in Drive A, and disks 5 and your work disk in Drive B.

 Assuming you have set up your disks as suggested by the README.DOC
 file, follow these steps to compile and link:

  1. Insert your DOS-bootable disk in Drive A.

  2. Turn on the machine.

  3. When the DOS prompt appears and the disk drive has stopped
     running, remove the boot disk and insert disk 1 in Drive A.

  4. Insert disk 5 in Drive B.

  5. Type "B:" at the DOS command prompt.

  6. Type "QC <filename>" (where <filename> is the name of the source
     file you will be working on).

  7. QuickC will now start. If the file does not currently exist,
     QuickC will ask if you want to create the file. Answer this query
     appropriately.

  8. You may now enter or edit your program.

  9. When the program is ready to be compiled, press F5.

 10. If you have made changes in the program QuickC will ask if you
     want to save these changes. Answer this query with a Yes or No.

 11. After a short while, QuickC will say it cannot find QCCOM.OVL.
     Insert disk 2 in Drive A, and press ENTER.

 12. QuickC will soon say it cannot access QC.EXE. At this point,
     again insert disk 1 in Drive A, and press ENTER.

 13. QuickC will ask for either ILINK.EXE or LINK.EXE soon. Remove disk
     1 from drive A, insert disk 2 into that drive, and press ENTER.

 14. After linking is complete, QuickC will ask for QC.EXE again.
     Remove disk 2 from Drive A and insert disk 1 in drive A. Press
     Enter.

 15. At this point you will have an executable file. Because you
     pressed F5 for run, QuickC will now run the program if no errors
     were encountered during the compile/link process.

 If there are errors in your code, QuickC will stop after step 12 and
 report any errors it finds. Correct these errors and start from Step
 9.


 195. Default Palette for Presentation Graphics in QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43740

 In Microsoft QuickC Version 2.00, the default palette for presentation
 graphics is independent of the palette used by low-level graphics
 routines. In addition, the presentation graphics palette uses a
 different index order than the palette for colors in graphics
 functions such as _settextcolor(). The default palette for
 presentation graphics is as follows:

    Index     Color             Index    Color

    0         Black              8       White
    1         Bright White       9       Gray
    2         Blue              10       Light Blue
    3         Green             11       Light Green
    4         Cyan              12       Light Cyan
    5         Red               13       Light Red
    6         Magenta           14       Light Magenta
    7         Brown             15       Yellow


 196. QuickC: Bad Symbolic Information for Char Array in Structure

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01
 Last Modified:  2-MAY-1989    ArticleIdent: Q43972

 Under Microsoft QuickC (QC) Versions 1.00 and 1.01, incorrect symbolic
 information is generated for particular elements of the structure
 defined below. The structure contains a pointer to itself, a bit
 field, and a character array.

 The structure is defined as follows:

 struct tag {
                   .
                   .
              struct tag *ptr;
                   .
                   .
              unsigned bit : 1;    /* problem is not dependent      */
                   .
                   .
              char array[10];      /* upon size of either data item */
                   .
                   .
            };

 Using CodeView (CV) or the integrated QC debugger, an examination of
 the array via a watch expression or a display expression (CV only)
 will yield "0" for its address and "" (double quotation marks) for its
 contents. However, dumping memory with the DA command in CodeView will
 reveal the actual contents of the array.

 This problem is dependent upon the existence and arrangement of the
 three data items, and not on additional structure elements. Without
 one of the three, proper symbolic information is produced. If the
 respective order of the three items is changed, the problem is also
 eliminated.

 Microsoft has confirmed this to be a problem in Versions 1.00 and
 1.01. We are researching this problem and will post new information as
 it becomes available.

 The problem does not manifest itself under the Microsoft QuickC
 Compiler Version 2.00 or the Microsoft Optimizing Compiler Versions
 5.x.

 The following sample program illustrates the necessary structure
 definition and arrangement to cause the problem:

 #include <string.h>

 struct tag {
              struct tag *ptr;
              unsigned bit : 1;
              char array[10];
            };

 void main( void )
 {
   strcpy(info.array, "boing");
 }

 Issuing the following commands displays the lack of proper symbolic
 information:

 >? info.array        /* debugging command */
 "0"                  /*   return value    */

                      /* debugging command--in QC, use the Add Watch */
 >w? info.array       /*                                Menu option  */
 "0"                  /*   return value in watch window */


 197. QuickC: Increasing Maximum Number of Open Files and Streams

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q43975

 Question:

 Is it possible to increase the maximum number of open files and
 maximum number of streams under QuickC Version 2.00?

 Response:

 QuickC 2.00 does not come with start-up code; therefore, you MUST have
 the Microsoft C 5.10 Optimizing Compiler to increase the maximum
 number of open files and streams. CRT0DAT.ASM and _FILE.C should be
 modified as described in the README.DOC included in the C 5.10
 package.

 Limited testing has been performed with QuickC 2.00 after altering
 the start-up code in this manner; however, Microsoft cannot guarantee
 that it will work properly in all cases.

 After successfully assembling CRT0DAT.ASM (use the /MX switch) and
 successfully compiling _FILE.C, you must do one of the following:

 1. Explicitly link your program with the new CRT0DAT.OBJ and/or
    _FILE.OBJ by compiling and linking on the command line using QuickC
    2.00. One possible command might be as follows:

       QCL TEST.C CRT0DAT /LINK /NOE

 2. You can also link with the modified start-up code by creating a
    program list in QuickC 2.00, which should include TEST.C,
    CRT0DAT.OBJ, and/or _FILE.OBJ. Do not forget to turn the extended
    dictionary flag OFF under the linker flags.

 3. Replace the CRT0DAT.OBJ and/or _FILE.OBJ in the appropriate model
    of the QuickC 2.00 run-time library. You can use the library
    manager and the Replace command symbol (-+) in the "commands" field
    to replace a module in the library.

 Note: Remember that the number of low-level files must be greater than
 or equal to the number of stream-level files. Therefore, if you
 increase the value of _NFILE_ in _FILE.C, you must also increase the
 value of _NFILE_ in CRT0DAT.ASM.

 The following program will open up to 64 files, write to them, close
 them, open the files again, and read from them:

 #include <stdio.h>
 #include <string.h>

 #define MAX_FILES  64
 #define MAX_BUFFER 128
 #define FILE_BASE  "MAX"
 #define FILE_EXT   ".TXT"
 #define TO_WRITE   "This is a bunch of text!"

 void main( void )
 {
     FILE *streams[MAX_FILES];
     char  buffer[MAX_BUFFER];
     int   i;
     int   max;
     int   cmp;

     /*  Open as many files as possible. */
     for( i = 0; i < MAX_FILES; i++ )
     {
         sprintf( buffer, FILE_BASE "%2.2d" FILE_EXT, i + 1 );
         streams[i] = fopen( buffer, "w" );
         if( streams[i] == NULL )
         {
             fprintf( stderr, "Open #%2.2d failed.\n", i + 1 );
             break;
         }
     }
     max = i;

     /*  Write to all open files. */
     for( i = 0; i < max; i++ )
         fputs( TO_WRITE, streams[i] );

     /*  Close all open files. */
     for( i = 0; i < max; i++ )
         fclose( streams[i] );

     /*  Open all of our files. */
     for( i = 0; i < max; i++ )
     {
         sprintf( buffer, FILE_BASE "%2.2d" FILE_EXT, i + 1 );
         streams[i] = fopen( buffer, "r" );
         if( streams[i] == NULL )
             fprintf( stderr, "Unable to re-open file #%2.2d\n", i + 1 );
     }

     /*  Read from all open files. */
     for( i = 0; i < max; i++ )
     {
         fgets( buffer, MAX_BUFFER, streams[i] );
         cmp = strcmp( buffer, TO_WRITE );
         if( cmp != 0 )
             fprintf( stderr, "Bad data in file #%2.2d\n", i + 1 );
     }

     /*  Close all open files. */
     for( i = 0; i < max; i++ )
         fclose( streams[i] );

     fputs( "All done!\n", stdout );
 }


 198. QuickC Internal Compiler Error: gencode.c, line 389

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 31-MAY-1989    ArticleIdent: Q43998

 Compiling the program below causes the Microsoft QuickC 2.00 compiler
 to produce the following error message, regardless of memory model or
 optimization level:

    bile.c(7) : fatal error C1001: Internal Compiler Error
            (compiler file 'gencode.c', line 389)
            Contact Microsoft Technical Support

 The program is as follows:

     /* bile.c -- causes ICE, gencode.c, line 389
      */
     char Image;

     void main()
     {
         Image = (char huge *)1;
     }

 The compiler will correctly generate a warning about the different
 levels of indirection on the same line as the one causing the ICE. The
 problem can be eliminated by properly declaring Image. Image should be
 declared as follows:

    char huge *Image;

 This mistake can be made easily if Image is the second of two
 variables in a declaration, as follows:

    char huge *foo, Image;

 This is a declaration of one huge pointer to character and one
 character variable, not two huge pointers to character. The
 declaration of two huge pointers to character is as follows:

    char huge *foo,
         huge *Image;

 Microsoft has confirmed this to be a problem in Version 2.00 We are
 researching this problem and will post new information as it becomes
 available.


 199. QuickC 2.00 "Rebuild All" Doesn't Necessarily Relink

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-MAY-1989    ArticleIdent: Q44003

 The "Rebuild All" item under the "Make" menu in the QuickC 2.00
 environment does not necessarily perform in the manner described in
 the "Microsoft QuickC Up and Running" manual. Page 36 of this manual
 states the following:

    When you choose the Rebuild All command from the Make menu, every
    .C file in the program list is compiled into a .OBJ file.  Then
    all of the .OBJ files are linked with .LIB files to create one
    .EXE file.

 With the Incremental link option on, the object files may not be
 relinked in all cases. Using the regular linker by disabling the
 Incremental link option will relink the object files as intended.

 The following program and sequence of steps will demonstrate the
 problem:

 #include <stdio.h>
 main()
     {
     printf("Hello.\n");
     }

 Create an additional subdirectory (e.g. LIB2) and copy SLIBCE.LIB into
 it. Run LIB on this copy and delete the printf module. Clear the LIB
 environment variable and enter QuickC, loading the above program.

 From the Options menu, set the LIB environment variable to the LIB2
 directory. Make sure that the Incremental Link option is selected.
 Compile the program. The linker produces the following error message,
 and no .EXE will be produced:

    Error L2029 : '_printf' : Unresolved external

 To witness the problem, change the LIB variable to the original QuickC
 2.00 LIB directory and Rebuild All. A good .EXE will be produced;
 execute it to be sure. Now, change the LIB back to the LIB2 directory
 and select Rebuild All. The dialog box will indicate that compilation
 and linking have taken place; however, no linker error will be
 generated. The program has not been fully relinked; even though the
 timestamp on the .EXE indicates that it has been updated, the printf
 code is still intact.

 The workarounds are to shell out to DOS and delete the .EXE file prior
 to performing a Rebuild All or to disable incremental linking prior to
 linking.

 This behavior will be dangerous if one set of libraries is initially
 linked and then the LIB variable is changed to point to C 5.10 or
 other libraries in which identically named functions have different
 definitions.


 200. Error L2025 from BASIC Calls to QuickC 2.00 Routines

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C B_QuickBAS
 Last Modified:  2-MAY-1989    ArticleIdent: Q44004

 Calling C routines in object modules compiled with Microsoft QuickC
 Version 2.00 from BASIC routines works correctly only when the BASIC
 modules are compiled with QuickBASIC Version 4.50. Using earlier
 versions of QuickBASIC or the BASIC Compiler 6.00 or 6.00b results in
 the following linker error message:

    L2025  'name' : symbol defined more than once

 Prior versions of QuickC can be linked successfully with the earlier
 versions of QuickBASIC or the BASIC Compiler 6.00 or 6.00b.

 In addition, when using graphics routines in C or BASIC mixed-language
 programs, the graphics calls must be from the QuickBASIC routines and
 use the QuickBASIC library. If graphics routines are called from
 QuickC 2.00, the linker returns the same error message as above. If
 the graphics routines are called from prior versions of the C run-time
 libraries, no error message is displayed; however, the results are
 unpredictable.

 If the QuickC 2.00 library includes the C Graphics or Pgchart library
 routines, then the QuickBASIC Version 4.50 calling program must be
 compiled without the /O option (using the BRUN45 library instead of
 BCOM45). Otherwise, you will get many "symbol defined more than once"
 errors at link time.

 Using the linker option /NOE (NO Extended function name/symbol
 dictionary search) will not prevent the L2025 error because the
 symbols are defined in both the QuickC 2.00 and BASIC libraries.


 201. C2097 Attempt to Initialize Short Address with Long Address

 Product Version(s): 1.01 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1989    ArticleIdent: Q44009

 When the example below is compiled in the medium memory model, the
 compiler returns the following error message:

    C2097  illegal initialization

 The following description of this error, which can be found on Page
 261 of the "Microsoft C Optimizing Compiler User's Guide" and on Page
 331 of the "Microsoft QuickC Programmer's Guide," is incomplete:

    An attempt was made to initialize a variable using a non-constant
    value

 Attempting to initialize a short address with a long address is
 another type of illegal initialization that can return this error.

 The example below demonstrates the problem when compiled in the medium
 memory model. The medium memory model is the only memory model
 available in Versions 1.00 and 1.01 of the QuickC environment. QuickC
 2.00 and the Microsoft C Optimizing Compiler support five memory
 models. QuickC 1.00 and 1.01 support four memory models (no huge) when
 compiling outside of the environment.

 To prevent the problem, compile with either /AS, /AL, or /AH (the
 small, large, or huge memory model, respectively). This ensures that
 the addresses for data are the same size as the addresses for code.
 Alternatively, make appropriate casts when initializing pointers and
 specify the far keyword on declarations as necessary.

 To compile (but not link) for small model with QuickC, use the
 following command line:

    qcl /AS /c test.c

 Or, with the Microsoft C Optimizing Compiler, use the following
 command line:

    cl /AS /c test.c

 The code example is as follows:

 /*  example  */

 int exit();

 typedef struct { void * data;
                } selection;

 selection menu[] = { { 0 },            /*  data  */
                      { exit }          /*  code  */
                    };


 202. Regular Expression Replacements in QuickC 2.00 Editor

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q44053

 Question:

 Can the regular expression replacement symbols be used in the "Change
 To:" field of the Change... option in the Search menu in QuickC 2.00?
 For example, could I use the regular expression "...." in the "search"
 field and replace it with '....', effectively replacing all strings of
 length four in double quotation marks with the same string in single
 quotation marks.

 Response:

 Regular expressions are limited to the "Find What:" field of the
 Change... option in the Search menu. In the example above, every
 occurrence of a string of four characters between double quotation
 marks in the text would be replaced with '....'.

 For a more complete discussion of regular expressions in QuickC 2.00,
 select the Change... option in the Search menu and press the F1 key
 for help.


 203. QuickC: _floodfill May Fail When Filling Color 0

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 18-MAY-1989    ArticleIdent: Q44054

 The graphics function _floodfill fails under any graphics mode with
 more than two colors when all of the following occur:

 1. A region enclosed by a border color is filled.

 2. A shape with the color of the border color is enclosed within that
    region.

 3. The color being _floodfilled is 0.

 When _floodfill encounters this enclosed shape, it slows down
 considerably. When it completes filling, the program hangs. Executing
 the following program demonstrates this problem:

    #include <graph.h>

    #define BORDER 15

    unsigned char mask[] = {255,1,1,1,1,1,1,1};

    void main (void)
     { _setvideomode (_VRES16COLOR);

       /* Draw the border. */
       _setcolor (BORDER);
       _ellipse (_GBORDER,10,10,630,340);

       _setfillmask ((char far *) mask);

       /* Remove drawing this interior shape and the program works. */
       _setpixel (323,84);

       /* This _floodfill is just for looks. */
       _setcolor (2);
       _floodfill (320,190,BORDER);

       _setcolor (0);

       /* This line will slow down and hang. */
       _floodfill (320,190,BORDER);
     }

 This problem is not related to the color currently mapped to color 0
 (black by default). If you must _floodfill black, remap another color
 to black and _floodfill that color. For example, to patch the above
 program, replace

    _setcolor (0);

 with the following:

    _remappalette (8,_BLACK);
    _setcolor (8);

 This also is a problem with Optimizing C Versions 5.00 and 5.10 when
 _floodfilling any color under the circumstances described above -- not
 just color 0.
 Microsoft is researching this problem and will post new information as
 it becomes available.


 204. _clearscreen Does Not Clear the Entire Screen in _ERESCOLOR

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 25-MAY-1989    ArticleIdent: Q44469

 Consider the following program:

    #include <graph.h>

    void main (void)
    {
            _setvideomoderows (_ERESCOLOR, 43);
            _rectangle (_GBORDER, 0, 0, 639, 349);
            _clearscreen (_GCLEARSCREEN);  /* not entirely successful */
    }

 When this program is executed on a computer that supports the
 _ERESCOLOR video mode with 43 lines of text, the largest rectangle
 possible is drawn on the screen. Next, the entire screen should be
 cleared by the _clearscreen function. But its not -- the bottom six
 lines of pixels are not cleared. This is incorrect behavior.

 To work around this problem, add the following two lines of code to
 the above program:

    _setcolor (0);
    _rectangle (_GFILLINTERIOR, 0, 344, 639, 349);

 This code will clear the bottom six lines of pixels.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.


 205. How to Debug Large QuickC 2.00 Program Inside the Environment

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q44160

 Question:

 I have a very large QuickC Version 2.00 program that is too big to
 debug in the QuickC 2.00 environment. How can I debug part of my
 program without including debug information for the whole application?

 Response:

 QuickC 2.00 does not give you the option to turn debug information on
 or off for single modules; however, there are ways to trick QuickC
 2.00 into compiling part of the application without debug information.

 By turning off the debug information, you can recompile some of the
 modules without debug information. When you are ready to run the
 application, turn debugging back on and recompile the changed modules.
 You must shell out to DOS at this point to delete the old executable
 file, which will force QuickC to relink before running. When you
 select RUN, QuickC will ask if you want to rebuild. If you select yes,
 all of the modules will be recompiled. If you select no, QuickC will
 link only the existing object files before executing the program.

 Note: To turn off debug information, go to the Options-Make menu and
 select the release flags. Do not try to turn off debugging information
 by selecting line numbers only in the compiler flags.


 206. Explanation of the _fontinfo Structure

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q44206

 Question:

 Which entries in the _fontinfo structure pertain to which fonts?
 Specifically, do 'ascent' and 'pixheight' pertain to vector fonts?
 Those two fields do not seem to change after the size of a vector font
 is changed.

 Response:

 All entries in the _fontinfo pertain to both font types. The two known
 values that are specific to each type are as follows:

    *.type      =>  If bit is set = vector font, clear = bitmap font
    *.pixwidth  =>  0 = proportional, others = character width in pixels

 For bitmapped fonts, the sizes are known; therefore, each font size is
 stored separately.

 For vector-mapped fonts, there is only one known size; therefore, only
 one size is stored in the font file. When you select a vector font
 with a specific size, the font routine will rescale the desired size
 proportionally to the known size. This is why all entries in _fontinfo
 structure are UNCHANGED (including the 'ascent' and 'pixheight'
 fields) every time the size of a vector-mapped font is changed.

 For example, setting the vector-mapped font size to either of the
 following will not have any effect on the _fontinfo values:

       'h100w200'
 or
       'h10w20'

 This means that the size of a vector-mapped font will be changed
 correctly, but you will not be able to tell to what size it was
 changed to by looking at the _fontinfo structure fields.

 This is currently a limitation of QuickC 2.00.

 Note: For an explanation of differences between 'ascent' and
 'pixheight,' please refer to Pages 654-655 in the book "Programming
 Windows" by Charles Petzold.



 207. Blink/Intensity Bit Not Restored by Environment in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 18-MAY-1989    ArticleIdent: Q44208

 When QuickC restores the output screen (e.g. after pressing F4), the
 palette's blink/intensity bit is not correctly restored when it is set
 to intensity. On an EGA, VGA, or MCGA display, this bit allows a
 palette of 16 background colors without blink capability, rather than
 a palette of eight background colors with blink capability.

 This bit is set through interrupt 0x10, function 0x10. The problem
 described can be demonstrated with the program below, by doing the
 following:

 1. Run the program below to completion. A red, nonblinking foreground
    is displayed on an intense white background. This is correct.

 2. Press any key to return to the integrated environment.

 3. Press F4 to view the output screen. This time, a dim background
    with a blinking foreground is displayed. This is not correct.

 For more information on this subject, refer to Pages 54-55 of the
 "Programmer's Guide to PC & PS/2 Video Systems" by Richard Wilton.

 Microsoft has confirmed this to be a problem in Version 2.00. We are
 researching this problem and will post new information as it becomes
 available.

 The program is as follows:

 /* blink.c - demonstrate usage of palette's blink/intensity bit */

 #include <graph.h>
 #include <dos.h>

 void main (void)
 {
   union REGS regs;

   _setvideomode (_TEXTC80);      /* This always sets blink on    */
   _clearscreen (_GCLEARSCREEN);

   regs.h.bl = 0;                 /* 0=intensity, 1=blink         */
   regs.x.ax = 0x1003;            /* Function 10h, subfunction 3  */
   int86 (0x10,&regs,&regs);      /* Turn intensity on, blink off */

   _settextcolor (12+16);         /* 12=red, 16=blink/intensity   */
   _setbkcolor (7L);              /* White                        */

   _outtext ("\nRed text on a bright white background\n");
 }


 208. Presentation Graphics Does Not Support 3-Dimensional Charts

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-MAY-1989    ArticleIdent: Q44260

 Microsoft QuickC Version 2.00 does not support three-dimensional
 charts with the Presentation Graphics package. The on-line help
 incorrectly states that the pie-chart Style 2 is a three-dimensional
 chart. The Feature Comparison data sheet available from the Microsoft
 Sales line, (800) 426-9400, prior to May 1989, also incorrectly states
 that the Presentation Graphics package supports three-dimensional
 charts.

 The reference to three-dimensional charts can be found on Page 149 of
 the "Microsoft Graphics Library Reference" manual. It can also be
 found by invoking on-line help on _pg_defaultchart and bringing up the
 description.

 When the following program is compiled, linked, and run, it is easy to
 see that both of the pie-chart styles are identical:

 #include <conio.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <string.h>
 #include <pgchart.h>

 #define COUNTRIES 5
 float far value[COUNTRIES] =    { 42.5,    14.3,    35.2,   21.3,  32.6    };
 char far *category[COUNTRIES] = { "USSR",  "France","USA",  "UK",  "Other" };
 short far explode[COUNTRIES] =  { 1,       1,       1,      0,     0       };

 main()
 {
    chartenv env;
    _setvideomode( _VRES16COLOR );               /* VGA graphics mode       */

    _pg_initchart();                             /* Initialize chart system */

    _pg_defaultchart( &env, _PG_PIECHART, 1 );   /* pie chart style 1       */
    strcpy( env.maintitle.title, "Widget Production" );
    _pg_chartpie( &env, category, value, explode, COUNTRIES );
    getch();

    _pg_defaultchart( &env, _PG_PIECHART, 2 );   /* pie chart style 2       */
    strcpy( env.maintitle.title, "Widget Production" );
    _pg_chartpie( &env, category, value, explode, COUNTRIES );
    getch();

    _setvideomode( _DEFAULTMODE );
 }


 209. Facts About MSHERC.COM; Why Hercules Support Must Be TSR

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 31-MAY-1989    ArticleIdent: Q44273

 MSHERC.COM is a TSR (Terminate and Stay Resident) graphics driver that
 is supplied with Microsoft QuickC, QuickBASIC, and the C Compiler. It
 provides high-resolution graphics capability (720 x 348, 2 colors) for
 the popular Hercules graphics adapter. MSHERC.COM was written in-house
 at Microsoft, and first shipped as QBHERC.COM with QuickBASIC. It is
 provided, in compiled form, with the above-mentioned packages, and may
 be distributed by programmers writing market applications with one of
 these languages.

 Four of the most common questions regarding MSHERC are as follows
 (this question is usually generated by one of the following three):

 1. Is the source code available? Under no circumstances. Releasing the
    source code for MSHERC would limit the development team's ability
    to change the application for increased efficiency at some time in
    the future (implementation change, with the user interface kept as
    it is).

 2. Why can't Hercules support be done with a BIOS call, like any other
    video support?

    The Hercules card is not part of the IBM standard. There is no BIOS
    support. The card is easily programmable, and the manuals that
    ship with a TRUE Hercules card explain in detail how to program for
    the card. Clone cards frequently do not provide this information.
    The MSHERC driver does the translation for the card, in a fashion
    that is transparent to the user.

 3. Can I build MSHERC into my program, so that I don't have to ship
    the driver with my program?

    No. The reason that this is a common question is that most
    individuals don't realize that the driver is an active TSR, and not
    just a sequence of initialization code for the Hercules Card. It
    would be possible to build this support into each of the routines
    in the graphics library, but it would involve quite an increase in
    the size of each routine, since every time that a routine did a
    BIOS call for graphic output, an alternate jump would have to be
    added to a routine that performed the same operation via the
    Hercules card. To build in this functionality would require the
    rewriting of many graphics functions. Although the run-time source
    to C 5.10 is available, this does not include any of the graphics
    routines.

 4. Can I use the System or spawn commands to call MSHERC from within
    my program, so that I don't have to load it independently?

    No. The C and QuickC compilers do memory initialization at start-up
    time. At this time, memory that has been allocated through DOS
    (such as a device driver or TSR program) is passed to the compiler.
    Going back to DOS via a System call and loading a TSR is a very
    risky proposition, because the compiler will have no knowledge of
    this operation. Possible consequences include memory fragmentation,
    memory overwrites, and hanging. Also, the hardware configuration
    is checked during start-up initialization. Therefore, after
    start-up has confirmed that no Hercules card is present, loading
    MSHERC.COM would not do any good.


 210. Problem Deleting a Line that Is a Breakpoint in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-MAY-1989    ArticleIdent: Q44287

 Consider the following sequence of events:

 1. You are debugging a program named FILE.C in the QuickC environment.

 2. A line is marked as a breakpoint (by pressing F9 or using the
    Debug.Breakpoint dialog box).

 3. That line is deleted (by pressing CTRL+Y for example).

 4. The program is rebuilt and re-executed (by pressing F5).

    At this point, the following pop-up is displayed:

       Cannot set breakpoint
              file.c:0

 To get past this point, you must remove this mysterious breakpoint
 through the dialog box selected with the Debug.Breakpoint menu option.
 Using this dialog box, remove all breakpoints with a line of zero. The
 program may then be executed successfully.

 To avoid this problem altogether, do not delete a line that is a
 breakpoint. Instead, toggle the breakpoint off by pressing F9 on the
 breakpoint prior to deleting that line.

 This problem is caused because when a breakpoint line is deleted, the
 associated breakpoint entry is not deleted. Rather, its line number is
 set to zero. There is no line zero that the debugger can set a
 breakpoint on; thus, the error pop-up occurs.



 211. QuickC: Unresolved _main in dos\crt0.asm

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q44329

 If you attempt to compile source code from the help window without
 copying it into the working window, you will get an unresolved
 external on _main in dos\crt0.asm. This error occurs because the
 compiler start-up code calls _main. The linker generates this error
 because there is no program (and hence no main function) in the
 working window. To correct this problem, make sure to copy the source
 FROM the help window TO the working window.


 212. QuickC tolower Macro Descriptions Contradictory

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 25-MAY-1989    ArticleIdent: Q44331

 The summary and description given for the tolower macro in the QuickC
 2.00 on-line help are contradictory.

 The summary text given is as follows:

     (tolower) lowercase equivalent of c only
               if c is an uppercase letter.
     (_tolower) lowercase equivalent of c

 The description text is as follows:

     The tolower macro converts c to lowercase if c represents an
     uppercase letter. Otherwise, c is unchanged. The _tolower macro
     is a version of tolower to be used only when c is known to be
     uppercase. The result of _tolower is undefined if c is not an
     uppercase letter.

 These descriptions imply different cases for the two macros tolower
 and _tolower. The summary indicates that tolower will only function on
 characters known to be uppercase; however, the description indicates
 the opposite. A more accurate summary is given in the "Microsoft C
 Run-Time Library Reference," which states the following:

     int tolower(c);     Converts c to lowercase if appropriate
     int _tolower(c);    Converts c to lowercase

 In other words, the description section in on-line help is correct;
 _tolower should only be used when c is KNOWN to be uppercase.


 213. sizeof() Returns 0 for Dereferenced Pointers to Arrays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 18-MAY-1989    ArticleIdent: Q44424

 The program below demonstrates a problem with the sizeof() keyword in
 the Microsoft QuickC Version 2.00 Compiler. When compiled at any
 warning level with any options, the program causes the following error
 to be generated on each line with the sizeof() expression:

    warning C4034: sizeof returns 0

 This problem occurs when the argument to sizeof() is a dereferenced
 pointer to an array of any type, regardless of whether or not it has
 been typedef'ed.

 The Microsoft C Version 5.10 and QuickC 1.01 compilers handle the
 sizeof() expression properly.

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.

 The following program demonstrates the problem:

 #include <stdio.h>

 typedef char        STRING80[81];

 STRING80            *pstr;
 int                 (*z)[10];
 int                 i;

 void main()
 {
   i = sizeof( *pstr );  /* Should be 81 */
   i = sizeof( *z );     /* Should be 20 */
 }

 Examination of the data generated by the sizeof() expression in such a
 case reveals that a value of 0 is, in fact, being used. The code
 executes but without the desired result.

 Because the sizeof() keyword is implemented by the compiler, rather
 than as a library function or at the preprocessor level, there is no
 way of replacing sizeof(). The workaround for the first sizeof()
 statement in the program above is to replace *pstr with STRING80 as
 follows:

    i = sizeof ( STRING80 );

 The workaround for the second case is to use a constant instead of
 calling sizeof().

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


 214. QuickC 2.00 Debugger Does Not Support Huge Pointers/Model

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-MAY-1989    ArticleIdent: Q44449

 The QuickC Version 2.00 debugger does not support the huge-memory
 model. It does not supply any information regarding huge pointers,
 even if the specified model is large, not huge.

 The debugger allows a watch to be placed on the pointer, but instead
 of supplying useful values, the following message appears in the debug
 window as soon as the variable is declared:

    image: <Debugger does not support huge model>

 This is intentional program design for the product.


 215. Regular Expressions in QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q44522

 Question:

 When using QuickC 2.00 and the regular-expression search parameters,
 there seems to be an inconsistency in the way they are handled when
 more than one regular expression is used in a search. For instance,
 suppose I have the following string in my source file:

    "VUTTVVUU"

 The string is found when I search using the following regular
 expression:

    "[TUV]*"

 If I search with the following regular expression, I would expect it
 to find the data between quoted strings, but it matches each
 individual character:

    [TUV]*

 How is this inconsistency explained?

 Response:

 The regular expressions work as described in the QuickC 2.00 on-line
 help. When more than one expression is used in a search, the results
 are unpredictable. The example above is one such inconsistency that
 occurs.

 Only one regular expression should be used per search. Regular
 expressions, within QuickC, were not meant to write complex search
 strings. If such functionality is desired, it is better to use another
 editor capable of such operations.


 216. More Information on Using _setfont in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | FYI
 Last Modified: 25-MAY-1989    ArticleIdent: Q44560

 Setfont is a run-time library routine included with the QuickC
 Version 2.00 graphics library for selecting the active font. The
 _outgtext function uses this font for succeeding output to the screen.
 The setfont function is very versatile and allows you to specify the
 font by name, number, or best-fit for a specified character size.

 Setfont brings the font (bit-map or vector) into far memory if the
 specified font exists or the best-fit attribute is given. If the font
 does not exist and best-fit is not given, the setfont function will
 fail and return (-1).

 If there is not enough far memory for setfont to load the specified
 font, setfont will return (-4). This is not documented in the graphics
 library reference manual for QuickC 2.00. To be on the safe side,
 always make sure the return value is (0) before continuing with the
 _outgtext.

 Note: The best-fit attribute does not check to see which font actually
 fits in memory; it is used only for selecting a font with specific
 character attributes.

 To use the setfont function, you must first change to a graphic screen
 and register the fonts on disk. The functions _setvideomode and
 _registerfonts, respectively, are provided for these procedures. After
 these have successfully completed, you can call setfont and outgtext
 as many times as you like. You should end the program by unregistering
 the fonts and returning to the default video mode.

 The following program prints "Hello World" to the screen using the
 script font with a height of 20 and a width of 10.

 #include <graph.h>

 void main(void)
 {
   _setvideomode(_ERES16COLOR);
   _registerfonts("d:\\qc2\\samples\\*.fon");

   if (_setfont("t'Script' h20 w10") == 0)
      _outgtext("Hello World");

   _unregisterfonts();
   _setvideomode(_DEFAULTMODE);
 }


 217. QuickC Incorrectly Complains Struct/Union Undefined

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 25-MAY-1989    ArticleIdent: Q44640

 In the example below the structure declaration compiles correctly;
 however, when a variable is defined using the defined type, QuickC
 2.00 incorrectly produces the following error:

    error C2079: 'this' uses undefined struct/union 'foo'

 Microsoft C Version 5.10 produces the correct error as follows:

    error C2035: enum/struct/union 'array' unknown size

 Program example
 ---------------

 struct foo
 {
      struct
      {
           char val;

      } array[];
 };

 struct foo this;

 void main(void)
 {

 }

 Microsoft has confirmed this to be a problem in Version 2.00 of the
 QuickC Compiler. We are researching this problem and will post new
 information as soon as it becomes available.



 218. QuickC 2.00 Has Problems with BREAK Key on TANDY 1000 TX

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 appnote
 Last Modified: 31-OCT-1989    ArticleIdent: Q44641

 A problem has been reported by individuals using QuickC 2.00
 regarding QuickC's behavior when the CTRL+C or CTRL+BREAK keystrokes
 are used, or when a CTRL+BREAK handler is used and/or coded.

 This problem only occurs in the QuickC environment, and does not
 affect the QCL command-line compiler. The symptoms of this problem are
 either that the machine is hung, or that the files on the disk are
 corrupted. Some of this corruption is limited to the filenames alone,
 while other instances result in corruption of whole files.

 All reports of this problem are solely against the TX model of the
 TANDY 1000 line. No other make of this line, nor any other IBM PC or
 compatible exhibits this behavior with QuickC 2.00.

 A patch which will correct this problem is now available from
 Product Support.  If you have a TANDY 1000TX and you are using
 QuickC version 2.00 you should avoid any use of the CTRL+BREAK
 and CTRL+C Keys until you have contacted Microsoft Support,
 received the patch, and installed it.  You can reach
 Support at (206) 454-2030.



 219. Compiling Incorrect or Incomplete C Syntax Can Hang Computer

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01
 Last Modified:  6-NOV-1989    ArticleIdent: Q48186

 QuickC Versions 2.00 and 2.01 hang the computer when given certain
 unusual and obscure configurations of invalid C syntax.

 For example, compiling the code shown below causes QuickC to hang. The
 code can be compiled both inside and outside of the environment with
 various switches turned on/off, and a hang results.

 To work around the problem, correct the invalid or incomplete syntax.
 If you are unsure of the location of the syntax errors, then use the
 QCL command-line compiler to locate the lines containing the specified
 errors.

 Make note of these error messages and then reboot your machine. You
 should correct these particular syntax errors.

 Note: This particular behavior of QuickC occurs only with very unusual
 and invalid C syntax.

 Microsoft has confirmed this to be a problem with QuickC Version 2.00
 and 2.01. We are researching this problem and will post new
 information as it becomes available.

 The following example demonstrates the problem. To correct this
 problem, place _dos_findfirst within a function, and correct the
 existing function definitions.

 The source code for prg.c is as follows:

 _dos_findfirst

 void wrflen(value)
 long value;
 {
      int buffer;

      buffer = value;

      for (;;) {
      }
 }

 int wrvlen(value)
 long value;
 {
      int buffer;

      while (1) {
      }
 }

 The QCL outputs the following text before hanging:

 Microsoft (R) Quick C Compiler Version 2.00
 Copyright (C) Microsoft Corp 1987-1989.  All rights reserved.

 prg.c (3) error C2054: expected '(' to follow '_dos_findfirst'
 prg.c (4) error C2085: 'wrflen': not in formal parameter list
 prg.c (4) error C2144: syntax error: missing ';' before type 'long'
 prg.c (8) error C2065: 'value': undefined


 220. QuickC 2.00 Debugger Does Not Debug Overlays

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-MAY-1989    ArticleIdent: Q44751

 The QuickC (QC) Version 2.00 debugger does not support the debugging
 of overlaid executables. If you need to debug a program with overlays,
 use the Microsoft CodeView debugger, Version 2.20 or later. If
 overlays are required because of memory constraints, you should not
 use the QC environment due to the large amount of memory which
 the QuickC enviroment consumes.


 221. "longjmp" Incorrectly Spelled "longjump" in QC Advisor Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 25-MAY-1989    ArticleIdent: Q44754

 The QuickC Version 2.00 on-line help system misspells the longjmp()
 function in one location as "longjump". Selecting the word from this
 location will not produce the help screen for longjmp().

 The misspelling occurs on the screen that can be reached with the
 following sequence of help selections:

     Help -> Contents -> Functions -> Miscellaneous

 The function name appears to be spelled correctly in every other case,
 and requests for help on "longjmp" while in the Edit Window function
 perform as expected.


 222. Long Arithmetic Incorrect in Certain Circumstances in QuickC

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 26-SEP-1989    ArticleIdent: Q44755

 QuickC Version 2.00 produces incorrect code for the subtraction and
 addition of long integers in some cases. One of the following set of
 conditions must be met for this problem to occur (these conditions
 apply to subtraction, but can be applied to the case of addition):

 1. The first set of conditions is as follows:

    a. The subtrahend is an element of an array of long ints.

    b. The array is defined locally.

    c. The subtrahend index is not a constant.

    d. The expected difference is less than zero.

 2. The second set of conditions is as follows:

    a. The subtrahend is being accessed through a pointer (either
       global or local).

    b. The expected difference is less than zero.

 To work around this problem, do one of the following:

 1. In the case of an array, make the array global, i.e., define it
    outside the body of any function.

 2. In the case of a pointer or array, eliminate the indirection in
    the expression.

 3. Disable pointer checking. This may be accomplished in the
    integrated environment with the following menu sequence:

        Options, Make, Compiler, Flag, Pointer Check

    When using QCL, do not use the /Zr switch.

 This problem occurs with code generated both in the integrated
 environment and by the command-line compiler QCL. The following
 program demonstrates this behavior:

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

 long int     *p;

 void main( void )
 {
     int      SubtrahendIndex = 0;
     long int array[1],
              diff;

     /* Bad case 1 */
     array[0] = 10L;
     diff = 5L - array[SubtrahendIndex];
     printf( "diff=%ld\n", diff );

     /* Bad case 2 */
     p = (long int *)malloc( sizeof( long int ) );
     *p = 10L;
     diff = 5L - *p;
     printf( "diff=%ld\n", diff );
 }

 The problem occurs when pointer check is enabled because the check is
 being performed in between accessing the MSW and LSW of the
 subtrahend, which clears the carry flag. The subsequent SBB
 instruction, which relies on the state of the carry flag to correctly
 borrow, is then inaccurate in the case of a negative result. Disabling
 pointer checking eliminates this problem.

 Microsoft has confirmed this to be a problem with QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.


 223. QC Advisor Says That fabs() Prototyped in STDLIB.H

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 19-SEP-1989    ArticleIdent: Q45093

 The QuickC Version 2.00 on-line help screen for the fabs() function
 incorrectly states that this function is prototyped in STDLIB.H. This
 is a documentation error. The fabs() function is actually prototyped
 in MATH.H. The abs() and labs() functions are prototyped in STDLIB.H.

 Attempts to use the fabs() function when MATH.H has not been included
 will produce inaccurate results at run time. At warning levels 2 and
 3, the compiler produces messages indicating that fabs() has not been
 prototyped and returns an integer by default; however, at warning
 levels 0 and 1 there is no indication that this problem exists.


 224. APPEND Command in DOS 4.x Incompatible with QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-SEP-1989    ArticleIdent: Q45218

 MS-DOS Versions 3.30 and 4.00 support an APPEND command that conflicts
 with the QuickC Version 2.00 environment. The DOS Version 4.00
 installation program may insert two APPEND commands in the
 AUTOEXEC.BAT file automatically. The same automatic insertion can
 occur for the DOS Box in OS/2.

 The presence of the APPEND command typically causes out-of-memory
 errors such as the following when compiling or linking inside the
 environment:

    ILINK returned -1

    R6005: Not enough memory on Exec

 Executing the command "APPEND ;" from the DOS command line may
 disable APPEND; if QuickC still produces errors, then removing APPEND
 entirely may be the only solution.  It will then be necessary to
 reboot for this change to take affect.


 225. Conflict between Global and Local Variables When Debugging

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 13-SEP-1989    ArticleIdent: Q45230

 The Microsoft QuickC Version 2.00 integrated debugger has a problem if
 a global variable in one source file has the same name as a local
 variable in another source file and that function has a printf()
 function call. The easiest workaround is to rename one of the
 variables. A problem description is given below.

 Microsoft has confirmed this to be a problem with the Microsoft QuickC
 Compiler Version 2.00. We are researching this problem and will post
 new information as it becomes available.

 The following two source files demonstrate this problem. To reproduce
 the problem, compile and link the two source files together. Step to
 the first executable line in the program and set a watch on the "foo"
 variable. Now step through the program and notice that the debugger
 does not show the correct value of foo after the assignment, although
 the sub() function will be called.

 Source File Example 1
 ---------------------

 /* main.c */
 extern void sub(void);
 int foo;
 main() {
     foo = 20;
     if (foo == 20) sub();
 }

 /* sub.c */
 #include <stdio.h>
 void sub(void) {
     int foo;
     printf("test");
 }

 To get around this problem, rename one of the offending variables,
 remove the printf() from the sub() function, or add another assignment
 to any global variable before the "foo = 20;" line in the main()
 function.

 Source File Example 2
 ---------------------

 /* main.c */
 extern void sub(void);
 int foo,temp;
 main() {
     temp = 20;      /* could also say "foo = 20;" */
     foo = 20;
     if (foo == 20) sub();
 }


 226. wait() and cwait() Prototyped in QuickC 2.00 Include Files

 Product Version(s): 2.00
 Operating System:   DOS
 Flags: ENDUSER | S_C
 Last Modified:  8-JUN-1989    ArticleIdent: Q45236

 Although wait() and cwait() are prototyped in the PROCESS.H include
 file from QuickC Version 2.00, neither of these functions is
 documented or found in the libraries.

 Both functions are for protected mode only and should not be in any of
 the QuickC libraries. They are in the include file for use with C
 Version 5.10. If a conflict arises due to prototypes, they
 can be removed.


 227. A Problem with Division Always Returning 1

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  8-JUN-1989    ArticleIdent: Q45349

 QuickC has demonstrated difficulty performing division under certain
 circumstances. When time optimization (/Ot or /Ox) is enabled,
 the program below outputs the following:

    quotient = 1

 The correct value is 5. No matter what the division operands are, the
 result is always 1 in this program. This behavior does not occur with
 longs or floats -- only with ints. The program that demonstrates this
 behavior is the following:

    #include <stdio.h>

    struct X
    { int i; } x = { 3 };

    void foo (struct X *);

    void main (void)
    {
      int denom, quotient;

      foo (&x);
      denom    = x.i;
      quotient = 15/denom;

      printf ("quotient = %d", quotient);
    }

    void foo (struct X *adr)
    {}

 To work around this problem with the program listed, disable time
 optimization. In the integrated environment, select
 Options.Make.Compiler Flags.Off. From the QCL command line, do not
 specify /Ot (or /Ox which implies /Ot).

 This problem can also be observed with the "C For Yourself" program
 GRAPHIC.C. The output of this program compresses when it is compiled
 with time optimization enabled.

 Microsoft has confirmed this to be a problem with QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.


 228. Casting Pointer to Char in the Watch Window Will Hang Machine

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified:  8-JUN-1989    ArticleIdent: Q45350

 If you are watching a pointer cast to a char in the Debug window in
 QuickC Version 2.00, the machine hangs. Other casts perform as
 expected. The example below demonstrates the problem.

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.

 In the QuickC environment, compile with debug options on. Next, set a
 Watch on a pointer and cast it to a char. For example, enter the
 expression "(char) intptr" (without the quotation marks). When this
 expression is entered, the mouse cursor disappears and QuickC no
 longer accepts any keyboard input.

 Code Example
 ------------

 char near * chptr;
 int near * intptr;
 float near * floatptr;

 void main (void)
 {
   chptr = (char near *) 1;
   intptr = (int near *) 1;
   floatptr = (float near *) 1;
   chptr = (char near *) 2;     /* put breakpoint here */

 }

 QuickC Versions 1.x do not exhibit this problem.


 229. Lack of Memory Can Cause pg_chartscatter to Fail

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-JUN-1989    ArticleIdent: Q45464

 The QuickC Version 2.00 presentation graphics functions
 _pg_chartscatter and _pg_chartscatterms fail if there is not enough
 memory in the far heap. These functions, like their cousins _pg_chart
 and _pg_chartms, depend on the availability of memory in the far heap
 for successful execution. The amount of memory needed for each
 function is directly proportional to the number of points being
 displayed. These functions return zero (0) if they execute
 successfully.

 To display more points with _pg_chartscatter and _pg_chartscatterms,
 try executing outside of the QuickC 2.00 environment. This method
 should free up enough memory for the functions to operate. Another way
 to free up memory is to turn debug information off.


 230. Only 20 Locals May Be Viewed Simultaneously

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-JUN-1989    ArticleIdent: Q45537

 QuickC Version 2.00 has the ability to view local variables
 automatically through the locals window. However, only 20 locals may
 be viewed at a time. If the function currently being debugged defines
 more than 20 local (automatic) variables, the 20 variables that are
 displayed are seemingly arbitrary.

 If you wish to view a local that is not one of the 20 displayed, the
 locals window may be edited directly. Delete a line that contains a
 variable that is not wanted, insert a new line, and type the name of
 the variable desired directly into the locals window.


 231. fcvt() Incorrectly Prototyped in QuickC Advisor

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-JUN-1989    ArticleIdent: Q45538

 In the QuickC 2.00 Advisor, the fcvt() function is incorrectly
 prototyped as the following:

    char *fcvt(double value, inc count, int *dec, int *sign);

 The correct prototype is as follows:

    char *fcvt(double value, int count, int *dec, int *sign);

 The second parameter is documented as being "inc count"; it should be
 "int count".


 232. Incorrect Prototypes for 'Window' Functions in QC Advisor

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-JUN-1989    ArticleIdent: Q45539

 A number of window functions that take the structure _wxycoord as a
 parameter are incorrectly prototyped in the QuickC Version 2.00
 Advisor. The Advisor states that the structure is to be passed; doing
 so generates the following error:

    test.c(11) : error C2115: 'argument' : incompatible types

 The functions actually take a pointer to the structure rather than the
 structure itself.

 The following are functions documented incorrectly in the Advisor as
 accepting structures rather than pointers to structures as parameters:

    _pie_wxy
    _rectangle_wxy
    _arc_wxy
    _ellipse_wxy
    _getimage_wxy
    _getviewcoord_wxy
    _imagesize_wxy


 233. Bad Library Environment Field Can Cause L1002

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUN-1989    ArticleIdent: Q45540

 Entering an invalid path in the "library" field of the
 Options.Environment selection in QuickC Version 2.00 can cause the
 error L1002 to be issued by the linker. For example, if the field is
 set to "D:/LIB" rather than "D:\LIB", the linker fails with the
 following message:

    LINK : fatal error L1002: LIB\ : unrecognized option name

 In such a situation, LINK is passed the contents of the "library"
 field with a backslash (\) and library name appended to it. The
 forward slash (/) is read by LINK as the beginning of an option that
 it doesn't understand.


 234. QuickC 2.00 Debugger Does Not Display Bit Fields.

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 30-AUG-1989    ArticleIdent: Q45555

 The debugger in QuickC Version 2.00 does not display bit-field
 structure members. An attempt to place a watch on a member of the
 following structure

 struct mystruct
    {
      unsigned level1: 4;      /* bits  0 - 3   */
      unsigned level2: 4;      /* bits  4 - 7   */
      unsigned level3: 4;      /* bits  8 - 11  */
      unsigned level4: 4;      /* bits 12 - 15  */
     } bitstruct;

 results in the following message appearing in the debug window:

    bitstruct.level1: <Cannot display>

 This is by design, and is expected behavior. QuickC Versions 1.00 and
 1.01, however, do display bit-field structure elements, as does CodeView.

 To workaround this to take the address of the structure, and then
 watch the memory contents at that address.


 235. Use _setfont to Specify Characteristics for Current Font

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickPascal
 Last Modified: 26-JUN-1989    ArticleIdent: Q45586

 The function _setfont is used to select the font that is to be
 currently active and to define its characteristics. Full
 documentation on specifying options for _setfont can be found on Pages
 266-267 of "C For Yourself."

 The function is prototyped as follows:

    short far _setfont(unsigned char *);

 The function's argument is a pointer to a character string. The string
 consists of letter codes that describe the desired font, using
 descriptors that specify the following:

    The name of the desired font                    (required)
    Whether a vector or raster font is desired      (optional)
    The desired height (in pixels)                  (optional)
    The desired width (in pixels)                   (optional)
    Whether a fixed-width or proportional
       font is desired                              (optional)
    Whether or not to allow the program to
       choose a "best fit" from the available
       fonts, if an exact match cannot be made      (optional)


 236. "DPATH" Utility Causes ILINK Error and R6005 Error

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 28-JUN-1989    ArticleIdent: Q45679

 The following errors:

    ILINK returned -1

 or

    R6005: not enough memory on Exec

 will occur when compiling or linking inside the QuickC 2.00/2.01
 environment if the following utilities are loaded into memory:

    DPATH or IBM File Facility

 Both of these utilities are similar to the APPEND command in DOS.

 The DPATH utility should not be confused with a "dpath" command. The
 dpath  command is used only in the OS/2 environment and works much the
 same way the "path" command does, except that dpath is used by an
 application to search for data files, whereas path is used by commands
 and utilities outside of applications.

 Only the OS/2 applications that are written to take advantage of dpath
 will use the data path specified.


 237. Making Your Own Key File with the MKKEY.EXE Program

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUN-1989    ArticleIdent: Q45653

 The following information is from the Version 2.00 "Microsoft QuickC
 Up And Running" manual, Page 31:

    The MKKEY program allows you to make your own key file. You must
    use three options: -c, -i, and -o. The first (-c) specifies the
    type of conversion: ASCII to binary (ab) or binary to ASCII (ba).
    The two others specify the input file (-i) and the output file
    (-o).

    To modify the default QC.KEY file, you must first convert it to an
    editable ASCII file:

       MKKEY -c ba -i QC.KEY -o MYEDITOR.TXT

    You may use any other editor (including QuickC's) to edit the file
    named MYEDITOR.TXT, which lists the keystrokes that perform certain
    actions. For example, you press CTRL+G to delete a character. The
    line in MYEDITOR.TXT looks like this:

       Del: CTRL+G

    You could change that command to any other keystroke (CTRL+D, say),
    as long as the key isn't already assigned to another function.
    Elsewhere in the file, CTRL+D is assigned to CharRight, so you'd
    have to delete or change that line if you wanted to use CTRL+D for
    the Del function.

    When you're satisfied with the new functions, you must convert the
    ASCII file to binary, so that it can be loaded into the QuickC editor:

       MKKEY -c ab -i MYEDITOR.TXT -o MYEDITOR.KEY

    Finally, to load the new key file, use the /k: option.

 The /k: option is used on the QuickC command line to specify a new
 .KEY file, as follows:

    QC /k:myeditor.key <filename>

 The "Up and Running" appendix lists the editor functions by name and
 shows their default assignments in the supplied .KEY files. Any of
 these may be remapped using the MKKEY utility. Menu options, which have
 key equivalents, may not be remapped (e.g. Exit).


 238. How to Reboot Your Machine within a QuickC 2.00 Application

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C H_MASM S_QuickASM
 Last Modified: 12-SEP-1989    ArticleIdent: Q45761

 Question:

 I'm writing a QuickC 2.00 application that needs to reboot itself
 without the user turning off the machine or issuing the CTRL+ALT+DEL
 command. Is this possible in QuickC 2.00?

 Response:

 Yes, it is. You can do a complete reboot without memory check using
 inline assembly. To reboot an 8086 family machine, you can insert the
 word "1234h" at memory location 0040:0072 and then perform a direct
 jump to address f000:fff0.

 The following function performs a reboot inside a QuickC 2.00 program:

 void reboot(void)
 {
   unsigned reboot_vector[] = {0xfff0, 0xf000};

   _asm {
       mov ax, 40h
       mov es, ax
       mov di, 72h
       mov es:[di], 1234h               ; move 1234h into special loc
       jmp dword ptr ds:reboot_vector   ; jump to the bios routine
       }
 }


 239. chdir() Description Incorrect in Manual and On-Line Help

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 26-JUN-1989    ArticleIdent: Q45903

 The description of the chdir() function provided with the Microsoft
 QuickC Compiler Version 2.00 is incorrect in the "Run-Time Library
 Reference" manual on Page 156 and in the QuickC Advisor (on-line
 help). In both cases the example call in the description section
 should read as follows:

    chdir("c:\\temp");

 The sample call in the description section of the on-line help reads
 as follows:

    chdir("c:\temp")

 It needs an additional backslash "\". To see this error, use the
 Help.Index menu selection, then choose the chdir() function, and
 change to the description section.

 The sample call in the manual reads as follows:

    chdir(c:\temp);

 This description needs another backslash (\) and quotes around the
 directory.


 240. How to Search Multiple Files in QuickC Advisor

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 27-JUN-1989    ArticleIdent: Q45981

 You can search through the QuickC Advisor (on-line help) for a
 specific string, even when it is not listed in the "Help.Contents"
 screen.

 The following example demonstrates how to search on the string "DOS"
 to find information on DOS access routines:

 1. Load QuickC Version 2.00. Select "Options.Display."

 2. In the right column of the dialog box you, find "Search Multiple
    Help Topics". Set this option and press ENTER.

 3. Select "Help.Contents". (Notice that there is no item for DOS
    access routines.) Select "Search.Find" and enter the string "DOS"
    in the dialog box at the "Find What:" prompt.

 4. The QuickC Advisor searches the "Help.Contents" screen for a
    matching item. In this example, there is no matching item, so a
    dialog box pops up and says "Search string not found Continue
    searching topics?" Answer "Yes."

 5. When it finds a match, the Advisor stops searching and displays a
    blinking cursor and highlight on the requested string. In this
    example, the string "DOS" is highlighted in the line "System Calls
    - DOS". Press F1 or ENTER to see a screen listing all the DOS
    System calls. (Press F3 to see the next match.)

 6. Pick a function to examine, for example, "_dos_getdrive". Place the
    cursor on it and press F1. You should see the "Help.Index.Summary"
    screen for the function.

 Once you see the Summary, you can choose Details for additional
 information or select Example for a complete, running example program
 that you can "Edit.Copy" and "Edit.Paste" into your QuickC edit
 screen. "Edit.Copy" and "Edit.Paste" are demonstrated in the QuickC
 Tutorial (LEARN.EXE) in the "Getting Around in QuickC, Managing
 Windows," in the Notepad Window example.

 You can also use "Search.Find" when the "Help.Index" menu is on the
 screen.


 241. C2018: Unknown Characters During Compile

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q46016

 Problem:

 When I copied an example from the QuickC Advisor (on-line help) and
 tried to compile it, I received errors with one of the following
 messages:

    volume.c(2) : error C2018 : unknown character '0xc4'
 or
    volume.c(1) : error C2018 : unknown character '0x11'

 Response:

 It is possible to actually copy the Advisor header along with the
 sample program. The example screens have a list of help buttons, e.g.
 <Contents> or <Index>, separated from the sample program by a line
 consisting of the ASCII extended character '0xc4'. If you mistakenly
 copy either of these two lines from the help screen, the compiler
 shows the error C2018.

 To prevent this problem, delete the Advisor header lines from your
 source file.


 242. Problem with QuickC Inline Assembler INT Call and Typedefs

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM buglist2.00
 Last Modified: 27-JUN-1989    ArticleIdent: Q46129

 When compiled with QuickC Version 2.00, the code below compiles and
 gives the following message for the line containing the initialization
 of bar:

    error C2064 : term does not evaluate to function

 Removing the parentheses from the 0 in the initialization causes the
 following message:

    error C2143 : missing ')' before 'constant'

 Inline assembler code must contain an interrupt call (INT) for this
 error to occur. Using a simple type cast before the typedef'ed type
 cast solves the problem. In the following example, reverse the order
 of the initializations for bar and fad to put the simple typecast
 first.

 Code Example
 ------------

 typedef unsigned short far *FOO;

 FOO   bar;
 float fad;

     void main( void )
     {
         _asm { int 11h }

         bar = ((FOO) (0));   /* reversing this line with the next */
         fad = (float)3.4;    /* prevents the problem              */
     }

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.


 243. Tecmar VGA Does Not Work in 43-Line Mode with QC2.00/QB4.50

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | B_QuickBas
 Last Modified: 27-JUN-1989    ArticleIdent: Q46133

 The Tecmar VGA graphics card interacts incorrectly with both the
 QuickC Version 2.00 and QuickBasic Version 4.50 integrated
 environments. The screen comes up in 43-line mode, but it truncates
 the last seven lines of the screen.

 This has been duplicated at Microsoft and verified as a problem with
 both the Version 1.08 and Version 1.09 Tecmar ROMs. The only
 workaround is to use 25-line mode, which works correctly.


 244. QuickC Does Not Always Deallocate Memory Given to Video Buffer

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm
 Last Modified: 18-SEP-1989    ArticleIdent: Q46217

 When a graphics mode program is run from within the QuickC
 environment, screen swapping is used as the method of screen exchange.
 Thus, a buffer is dynamically allocated for holding the contents of
 the graphics-mode output screen. If the video mode is not reset to a
 text mode at the end of the program [i.e.,
 _setvideomode(_DEFAULTMODE);],  this buffer will not be deallocated
 properly, and the available memory will be decreased accordingly. A
 program that is constructed in this manner will eventually fail due to
 lack of memory, either at start-up or in the body of the code, when an
 attempt is made to allocate memory for use by the program.

 The following program demonstrates the problem. If the
 _setvideomode(_DEFAULTMODE); line is uncommented at the end of the
 program, it will run properly inside of the QuickC environment an
 unlimited number of times. However, if the program is allowed to
 terminate without resetting the video mode, it will fail the second,
 third, or fourth try, depending upon the initial amount of free memory
 in the system. This program will run properly from a DOS prompt any
 number of times. Another solution is simply to shell out of QuickC and
 reset the mode to a text mode. The program will then run one more
 time. However, the best solution is to change the program.

 Sample Program
 --------------

 #include <stddef.h>
 #include <malloc.h>
 #include <process.h>
 #include <graph.h>
 #include <conio.h>

 void main (void)
  { long size;
    char huge *image;

    /* Put the display in a EGA mode and allocate a buffer. */
    if (_setvideomode(_ERESCOLOR)==0)
        { _outtext ("Video mode not supported!\n");
          exit (0);
        }

    /* In _VRES16COLOR, size is 153604. */
    size = _imagesize(0,0,639,349);

    if ( (image=(char huge *)halloc(size,1)) == NULL)
         {
          _outtext ("Not enough memory for buffer!\n");
          exit (1);
        }
    /* Draw a couple of shapes and capture the screen. */
    _ellipse (_GBORDER,0,0,639,349);
    _rectangle (_GBORDER,0,0,639,349);
    _getimage (0,0,639,349,image);

    /* Clear the screen and redraw the image. */
    _clearscreen (_GCLEARSCREEN);
    _putimage (0,0,image,_GOR);
    getch();
    hfree ((char huge *)image);       /* carefully free the image buffer */
    /* _setvideomode (_DEFAULTMODE); */
    /* uncomment the line above, and the program works every time */
 }


 245. _registerfonts, _setfont Return Values Incorrect in Manual

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 30-AUG-1989    ArticleIdent: Q46382

 The return values for _registerfonts() and _setfont() are incorrect on
 Page 325 of the "C for Yourself" manual that comes with Microsoft
 QuickC Version 2.00. These functions are described as returning void;
 however, the return values as specified in the "Microsoft QuickC
 Graphics Library Reference" manual are signed short integers.

 The following _registerfonts() function return values have the
 following meanings:

    Return
    Value    Meaning
    ------   -------

    > 0      If positive, the number of fonts registered
     -1      No such file or directory
     -2      One or more of the .FON files was not a valid,
             binary .FON file
     -3      One or more of the .FON files is damaged

 The _setfont() function returns the following:

      0      If successful
     -1      Font wasn't registered
     -4      Not enough memory available for the font


 246. Example Program RECORD2.C Is Incorrect

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 17-JUL-1989    ArticleIdent: Q46384

 The QuickC example program RECORD2.C modifies memory pointed to by an
 uninitialized pointer (recpos). RECORD2.C is the example program in
 on-line help for the functions fgetpos and fsetpos.

 If this program is executed with pointer check enabled, execution may
 terminate with the following diagnostic displayed:

    run-time error R6013
    - illegal far pointer use

 If RECORD2.C is executed without pointer check enabled, the system may
 crash, or it may appear to execute successfully.

 To correct this problem add an additional header file, as
 follows:

    #include <malloc.h>

 Also, replace the line

    fpos_t *recpos;

 with the following:

    fpos_t *recpos = malloc(sizeof(fpos_t));


 247. Unrecognized Switch /Z1 Is Caused by Wrong Linker

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm
 Last Modified: 18-AUG-1989    ArticleIdent: Q46807

 Question:

 Immediately after setting up QuickC Version 2.00, an attempt to
 compile a file results in the error message "unrecognized switch Z1".
 The manual does not document this switch, and in addition, a /Z1
 switch is not being used in this instance. How can the compiler be
 made to finish compilation?

 Response:

 This is a simple LINK version problem. The "Z1" switch is unrecognized
 by LINK 3.05, and the error is returned directly to the screen (over
 the top of the program text). Check to make sure that the proper
 version of the linker (4.06) is being found and used.


 248. "QC Is Already Running" Message Appears

 Product Version(s): 2.50 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified:  9-NOV-1990    ArticleIdent: Q66432

 Question:

 When I invoke the QuickC integrated environment, a dialog box comes up
 with the following message:

    QC is already running
            Exit?

 The online help states that this message indicates another instance of
 QuickC running on my system. However, I am sure that I do not have
 another instance of QuickC running. I have rebooted and the message
 still appears. How can I eliminate this dialog box?

 Response:

 This message is caused by the presence of the file QC.LCK, which is
 created when the QuickC environment is invoked. If you shell out to
 DOS during a QuickC session by choosing DOS Shell from the File menu,
 and then attempt to start another QuickC session by typing "qc" at the
 DOS prompt, you will receive this message. The file QC.LCK is
 automatically deleted when you exit the QuickC environment.

 However, if your system has crashed for some reason during a QuickC
 editing session, or during the execution of a program from within the
 QuickC environment, the file is not deleted, and when you reboot and
 attempt to start QuickC, the presence of QC.LCK causes this message
 box to appear.

 The solution to this problem is to delete the QC.LCK file; it is
 placed in the BIN subdirectory.


 249. How to Change the Size of a Presentation Graphics Chart

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm
 Last Modified: 18-AUG-1989    ArticleIdent: Q47002

 Question:

 How can the size of a chart be changed so that you can use part of the
 screen to output explanatory text?

 Response:

 This capability is built into the charting environment. The chartenv
 structure is defined as follows:

            typedef struct {
              short          charttype;
                                 /* _PG_BAR, _PG_COLUMN, _PG_LINE, etc.*/
              short          chartstyle;
                                 /* style for selected chart type      */
              windowtype     chartwindow;
                                 /* SIZE OF WINDOW FOR CHART!!!!!      */
              windowtype     datawindow;
                                 /* size of window for chart data      */
              titletype      maintitle; /* main chart title            */
              titletype      subtitle;  /* chart sub-title             */
              axistype       xaxis;
                                 /* structure for customizing x-axis   */
              axistype       yaxis;
                                 /* structure for customizing y-axis   */
              } chartenv;

 The size can be changed by modifying the elements of the "chartwindow"
 element of the "chartenv" structure. The "chartwindow" element is of
 "windowtype", which is defined as follows:

             typedef struct {
                short  x1;        /* left edge of window in pixels     */
                short  y1;        /* top edge of window in pixels      */
                short  x2;        /* right edge of window in pixels    */
                short  y2;        /* bottom edge of window in pixels   */
                short  border;    /* TRUE=border, FALSE=no border      */
                short  background;/* palette color for window bkground */
                short  borderstyle; /* style bytes for window border   */
                short  bordercolor; /* palette color for window border */
                } windowtype;

 Therefore, if the program has defined a variable "env" of "chartenv"
 type, the chart can be sized by changing env.chartwindow.x1,
 env.chartwindow.y1, env.chartwindow.x2, and env.chartwindow.y2. The
 following program demonstrates making these changes to a simple bar
 chart:

 /*-------------------------------------------------------------------*/
 /* MINIBAR.C: This program demonstrates sizing the entire chart so   */
 /* that it will fit in the upper-left quarter of the screen, leaving */
 /* the remainder of the screen available for other uses. The chart   */
 /* is a simple default bar chart, but the principle is the same,     */
 /* regardless of chart type.                                         */

 #include <conio.h>
 #include <string.h>
 #include <graph.h>                 /* required include files */
 #include <pgchart.h>

 #define MONTHS 12

 typedef enum {FALSE, TRUE} boolean;

 float far value [MONTHS] =          /*value (series) data array */
 {
  (float)1.00, (float)2.00, (float)3.00, (float)4.00,
  (float)5.00, (float)6.00,(float)7.00, (float)8.00,
  (float)9.00, (float)10.00, (float)11.00, (float)12.00
   };

 char far *category[MONTHS] =         /* category data array */
   {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   "Jly", "Aug", "Sep", "Oct","Nov", "Dec"
   };

 main()

 {
 chartenv env;                     /* define chart environment variable */

 _setvideomode(_ERESCOLOR);        /* set to graphics mode */

 /* initialize chart library and a default bar chart */
 _pg_initchart();

 _pg_defaultchart(&env, _PG_BARCHART, _PG_PLAINBARS);

 /* set the chart size to the upper left quarter of the screen   */

 env.chartwindow.x1 = 0;
 env.chartwindow.y1 = 0;
 env.chartwindow.x2 = 320;
 env.chartwindow.y2 = 175;

 if(_pg_chart (&env,category,value, MONTHS)) /* call to charting routine*/
         {_setvideomode(_DEFAULTMODE);       /* error trap...*/
          _outtext("error, can't draw chart");
          }
      else
         {
          getch();                          /* wait for a keystroke */
          }
         _setvideomode(_DEFAULTMODE);      /* reset the video mode  */

          return(0);
          }


 250. Overlaying Charts and Displaying Multiple Charts on the Screen

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm
 Last Modified: 18-AUG-1989    ArticleIdent: Q47004

 It is not possible to overlay charts of the same size, as the charting
 routines clear the current viewport before drawing a chart. However,
 it is possible to display a small chart on top of a larger one, or to
 display charts side-by-side on the screen. The following programs
 demonstrate the steps necessary to size charts and display more than
 one chart at a time. PROG1.C overlays two small charts on top of a
 full-screen bar chart. PROG2.C displays four charts, one in each
 corner of the screen.

 The same technique can be used to place a chart onto an existing
 screen. Define the coordinates for the area in which you wish the
 chart to appear, and assign these coordinates to the "chartwindow"
 structure of the charting environment. Only this area is cleared when
 the chart is drawn.

 /* PROG1.C  ---------------------------------------------------------*/
 /* This program demonstrates overlaying charts. The initial chart    */
 /* drawn is a simple bar chart, which uses the entire screen. The    */
 /* second chart drawn is a column chart, which is displayed in a     */
 /* a viewport (x1=400, y1=50, x2=550, y2=175). This is displayed     */
 /* overlayed on the original bar chart. The third chart drawn is     */
 /* a pie chart, which is also drawn in a viewport (x1=350, y1=300,   */
 /* x2=525, y2=420), overlayed on the original barchart.              */

 #include <conio.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <string.h>
 #include <pgchart.h>

 #define COUNTRIES 5
 float far value[COUNTRIES] =    { 42.5, 14.3, 35.2, 21.3, 32.6    };
 char far *category[COUNTRIES] = { "A","B","C","D","E" };
 short far explode[COUNTRIES] =  { 0,1,0,1,0};

 void main(void)
 {
     chartenv env;                       /* define chart environment */

     _setvideomode(_VRES16COLOR);        /* set video mode...         */

     _pg_initchart();                    /* Initialize chart system    */

     /* Single-series bar chart. (full-screen) */
     _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
     strcpy( env.maintitle.title, "Widget Production" );
     _pg_chart( &env, category, value, COUNTRIES );

     /* Single-series column chart. (viewport at upper right) */
     _pg_defaultchart(&env, _PG_COLUMNCHART, _PG_PLAINBARS);
     strcpy( env.maintitle.title, "Widget Production" );
     env.chartwindow.x1 = 400;
     env.chartwindow.y1 = 50;
     env.chartwindow.x2 = 550;
     env.chartwindow.y2 = 175;

     _pg_chart( &env, category, value, COUNTRIES );

     /* Pie chart. (viewport at lower right) */
     _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );
     strcpy( env.maintitle.title, "Widget Production" );
     env.chartwindow.x1 = 350;
     env.chartwindow.y1 = 300;
     env.chartwindow.x2 = 525;
     env.chartwindow.y2 = 420;

     _pg_chartpie( &env, category, value, explode, COUNTRIES );
     getch();

     _setvideomode(_DEFAULTMODE);
 }

 /* PROG2.C  ---------------------------------------------------------*/
 /* This program demonstrates placing charts side-by-side on the      */
 /* screen. It displays four different charts, each taking up one     */
 /* quarter of the screen.                                            */

 #include <conio.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <string.h>
 #include <pgchart.h>

 #define COUNTRIES 5
 float far value[COUNTRIES] =    { 42.5, 14.3, 35.2, 21.3, 32.6    };
 float far axis2[COUNTRIES] =    { 1.0, 2.0, 3.0, 4.0, 5.0};
 char far *category[COUNTRIES] = { "A","B","C","D","E" };
 short far explode[COUNTRIES] =  { 0,1,0,1,0};

 void main(void)
 {
     chartenv env;                       /* define chart environment */

     _setvideomode(_ERESCOLOR);        /* set video mode...         */

     _pg_initchart();                    /* Initialize chart system    */

     /* Single-series bar chart. (viewport at upper left) */
     _pg_defaultchart( &env, _PG_BARCHART, _PG_PLAINBARS );
     strcpy( env.maintitle.title, "Widget Production" );
     env.chartwindow.x1 = 0;
     env.chartwindow.y1 = 0;
     env.chartwindow.x2 = 320;
     env.chartwindow.y2 = 175;

     _pg_chart( &env, category, value, COUNTRIES );

     /* Single-series column chart. (viewport at upper right) */
     _pg_defaultchart(&env, _PG_COLUMNCHART, _PG_PLAINBARS);
     strcpy( env.maintitle.title, "Widget Production" );
     env.chartwindow.x1 = 320;
     env.chartwindow.y1 = 0;
     env.chartwindow.x2 = 639;
     env.chartwindow.y2 = 175;

     _pg_chart( &env, category, value, COUNTRIES );

     /* Pie chart. (viewport at lower left) */
     _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );
     strcpy( env.maintitle.title, "Widget Production" );
     env.chartwindow.x1 = 0;
     env.chartwindow.y1 = 175;
     env.chartwindow.x2 = 320;
     env.chartwindow.y2 = 349;

     _pg_chartpie( &env, category, value, explode, COUNTRIES );

     /* Scatter chart. (viewport at lower right)   */
     _pg_defaultchart(&env, _PG_SCATTERCHART, _PG_POINTONLY);
     env.chartwindow.x1 = 320;
     env.chartwindow.y1 = 175;
     env.chartwindow.x2 = 639;
     env.chartwindow.y2 = 349;
     _pg_chartscatter(&env, (float far *)axis2, (float far *)value, 5);

     getch();

     _setvideomode(_DEFAULTMODE);
 }


 251. Presentation Graphics Charting Function: Error Codes

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JUL-1989    ArticleIdent: Q47018

 The following information is taken from the Presentation Graphics
 header file, PGCHART.H.

 Listed below are the error codes returned by the Presentation Graphics
 charting functions, which include the following:

    _pg_chart                 _pg_chartms
    _pg_chartscatter          _pg_chartscatterms
    _pg_chartpie

 The error codes are as follows. Error numbers greater than 100 will
 terminate the charting routine, others will cause default values to be
 used.

 Manifest Constant      Value      Definition
 -----------------      -----      -----------

 _PG_NOTINITIALIZED     102        Charting library not initialized by
                                   _pg_initchart and _pg_defaultchart
 _PG_BADSCREENMODE      103        Screen not set to graphics mode
 _PG_BADCHARTSTYLE       04        Invalid chart style
 _PG_BADCHARTTYPE       104        Chart type invalid
 _PG_BADLEGENDWINDOW    105        Invalid legend window specified
 _PG_BADCHARTWINDOW      07        x1=x2 or y1=y2 in chart window spec
 _PG_BADDATAWINDOW      107        If the chart window is too small
 _PG_NOMEMORY           108        Not enough memory for data arrays
 _PG_BADLOGBASE          05        Log base <= 0
 _PG_BADSCALEFACTOR      06        Scale factor = 0
 _PG_TOOSMALLN          109        Number of data points <= 0
 _PG_TOOFEWSERIES       110        Number of series <= 0


 252. Don't Use #line While Debugging in QuickC or Using CodeView

 Product Version(s): 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_CodeView
 Last Modified: 11-OCT-1989    ArticleIdent: Q47020

 Do not use the #line directive when using the debug facility under
 QuickC or while using CodeView.

 The #line directive tells the preprocessor to change the compiler's
 internally stored line number and filename to a given line number and
 filename. The compiler uses the line number and filename to refer to
 errors that it finds during compilation. The line number normally
 refers to the current input line, and the filename refers to the
 current input file. The line number is incremented after each line is
 processed.

 If you change the line number, the compiler ignores the previous
 values and continues processing with the new values. Therefore, if you
 debug or use CodeView, the trace does not match up to your source
 code.


 253. C2065: '_asm': Undefined

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  7-NOV-1990    ArticleIdent: Q47027

 The following error code is generated when compiling in-line assembly
 code in QuickC Version 2.00 if the Quick environment's compiler
 option is set for ANSI Compatibility instead of MS Extensions:

    C2065: '_asm': undefined

 Any code following the "_asm" keyword also generates syntax error
 messages.

 To set the required compiler option, use the following procedure:

 1. Choose Options.Make.

 2. Within Customize Build Flags, choose Compiler Flags.

 3. Within C Language, choose MS Extensions.

 /Ze, Microsoft Extensions, is the default for the command line compiler,
 QCL. This can create a situation where compiling with QCL will not
 issue any complaints about _asm keywords, but compiling within the
 QuickC environment will view _asm as undefined (if ANSI option is
 specified instead of MS Extensions).

 The following program works as expected when compiled and linked
 at the command line with default options, for example:

 qcl testasm.c

 /* TESTASM.C */

 void main (void)
 {
   _asm {  mov ax, 5  }
 }



 254. QC 2.00: Watch Values on Float Pointers Show char String

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00
 Last Modified: 26-JUL-1989    ArticleIdent: Q47035

 QuickC Version 2.00 does not display float pointers correctly in the
 Watch Value window. Float pointers display an ASCII character string
 of the memory that it points to, until a null character is reached.

 Use the following method as a workaround:

 For a float pointer, declared as

    float *fl;

 display the pointer in the Watch Value window as

    &*fl : 0xSEG:0xOFF         <---- displays correctly

 which essentially says "the address of what fl points to,"
 rather than the following

    fl   : "<garbage>"         <---- displays char string

 which displays the ASCII string of what fl points to.

 The following Watch Value displays the first byte that fl points to as
 an ASCII character before program execution begins, but displays the
 correct results after initialization:

    *fl  :

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.

 Example
 -------

     float *fl

     fl = (float *) malloc (sizeof(float));
     *fl = 3.5 ;

 A Watch Value set to fl displays the following:

     fl : "<garbage>"

 The "garbage" is an ASCII character string of the memory that fl
 points to. The string continues until a null character is encountered.
 The float pointer Watch Value displays a string even before program
 execution, when other watch values display <Unknown Identifier>.


 255. Scaletitle Does Not Display Category Axis

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-JUL-1989    ArticleIdent: Q47159

 The presentation graphics variable "scaletitle" does not display
 labels on axes with nonvalue data. Scaletitle is part of the chart
 variable "env". As documented on Page 80 of the "Microsoft QuickC
 Graphics Library Reference," scaletitle works correctly only with
 value data.

 To modify the scaletitle variable, you must copy a string into the
 environment as depicted in the following source line:

    strcpy(env.xaxis.scaletitle.title,"Supply vs. Demand");

 Scaletitle is of type "titletype", which has the following structure
 definition:

 typedef struct
 {
   char    title[_PG_TITLELEN];     /* Title text */
   short   titlecolor;              /* Palette color for the title */
   short   justify;                 /* _PG_LEFT, _PG_CENTERAL
                                       or _PG_RIGHT */
 } titletype;

 To unconditionally display axis titles, the variable "axistitle"
 should be used instead. The chart functions display these axis titles
 whether the axis is of numeric value type or string category type.



 256. Cannot Access LINK.EXE: Retry Does Not Retry Another Floppy

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm ILINK buglist2.00 buglist2.01
 Last Modified: 26-JAN-1990    ArticleIdent: Q47167

 Problem:

 When I am compiling and linking from floppy drives, there are times
 when QuickC does not find the linker (LINK or ILINK). When this
 happens, I get an error with the option to RETRY. If I then switch
 floppies, placing the proper version of the linker in the drive, the
 error does not go away.

 Response:

 Microsoft has confirmed this to be a problem with QuickC Version 2.00
 and with QuickAssembler Version 2.01. We are researching this problem
 and will post new information as it becomes available.

 There are two ways, however, that you can work around this
 problem. Your first option is to wait until the error appears, choose
 CANCEL, insert the proper floppy disk, and then choose BUILD PROGRAM
 from the MAKE menu. Because the .OBJ file is up-to-date, QuickC will
 not try to recompile, but will go directly to the link stage. With the
 new disk in the drive, QuickC will find the linker without a problem.

 To avoid the error completely, compile and link in two stages. This
 means selecting the MAKE menu and then the COMPILE FILE option. After
 the file compiles without errors, place the linker floppy disk in the
 proper drive. Next, choose the BUILD PROGRAM option from the MAKE
 menu. This is similar to the above procedure but will not generate
 the error message because the linker is not searched for until the
 BUILD PROGRAM option is selected.


 257. QuickC Does Not Support Alternate Math Library

 Product Version(s): 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# MS01691
 Last Modified: 10-OCT-1989    ArticleIdent: Q47194

 Neither the environment nor the command line in Microsoft QuickC
 support an alternate math package for floating point operations.
 However, both the emulator and coprocessor math packages are
 supported.


 258. Scaling Values for PG Charts Do Not Work Correctly

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01
 Last Modified: 10-OCT-1989    ArticleIdent: Q47235

 There is a problem with the scaling routines that are part of the
 QuickC 2.00 Presentation Graphics library. The "scalefactor" structure
 member of the axistype structure is not calculated correctly. The
 program included below demonstrates the problem. It draws a default
 bar chart, which displays with no problems. However, when a
 scalefactor of (first) 100, and (second) 1000 is defined, obvious
 difficulties arise. Some values are calculated incorrectly, and other
 values disappear from the graph altogether. The only changes that are
 made to the default charting environment deal with the scaling factor:

 1. The addition of a scaling factor other than 0.

 2. Resetting the maximum value for the x-axis.

 3. Resetting the tic-interval for the x-axis.

 When the scalefactor is set to a small value (in the 2.00 - 50.00
 range) it seems to be ignored altogether. Microsoft has confirmed that
 this is a problem with the QuickC 2.00 and 2.01 Presentation Graphics
 library. We are researching this problem and will post new information
 as it becomes available. At present, there is no workaround for the
 problem.

 The following program demonstrates the problem:
 /*----------------------------------------------------------------*/
 /* This routine draws a simple bar chart (plain bar style) to     */
 /* demonstrate a problem with the "scalefactor" setting           */
 /* which is defined in the "axistype" structure in PGCHART.H.     */
 /* The program defines and draws the chart three times:           */
 /*   1. with no scaling factor set.                               */
 /*   2. with the scaling factor set to 100                        */
 /*   3. with the scaling factor set to 1000                       */
 /* The only other change made is to change the axistitle and      */
 /* and the minimum and maximum scaling axis values accordingly.   */
 /* Problem: The "scaled" output is very inconsistent. Some        */
 /* values are scaled incorrectly, and some disappear from the     */
 /* chart altogether.                                              */

 #include <conio.h>
 #include <string.h>
 #include <graph.h>                 /* required include files */
 #include <pgchart.h>

 #define MONTHS 12

 typedef enum {FALSE, TRUE} boolean;

 float far value [MONTHS] =          /*value (series) data array */
 {
  (float)1000.00, (float)2000.00, (float)3000.00, (float)4000.00,
  (float)5000.00, (float)6000.00,(float)7000.00, (float)8000.00,
  (float)9000.00, (float)10000.00, (float)11000.00, (float)12000.00
   };

 char far *category[MONTHS] =         /* category data array */
   {
   "Jan", "Feb", "Mar", "Apr", "May", "Jun",
   "Jly", "Aug", "Sep", "Oct","Nov", "Dec"
   };

 main()

 {
 chartenv env;                /* define chart environment variable */

 _setvideomode(_ERESCOLOR);   /* set to graphics mode */
                  /* initialize chart library and a default bar chart */
  _pg_initchart();

 _pg_defaultchart(&env, _PG_BARCHART, _PG_PLAINBARS);

                             /*add titles and some chart options       */
  strcpy(env.xaxis.axistitle.title, "Simple bar chart, no scale factor");
  env.xaxis.autoscale = FALSE;           /* turn off autoscaling       */
  env.xaxis.scalemax = (float)15000.00;  /* max x-axis value           */
  env.xaxis.scalemin = (float)0.00;      /* min x-axis value           */
  env.xaxis.ticinterval = (float)1000.00;/* interval for x-axis tickmarks*/

 if(_pg_chart (&env,category,value, MONTHS)) /* call to charting routine*/
         {_setvideomode(_DEFAULTMODE);       /* error trap...          */
          _outtext("error, can't draw chart");
          }
      else
         {
          getch();                          /* wait for a keystroke */
          }
  /*********************************************************************/
  /* same chart, same series, scaled by a factor of 100 */
  strcpy(env.xaxis.axistitle.title,"Same chart, scalefactor set to 100");
  env.xaxis.autoscale = FALSE;           /* turn off autoscaling */
  env.xaxis.scalemax = (float)150.00;    /* max x-axis value */
  env.xaxis.scalemin = (float)0.00;      /* min x-axis value */
  env.xaxis.ticinterval = (float)10.00;  /* interval for x-axis tickmarks*/
  env.xaxis.scalefactor = (float)100.00;

 if(_pg_chart (&env,category,value, MONTHS)) /* call to charting routine*/
         {_setvideomode(_DEFAULTMODE);       /* error trap...*/
          _outtext("error, can't draw chart");
          }
                  else
         {
          getch();                             /* wait for a keystroke */
          }
  /********************************************************************/
  /* same chart, same series, scaled by a factor of 1000              */
  strcpy(env.xaxis.axistitle.title,"Same chart, scalefactor set to 1000");
  env.xaxis.autoscale = FALSE;           /* turn off autoscaling */
  env.xaxis.scalemax = (float)15.00;  /* max x-axis value */
  env.xaxis.scalemin = (float)0.00;      /* min x-axis value */
  env.xaxis.ticinterval = (float)1.00;  /* interval for x-axis tickmarks*/
  env.xaxis.scalefactor = (float)1000.00;

 if(_pg_chart (&env,category,value, MONTHS)) /* call to charting routine*/
         {_setvideomode(_DEFAULTMODE);       /* error trap...*/
          _outtext("error, can't draw chart");
          }
                  else
         {
          getch();                          /* wait for a keystroke */
          }

 /********************************************************************/
         _setvideomode(_DEFAULTMODE);      /* reset the video mode  */

          return(0);
          }


 259. SideKick 1.56x Causes Problems with Keyboard Input

 Product Version(s): 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47254

  Borland's SideKick Version 1.56x has been found to cause problems
 with keyboard input in QuickC and QuickAssembler.

 The following routines have been observed to show the problem with
 SideKick loaded: gets, getch, getche, cgets, cscanf, scanf, and kbhit.

 In all cases, when a program requiring keyboard input is run with one
 of these routines, input does not occur as expected. The first 15 keys
 pressed during a call to one of these run-time library functions do
 not appear on the run screen. The 16th and all following keys are
 received by the input function/procedure. Upon termination of the
 program being run under the QuickC environment, the 15 keys pressed
 during run time appear on the QuickC editing screen.

 To alleviate this problem, either do not load SideKick after booting,
 or use the Hot-Key combination to remove it from memory. The key
 combination should be used at the DOS command prompt, as follows:

    CTRL+ALT (To call up the main selection window), then
    CTRL+HOME+END


 260. Chart Location for Scaletitle Documented Incorrectly

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 10-OCT-1989    ArticleIdent: Q47450

 In the Presentation Graphics chapter of "C for Yourself," there is an
 error on Page 256. Under the scaletitle heading, the second paragraph
 states that "the x axis scaletitle appears below the x axis title."
 This is not correct. If an x axis scaletitle is displayed, it always
 will be ABOVE the x axis title. The positioning of the y axis
 scaletitle is described correctly.


 261. Black and White Text Modes Display in Color on Color System

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C docerr
 Last Modified: 22-DEC-1989    ArticleIdent: Q47451

 Question :

 The characteristics of the different video modes that you can obtain
 with _setvidemode are listed in "C for Yourself" on Page 201. The two
 black and white text modes, _TEXTBW40 and _TEXTBW80, both show 16 gray
 shades as the available colors. When I set either of these modes, my
 text is output in color rather than in gray shades. Why can't I get
 gray tones?

 Response :

 The information in "C for Yourself" is accurate, but incomplete. The
 chart under _setvideomode in the QuickC on-line help is more
 informative. "C for Yourself" fails to explain that these modes do
 provide 16 colors, unless you are using a monochrome display, in which
 case you get 16 gray shades.

 The "C 5.1 Run-time Library Reference" and the QuickC on-line help for
 _setvideomode both list the black and white text modes as follows:

    Mode                Type      Size      Colors    Adapter
    ----                ----      ----      ------    -------

    _TEXTBW40           M/T       40x25     16        CGA
    _TEXTBW80           M/T       80x25     16        CGA

 This table is followed by the footnote:

 "For monochrome displays the number of colors is the number of gray
 shades".


 262. Libraries Only Found When Linking in Environment

 Product Version(s): 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q47501

 Question :

 When I use the QuickC environment, my programs compile and link
 properly, but when I compile and link from the command line, I get the
 error "Cannot find library." I tried running the NMAKE file that was
 produced by QuickC and that method did not work either. What is the
 difference when I am in the QuickC environment?

 Response :

 The only reason this situation might occur is if your LIB environment
 variable string was not typed in correctly. If the string contains any
 spaces, then, although it may point to the correct directories, it is
 not interpreted correctly.

 Everything works correctly inside the QuickC environment because the
 QuickC environment actually parses the environment strings, and passes
 on the correct values without the spaces to the compiler and linker.
 This parsing does not occur when you work outside the environment with
 command line compiling and linking, or when using NMAKE.

 Another reason a badly set environment string may not be noticed inside
 the QuickC environment is because of the QuickC initialization file
 QC.INI. This file is created the first time you run QuickC, and it is
 updated on each subsequent usage. It is used to store environment
 information such as compiler and linker flags, menu options, completed
 Learn QuickC lessons, etc.

 If you select the Environment option under the Options menu, you can
 see the current LIB setting. If you modify this string, then the
 modified string is used in place of the LIB environment variable, and
 it is saved for future use in the QC.INI file. If, at a later time,
 the LIB environment variable is set incorrectly, it will go unnoticed
 inside of the QuickC environment as the string in QC.INI always
 overrides it.

 Environment variables are used by various programs as a source of
 global configuration information. With Microsoft's C products, PATH,
 LIB, INCLUDE, and TMP are the environment variables used. These values
 must be set each time the computer is booted up or rebooted from the
 keyboard. Therefore, a batch file is normally used to make these
 settings -- usually AUTOEXEC.BAT. The SET command is used to set an
 environment variable to a value. For example,

    SET LIB=C:\MSC\INCLUDE

 sets LIB to the C:\MSC\INCLUDE directory and any program may use this
 information if needed. No spaces may be entered anywhere in the string
 and, if they are, then the programs utilizing this variable will not
 find the correct information. It is especially important that no
 spaces are entered at the end of the string because these are very
 hard to detect. All of the following examples are incorrect:

    SET LIB = C:\MSC\LIB
    /* illegal spaces around equal sign - this will even cause a
       failure inside the QuickC environment */

    SET LIB=C:\MSC\LIB; C:\QC2\LIB
    /* illegal space after the semicolon - the first directory would
       be found, but not the second */

    SET LIB=C:\MSC\LIB<space>
    /* the space character at the end can cause problems */

 You may find situations where some of these examples do not cause any
 problems, but if you are experiencing problems that seem to involve
 environment variables, it is best to delete the lines that SET them in
 your batch files, and then completely retype them.


 263. QuickC Can Dimension Arrays Only Up to 0xFFFF Bytes

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47502

 Problem:

 When compiled with QuickC 2.00, the second line of the following code
 generates the error "C2125: too_big : allocation exceeds 64K." The
 same code compiles without error under C 5.10.

    char not_big[0x0FFFF];
    char too_big[0x10000];

 In compact or large model, the definition of too_big should be legal.
 Although too_big is being defined as 0x10000 bytes, the indices for
 the array goes only from 1 to 0xFFFF, which is a single segment. The
 following array definition results in the same error:

    char still_too_big[0x100][0x100];

 Again, this should be legal since the space taken by the array is a
 single segment.

 Response:

 This problem is caused by a limitation of the QuickC compiler and the
 way in which it stores information concerning arrays. The upper limit
 of an array is stored in a single word, which can hold only values up
 to 0xFFFF. The upper limit of the arrays shown above are 0x10000;
 thus, they do not fit in the word used by QuickC 2.00 and are
 tagged with C2125.

 A workaround of the limitation would be to declare a pointer to the
 required type, and then allocate space for it with either halloc or
 _dos_allocmem.

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


 264. Directory Listing for QuickC 2.00 Distribution Disks (5.25)

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | QC
 Last Modified:  6-FEB-1991    ArticleIdent: Q47610

 The following is a directory listing for the QuickC version 2.00
 distribution disks (5.25-inch disk set). This is a superset of the
 information presented in the PACKING.LST file for QuickC 2.00. This
 list includes the size (in bytes) of each file and the time/date
 stamps.

 Disk 1: Setup

 DOSPATCH        <DIR>      12-21-88   5:25p
 SAMPLES         <DIR>      12-21-88   5:25p
 SETUP        EXE    49543  12-13-88  11:32a  Setup program: installs
                                              QC
 PACKING      LST     7052  12-13-88  11:35a  Packing list (this file)
 README       DOC    39666  12-21-88   4:16p  Release notes: QC 2.00
 FIXSHIFT     COM      690  10-06-87  10:49a  BIOS bug fix Compaq\kbds
 HELPMAKE     EXE    46828  12-07-88   9:05a  Creates help files
 MSHERC       COM     6749  10-26-88   7:37p  TSR for Herc. card grafix
      8 File(s)      4096 bytes free

 <subdirectory DOSPATCH>
 .               <DIR>      12-21-88   5:25p
 ..              <DIR>      12-21-88   5:25p
 PATCH320     DOC     2169   2-19-88   4:29p  Patch for DOS 3.20
 PATCH87      DOC     3937   2-19-88   4:30p  Patch for README.DOC files
 PATCH87      EXE     4206   1-29-88   2:30p  ""
 RMRHS        EXE      543   6-29-86   4:00a  ""
 SETRHS       EXE      543   6-29-86   4:00a  ""
 STKPAT       BAT       94   6-29-86   4:00a  ""
 STKPAT       SCR       30   6-29-86   4:00a  ""
      9 File(s)     4096 bytes free

 <subdirectory SAMPLES>
 .               <DIR>      12-21-88   5:25p
 ..              <DIR>      12-21-88   5:25p
 SAMPLES      DOC     3518  12-02-88   6:04p  Sample C programs
 GRDEMO       C      18582  12-15-88   4:25p  " -- Read SAMPLES.DOC
 MENU         C      11114  12-14-88  12:31p  ""
 MENU         H       1956   8-29-88   4:15p  ""
 GRDEMO       MAK      617  11-08-88   6:09p  ""
 TURTLE       C      13511  12-14-88   5:26p  ""
 TURTLE       H       3933  11-22-88  11:30a  ""
 CHRTDEMO     C      58162  12-07-88   2:00p  ""
 CHRTSUPT     C      14174  12-06-88   8:11a  ""
 CHRTDEMO     H       3742  11-23-88  11:46a  ""
 CHRTDEMO     MAK      560  12-06-88   8:14a  ""
 CRLF         C       9355  12-07-88  11:41a  ""
 LIFE         MAK      562  11-08-88   6:02p  ""
 LIFE         C      35018  11-21-88   6:42p  ""
 TOOLS        C       3157  11-21-88   6:43p  ""
 TOOLS        H       1199   8-10-88  12:15p  ""
      18 File(s)         4096 bytes free

 Disk 2: Learning the Microsoft QuickC Integrated Environment

 LINK         EXE   121347  12-05-88   3:24p  Linker: Win and OS/2
 LEARN        COM    29264  12-05-88   1:14p  Tutorial and intro. to QC
 LC           PGM    27456  12-05-88   1:14p  Tutorial support files
 QCCBT        CTX    73796  12-05-88   1:14p  ""
 QCCBT        SCN    49548  12-05-88   1:14p  ""
 QCCBT        SOB    44554  12-05-88   1:14p  ""
      6 File(s)    13312 bytes free

 Disk 3: Integrated Development Environment 1

 QCENV        HLP    56718  12-14-88   8:57a  Help on QC environment
 QC           EXE   286126  12-19-88  11:59a  QuickC intgd. prog. env.
      2 File(s)    18432 bytes free

 Disk 4: Integrated Development Environment 2

 INCLUDE         <DIR>      12-19-88  4:27p
 C1           ERR    17267  12-14-88   7:34p  Comp. err. msg for QC/QCL
 QCC          OVL   169477  12-19-88  10:51a  QC overlay for integrated
                                              env.
 NMAKE        EXE    66711  12-05-88   5:04p  Program maint. utility
      4 File(s)     9216 bytes free

 <subdirectory INCLUDE>
 .               <DIR>      12-19-88   4:27p
 ..              <DIR>      12-19-88   4:27p
 SYS             <DIR>      12-19-88   4:27p
 ASSERT       H        939  12-05-88    6:54p  Include files
 BIOS         H       4739  12-05-88    6:54p  "" Read files for details
 CONIO        H        862  12-05-88    6:54p  ""
 CTYPE        H       2174  12-05-88    6:54p  ""
 DIRECT       H        602  12-05-88    6:54p  ""
 DOS          H       5513  12-05-88    6:54p  ""
 ERRNO        H       1346  12-05-88    6:54p  ""
 FCNTL        H       1127  12-05-88    6:54p  ""
 FLOAT        H       4870  12-05-88    6:54p  ""
 IO           H       1206  12-05-88    6:54p  ""
 LIMITS       H       1256  12-05-88    6:54p  ""
 MALLOC       H       2911  12-05-88    6:54p  ""
 MATH         H       3182  12-05-88    6:54p  ""
 MEMORY       H        975  12-05-88    6:54p  ""
 PROCESS      H       1836  12-05-88    6:54p  ""
 SEARCH       H        935  12-05-88    6:54p  ""
 SETJMP       H        815  12-05-88    6:54p  ""
 SHARE        H        450  12-05-88    6:54p  ""
 SIGNAL       H       1800  12-07-88   10:41a  ""
 STDARG       H        533  12-05-88    6:54p  ""
 STDDEF       H       1075  12-05-88    6:54p  ""
 STDIO        H       4326  12-05-88    6:54p  ""
 STDLIB       H       4717  12-05-88    6:54p  ""
 STRING       H       2117  12-05-88    6:54p  ""
 TIME         H       2137  12-05-88    6:54p  ""
 VARARGS      H        561  12-05-88    6:54p  ""
 GRAPH        H      13508  12-13-88   11:47a  ""
 PGCHART      H       8654  12-13-88   12:18p  ""
      31 File(s)      9216 bytes free

 <subdirectory INCLUDE\SYS>
 .               <DIR>      12-19-88    4:27p
 ..              <DIR>      12-19-88    4:27p
 LOCKING      H        468  12-05-88    6:54p  ""
 STAT         H       1301  12-05-88    6:54p  ""
 TIMEB        H        740  12-05-88    6:54p  ""
 TYPES        H        734  12-05-88    6:54p  ""
 UTIME        H        952  12-05-88    6:54p  ""
      7 File(s)      9216 bytes free

 Disk 5: Utilities

 BRIEF        KEY      130  12-14-88    7:42p  Keyboard files
 EMACS        KEY      155  12-14-88    7:42p  ""
 ME           KEY      116  12-14-88    7:43p  ""
 QC           KEY      258  12-14-88    7:43p  ""
 EPSILON      KEY      155  12-14-88    7:42p  ""
 QCC          DAT    31568  12-19-88   10:51a  Data file used by QC
                                               env.
 ERRORS       HLP    62639  12-09-88    1:16p  Help on error messages
 LINK         EXE    95532  12-05-88    3:05p  Linker
 ILINK        EXE    48073  12-18-88   11:44a  Incremental linker
 ILINKSTB     OVL     4214  12-13-88   11:09a  Ilink overlay
 MOUSE        COM    14674   9-20-88    6:32p  MS mouse driver, V6.24a
 LIB          EXE    35659  12-05-88    5:59p  Library maintenance
                                               util.
 MKKEY        EXE    36967  12-15-88   10:03a  Custom kbd command files
 CRLF         EXE    14053  12-07-88   11:42a  Del CTRL chr, ins.
                                               CR/LFs
      14 File(s)      9216 bytes free

 Disk 6: Microsoft QC Advisor

 QC           HLP   355940  12-13-88    9:34a  Help on C and lib
                                               functions
      1 File(s)      6144 bytes free

 Disk 7: Command-Line Compiler

 QCL          HLP     1482  11-17-88   12:14p  Help on QCL
 CL           ERR     1583  12-14-88    7:15p  Error msg for QCL and QC
 GRAPHICS     HLP    94922  12-16-88   10:30a  Help on graphics fncs.
 QCCOM        EXE   207872  12-19-88   11:59a  Cmd-line compiler drvr.
 QCL          EXE    25416  12-19-88    8:19p  Command-line compiler
      5 File(s)     29696 bytes free

 Disk 8: Libraries 1

 SLIBC        LIB   137243  12-06-88    3:07p  Library for small model
 SLIBFP       LIB    40389  11-28-88    7:41p  Fl-point math lib. (sm)
 SVARSTCK     OBJ      507   5-09-88    2:59p  Sm. heap/stack .OBJ file
 MLIBC        LIB   138779  12-06-88    3:37p  Library for medium model
 MLIBFP       LIB    40901  11-28-88    7:52p  Fl-point math lib. (med)
 MVARSTCK     OBJ      507   5-09-88    3:18p  Med. heap/stack .OBJ
                                               file
      6 File(s)      1024 bytes free

 Disk 9: Libraries 2

 DBUSED       OBJ       48  12-06-88    4:03p  For C5.1 OS/2 lib.
 87           LIB     4633   9-16-88    2:54p  FP math lib. for 8087
 BINMODE      OBJ      127   5-09-88    3:03p  File I/O: text to bin
 EM           LIB    16921   9-21-88   10:59p  FP math lib: em. of 8087
 LIBH         LIB    14209   5-24-88   11:47a  General helper library
 SETARGV      OBJ      143   5-09-88    3:05p  Wild card: cmdline.
                                               args.
 CLIBC        LIB   147007  12-06-88    3:56p  Library for compact mod.
 CLIBFP       LIB    41415  11-28-88    7:46p  Fl-point math lib. (cpt)
 CVARSTCK     OBJ      487   5-09-88    3:35p  Cpt heap/stack .OBJ file
 GRAPHICS     LIB    75337  12-13-88   10:19a  Low-level graphics lib.
 PGCHART      LIB    54435  11-23-88    1:00p  Presentation grphcs lib
 RMFIXUP      OBJ      233   8-30-88    4:33p  No ints: co-prcssor math
      12 File(s)         0 bytes free

 Disk 10: Libraries 3/Fonts

 NOTES        HLP     5558  12-02-88    3:00p  User-defined help file
 LLIBC        LIB   148543  12-06-88    4:13p  Library for large model
 LLIBFP       LIB    42439  11-28-88    8:02p  Fl-point math lib. (lg)
 LVARSTCK     OBJ      487   5-09-88    4:00p  Lg. heap/stack .OBJ file
 FONT          <DIR>        12-19-88    4:49p
      5 File(s)     14336 bytes free

 <subdirectory FONT>
 .             <DIR>        12-19-88    4:49p
 ..            <DIR>        12-19-88    4:49p
 COURB        FON    19088  11-12-87    1:23p  Font files
 HELVB        FON    50880  11-12-87    1:25p  ""
 MODERN       FON     7584  11-12-87    1:26p  ""
 ROMAN        FON    11120  11-12-87    1:27p  ""
 SCRIPT       FON    10304  11-12-87    1:27p  ""
 TMSRB        FON    45936  11-12-87    1:27p  ""
      8 File(s)     14336 bytes free


 265. QuickC: Tilde Erroneously Replaced by Minus Sign in Help

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc docerr
 Last Modified: 10-OCT-1989    ArticleIdent: Q47725

 In the operator precedence table in the on-line help in QuickC Version
 2.00 and QuickC with Quick Assembler Version 2.01, the character
 displayed as the one's complement operator is the minus sign (-). This
 erroneous character should be the tilde (~).

 To view the erroneous character, call up QuickC, bring up the help
 menu, go into the contents section, and select operator precedence
 under the "Useful Tables" heading. The minus sign is located in the
 second section above the correctly represented minus sign.


 266. "File Does Not Exist" Error in OS/2 DOS Box with Existing File

 Product Version(s): 1.01 2.00 2.01
 Operating System:   OS/2
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47748

 When using QuickC in the DOS compatibility box under OS/2, if a file
 is locked by another application, the environment lists the file (for
 example, in File.Open), but if an attempt is made to open the file, an
 error is displayed. The file obviously exists, because the environment
 just listed it. Yet, in QuickC Version 2.00 and QuickC with
 QuickAssembler Version 2.01, the error displayed in the dialog box is
 "File Does Not Exist." In QuickC Version 1.01, the error displayed is
 "General Failure."

 This problem is a result of the fact that QuickC is designed for the
 single-user, DOS environment, and does not deal gracefully with a
 locked file. If you swap to the other screen group, and release the
 file, QuickC then loads the file.

 Note: This is a particular problem when merging files into another
 document in a protected-mode program. If, for example, you merge the
 file into a letter in Word 5.00 running in protected mode, and try to
 load the file into QuickC running in the DOS box, you will encounter
 this problem, and it will not be immediately apparent that the file is
 actually being used by another application. Saving the file in Word
 releases Word's hold on the file, since it then becomes a part of the
 letter.


 267. Modulus Yields Incorrect Result When Used with /Ot

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01 fixlist2.50 fixlist2.51
 Last Modified: 31-AUG-1990    ArticleIdent: Q65107

 The following code using the modulus operator "%" yields incorrect
 results under Microsoft QuickC version 2.00 when optimizations are set
 to ON or FULL and release mode is selected.

 The error also occurs when compiling using the qcl command if you use
 the /O, /Ot, or /Ox optimizations.

 To avoid the error, upgrade to QuickC version 2.50 or QuickC with
 QuickAssembler version 2.51, or avoid the problem optimizations.
 Neither version 5.10 or version 6.00 of the Microsoft C Compiler
 demonstrate this error.

 Sample Code
 -----------

 #include <stdio.h>

 main ()
 {
  int x=26,
      Number = 151-(3 * x),
      Onesdigit = Number % 10;

  printf("The one's digit is: %i\n",Onesdigit); // correct output is 3,
                                                // buggy output is 0
 }

 Microsoft has confirmed this to be a problem with QuickC versions 2.00
 and 2.01. This problem is corrected in versions 2.50 and 2.51.


 268. The _QC Predefined Preprocessing Macro

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47760

 The _QC macro is automatically defined when compiling with QuickC and
 undefined when compiling with Microsoft C Optimizing Compiler. This
 predefined macro can be used to conditionally compile parts of code
 that are unique to one compiler or another. For example, if inline
 assembly is used in an application program, it might be a good idea to
 check the condition of _QC macro before compiling that section of
 code, as follows:

 #ifdef _QC      /* check to see if compiling in QuickC */

 #define _enable()  _asm { sti }
 #define _disable() _asm { cli }

 #endif

 This macro was not documented in the QuickC manuals or in the
 README.DOC. Support for this macro is not guaranteed in future
 releases of the QuickC product.


 269. Incorrect Warning C4413 Issued After Editing Blank Line

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM buglist2.00 buglist2.01
 Last Modified: 10-OCT-1989    ArticleIdent: Q47836

 The code below demonstrates a problem with Version 2.00 or 2.01 of the
 Microsoft QuickC Compiler's incremental compilation capability. The
 compiler may return the following error message when insignificant
 editing to the code is done before compiling:

    filename.c(2): warning C4413: 'main' redefined: preceding reference
                   may be invalid.

 The following are workarounds:

 1. Recompile the file without making any further changes.

 2. Turn off incremental compile in the Options.Make.Compiler Flags
    menu.

 3. Chose the menu option Make.Rebuild All.

 To reproduce the warning, simply compile the following program with
 incremental compile enabled. After the clean compile, remove the blank
 second line, save the file, and recompile to cause the warning.

 void foo(void) {}

 void main(void) {foo();}

 A second compile does not flag the error. However, if you put the
 blank line back in and save the file, recompiling results in the
 reoccurrence of the warning.

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching the problem and will post new information
 as it becomes available.


 270. Using the Spawn, Exec, and System Routines to Call Batch Files

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q47879

 Question:

 Is it possible to execute a batch file (.BAT) using the C run-time
 routines spawn(), exec(), and system()?

 Response:

 Yes. The easiest method is to use the system() routine; however, you
 also can use the spawn() and exec() functions.

 When using the system() function, you need specify only the name of
 the batch file and its arguments (if any).

 The trick when using the spawn() and exec() functions is to create a
 command shell and then submit the batch file to this shell. This can
 be accomplished by spawning or exec'ing COMMAND.COM, and specify the
 /c option along with the name of the batch file.

 Shown below are three examples of executing the batch file "BATCH.BAT"
 using the system(), spawn(), and exec() functions.

 Example 1: Using the system() Routine
 -------------------------------------

    #include <stdio.h>
    #include <process.h>

    void main (void)
    {
      system ("BATCH.BAT");
    }

 Example 2: Using spawn()
 ------------------------

    When using spawn to execute a batch, make sure that you pass
    COMMAND.COM as the second and third parameter.

    #include <stdio.h>
    #include <process.h>

    void main (void)
    {
    /* Using P_WAIT will cause the child process to return to the parent */
    /* process and using P_OVERLAY will not return the child process to  */
    /* the parent process                                                */

      spawnlp (P_OVERLAY, "COMMAND.COM", "COMMAND.COM", "/C",
               "BATCH.BAT", NULL);
       /* or */
      spawnlp (P_WAIT, "COMMAND.COM", "COMMAND.COM", "/C",
               "BATCH.BAT", NULL);
    }

 Example 3: Using exec() to Execute a Batch File
 ---------------------------------------------

 When using exec() to execute the batch file, make sure that
 COMMAND.COM is passed as the first and second parameter.

    #include <stdio.h>
    #include <process.h>

    void main (void)
    {
      execlp ("COMMAND.COM", "COMMAND.COM", "/C", "BATCH.BAT", NULL);
    }

 For further information regarding system(), spawn(), and exec(),
 consult the "Microsoft C Run-Time Library Reference Manual."


 271. Contents of Microsoft Academic Edition Packages

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | B_QuickBas
 Last Modified: 10-OCT-1989    ArticleIdent: Q47964

 Microsoft academic products are the result of our commitment to offer
 Microsoft products at the lowest possible prices for educational
 institutions. Microsoft academic products contain the same software as
 our full-price retail products, with the exception of Microsoft
 QuickBASIC Interpreter Academic Edition. This particular product was
 redesigned around the needs of the student programming courses.

 Academic products are available in the three different configurations
 listed below:

 1. Packaged for personal use for faculty and students.

 2. Ten-packs that contain 10 sets of software and one set of
    documentation for use in labs, classrooms, departments, and
    administrative offices. The packs are licensed only for
    institutionally owned computers and offer additional savings over
    Microsoft Academic Editions.

 3. Microsoft Academic LANs (local area networks) contain software for
    one network server, which may be accessed by up to 32 users on the
    LAN. One set of documentation is also included.

 For example, Microsoft has made a release of QuickC Version 2.00
 available for schools that differs from the retail package. This
 academic package does not contain the "C for Yourself" text or the
 "Microsoft QuickC Tool Kit" because most classes will have their own
 preferred texts. The only text included in the academic package is the
 "Microsoft QuickC Up and Running" manual. The software in the academic
 package is identical to that in the retail package.

 If you have further questions regarding this or any other academic
 releases that Microsoft has offered, contact Microsoft Educational
 Services at (800) 227-4679.


 272. QuickC Message: "Cannot Edit Binary File"

 Product Version(s): 1.00 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q48293

 Question:

 When I compile my program, the compiler gives me an error message that
 says "Cannot edit binary files" or "Cannot load binary file." My
 source file loads correctly, so why do I get this error message when I
 compile it?

 Response:

 These error messages indicate that either one of the include files is
 bad, or you have a bad file on the program list. To correct this
 error, you must identify the bad file and replace it.

 If You Are Using QuickC Version 1.00 or 1.01
 --------------------------------------------

 1. Locate the bad file. After you press ENTER at the error message,
    QuickC will do one of the following two things:

    a. Return you to the source window and report "no errors." This
       indicates that the bad file is one of the include files. To
       determine which include file is bad, remove them from your
       source file, one at a time, until the error goes away.

    b. Continue to compile and link the program, then return to the
       source window reporting "error L1101: invalid object module"
       This indicates that the bad file is one of the files in the
       program list. To determine which file is bad, remove the files
       from the program list, one at a time, until the error goes away.

 2. If the file was originally from one of the distribution disks,
    replace it with a fresh copy from your backup copy of the
    distribution disk.

 If You Are Using QuickC Version 2.00 or 2.01
 --------------------------------------------

 1. Locate the bad file. After you press ENTER at the error message,
    QuickC will do one of the following two things:

    a. Return you to the source window and display "error C2059: syntax
       error 'int constant'." This indicates that the bad file is one
       of the include files. The error message will report the name of
       the bad file.

    b. Return you to the source window and display "error C2018:
       unknown character '0x...'." This indicates that the bad file is
       one of the files on the program list. The error message will
       report the name of the bad file.

 2. If the file is originally from one of the distribution disks,
    replace it with a fresh copy from your backup copy of the
    distribution disks.


 273. Linesize Pragma Not Supported in QuickC

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C
 Last Modified: 10-OCT-1989    ArticleIdent: Q48641

 The linesize pragma can be used with C Version 5.10 for setting the
 width of source listings. This pragma is supported only by Microsoft C
 Version 5.10 and not by any version of Microsoft QuickC. Documentation
 for the pragma can be found on Pages 13-14 of the update section of
 the Version 5.10 "Microsoft C for the MS-DOS Operating System: User's
 Guide." Possible error messages reported by QuickC include the
 following:

    warning C4068: unknown pragma

    warning C4000: unknown warning


 274. Incorrect Evaluation When Type Casting in while and for Loops

 Product Version(s): 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM buglist1.01 buglist2.00
 Last Modified: 10-OCT-1989    ArticleIdent: Q48724

 The resulting value is incorrectly evaluated when you type cast an
 integer to a float (or double) in "for" loops and "while" loops in
 QuickC Versions 1.01 and 2.00 and QuickAssembler Version 2.01.

 The problem does not occur in the initialization expression, only
 in the conditional test expression and the increment expression.
 Workarounds include using a temporary variable and simplifying the
 assignment expression.

 Microsoft has confirmed this to be a problem with QuickC Versions 1.01
 and 2.00 and QuickAssembler Version 2.01 (buglist2.01). We are
 researching this problem and will post new information as it becomes
 available.

 The following program demonstrates the problem. Note that the problem
 also exists if you replace references to "float" by "double".

 #include <stdio.h>
 void main(void)
 {
    float var;
    float temp;

    var = (float)1;               /* do-while statement:            */
    do                            /* all casts work correctly       */
      var += (float)2;
    while (var <= (float)5);
    printf ("var = %12f, expected 7.000000\n", var);

    var = (float)1;               /* while statement:                */
    while (var <= (float)5)       /* this cast works incorrectly     */
      var += (float)2;            /* this cast works correctly       */
    printf ("var = %12f, expected 7.000000\n", var);

    for                           /* for statement:                  */
        (var = (float)1;          /* this cast works correctly       */
         var <= (float)5;         /* this cast works incorrectly     */
         var += (float)2)         /* this cast and/or the assignment */
                                  /* works incorrectly               */
             continue;
    printf("var = %12f, expected 7.000000\n", var);

 /* Workarounds for the while- and for-loops:                        */

    var = (float)1;               /* while statement:                */
    temp = (float)5;              /* this cast works correctly       */
    while (var <= temp)           /* use a non-cast float here       */
      var += (float)2;            /* this cast works correctly       */
    printf ("var = %12f, expected 7.000000\n", var);

    for                           /* for statement:                  */
        (var = (float)1;          /* this cast works correctly       */
         var <= (float)5;
         var = var + (float)2)    /* use a different assignment      */
             continue;
    printf("var = %12f, expected 7.000000\n", var);
 }


 275. Absolute Coordinate of Top Left Corner for _settextwindow

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickASM 2.01
 Last Modified: 10-OCT-1989    ArticleIdent: Q48729

 The absolute coordinate of the top left corner for _settextwindow() is
 (1,1) and NOT (0,0).

 Attempting to _settextwindow() with the top left corner as (0,0) and
 using _settextposition() along with _outtext() causes the program to
 function abnormally. The text is either placed in an incorrect area or
 the machine hangs. The top and left absolute address is (1,1). This is
 not documented in the "Microsoft QuickC Run-Time Library Reference" or
 the on-line help. However, it is documented in the "Microsoft QuickC
 Graphics Library Reference" in Section 2.2 on Pages 42 and 43.


 276. Format Specifier %p Not Found in Documentation

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 10-OCT-1989    ArticleIdent: Q48732

 The format specifier %p was left out of both the QuickC Version 2.00
 written documentation and the on-line help facility included with the
 package. %p is used to display the contents of pointer variables. This
 is useful for debugging programs that use pointers. The pointer should
 be near or far, depending on the memory model. However, the pointer
 size can be overridden with the "N" or "F" attribute, depicting near
 or far, respectively. The following small model program declares two
 pointers (near and far) and prints out their contents with printf:

 #include <stdio.h>
 void main(void)
 {
   int     i    =1;
   int     *ptr =&i;
   int far *fptr=(int far *)&i;

   printf("the near pointer: %p    the far pointer: %Fp",ptr,fptr);
 }


 277. QuickC 2.00 Fails with Self-Relative PATH Variable

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM buglist2.00 buglist2.01
 Last Modified: 10-OCT-1989    ArticleIdent: Q48743

 QC.EXE and QCL.EXE behave differently from LINK.EXE and NMAKE.EXE when
 loaded under specific PATH settings, specifically when the pathname is
 relative to the directory containing QC.EXE and QCL.EXE.

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

 The following demonstrate the differences. In all cases, QC.EXE is in
 C:\QC2\BIN:

 Case 1: (Different Behavior)
 ----------------------------

 PATH=..
 CD C:\QC2\BIN\B          (an immediate subdirectory)
 QC                       (Get 'Program is not on search path' message)
 QCL                      (Get Microsoft copyright)
 LINK                       "      "        "
 NMAKE                      "      "        "

 Case 2: (Different Behavior)
 ----------------------------

 PATH=QC2\BIN
 CD \                     (root directory)
 QC                       (Get 'Program is not on search path' message)
 QCL                      (Get Microsoft copyright)
 LINK                       "    "   "
 NMAKE                      "    "   "

 Case 3: (Different Behavior)
 ----------------------------

 MD C:\QC2\BIN\B\M
 PATH=M\..\..
 CD C:\QC2\BIN\B
 QC                       (EXEC failure)
 QCL                         "     "
 LINK                     (Access denied)
 NMAKE                       "       "

 The directories "B" and "M" can be changed to any other name to
 produce the error, as long as M is a single character name. If M is
 renamed to a name with more than one character, the message "Program
 is not on search path" occurs.

 Case 4: (All Invocations Perform Properly)
 ------------------------------------------

 PATH=C:\QC2\BIN\B\..     (or PATH=\QC2\BIN\B\..)
 CD \                     (or CD C:\QC2\BIN\B)
 QC                       (loads QC environment)
 QCL                      (Get Microsoft copyright)
 LINK                       "      "        "
 NMAKE                      "      "        "


 278. Explanation of Manifest Constants Used By _putimage()

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM docerr
 Last Modified: 10-OCT-1989    ArticleIdent: Q48746

 When invoking the on-line help in Microsoft QuickC Version 2.00 or
 QuickAssembler Version 2.01 for the _putimage() function, the
 description section mentions five manifests constants, but does not
 describe what they mean.

 The following information is taken from the "Microsoft QuickC Run-Time
 Library Reference" manual, Page 470:

    _GAND     Transfers the image over an existing image on the screen.
              The resulting image is the logical-AND product of the two
              images: points that had the same color in both the existing
              image and the new one will remain the same color, while
              points that have different colors are ANDed together.

    _GOR      Superimposes the image onto an existing image. The new image
              does not erase the previous screen contents.

    _GPRESET  Transfers the data point-by-point onto the screen. Each
              point has the inverse of the color attribute it had when it
              was taken from the screen by _getimage, producing a negative
              image.

    _GPSET    Transfers the data point-by-point onto the screen. Each
              point has the exact color attribute it had when it was taken
              from the screen by _getimage.

    _GXOR     Causes the points on the screen to be inverted where a point
              exists in the image buffer. This behavior is exactly like
              that of the cursor: when an image is put against a complex
              background twice, the background is restored unchanged. This
              allows you to move an object around without erasing the
              background. The _GXOR constant is a special mode often used
              for animation.


 279. LIB.LIB: Cannot Find Library

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q48771

 The following error occurs when you try to compile and link
 a program in the QC environment, and don't use or have LIB.LIB:

    LIB.LIB: cannot find library

 This error occurs when a trailing space is included at the end of the
 library files directory in Options.Environment. Remove the trailing
 space or retype the directory and path without the trailing space.


 280. Tabs from QuickC Get Expanded

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q48805

 When using other editors to display a file originally created in the
 QuickC environment, the file appears to have jagged or skewed lines.

 The following is a workaround:

 Edit or display your file only with editors similar to the QuickC
 environment, such as the "M Editor", that allow you to change the
 default value of the tab character. Or, you could run your file
 through a translator to replace each tab character with a specific
 number of blank spaces.

 If you press the TAB key in the QuickC environment, the tab character
 (09h) is inserted into your edited file. QuickC does not expand the
 tab character to its equivalent in blank spaces, it merely displays
 the number of blank spaces equivalent to the tab character. The
 default value is eight blank spaces per tab character. Changing this
 default value within QuickC does not change the default value for
 other editors.


 281. Video Modes Available on Tandy 1000 Computers

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 10-OCT-1989    ArticleIdent: Q48857

 Question:

 Using Quick C and a Tandy 1000TX computer, what video modes are
 available?

 Response:

 There is an on-line example that tests every video mode on your
 computer until a video mode cannot be set. The program starts by going
 through all the text modes, and then it tests the graphics modes. This
 sample program can be found under _setvideomode() on-line help.

 The following is a list of video modes that work on Tandy 1000
 computers:

    _TEXTBW40
    _TEXTC40
    _TEXTBW80
    _TEXTC80
    _MRES4COLOR
    _MRESNOCOLOR
    _HRESBW


 282. Difference between Huge Pointers Is Incorrect in QuickC 2.00

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm 2.01 S_C buglist2.00
 Last Modified: 10-OCT-1989    ArticleIdent: Q48870

 Taking the difference of two pointers should return the number of
 elements between the two pointers. Using huge pointers, this should
 also work correctly across a segment boundary. However, QuickC fails
 to return the proper value. A simple workaround, and the code that
 fails, is shown below. Note that the suggested workaround works
 properly only under DOS, but finds the distance (defined as the number
 of elements) between any two far pointers, and uses long arithmetic
 instead of signed integer arithmetic.

 Code Example
 ------------

 /*
   Finds the number of elements between far pointers under DOS.
 */

 #include <stdio.h>
 #include <malloc.h>
 #include <stdlib.h>
 #include <dos.h>

 /*  define the type of the pointers (long is a 4 byte type) */
 typedef long ELTYPE ;

 void main( void )
 {
    ELTYPE huge *beginptr, huge *endptr;
    long  count = 20000L;
    long  x, tmp ;

          /* Allocate huge buffer. */
    beginptr = (ELTYPE huge *)halloc( count, sizeof( ELTYPE ) );
    if( beginptr == NULL )
          {
                   printf( "Insufficient memory" );
                   exit( 1 );
          }

          /* Fill the buffer with characters. */
    for( endptr = beginptr; count; count--, endptr++ )
       *endptr = (char)count % 255 ;

    /**************************************************************
    *
    * This method is inaccurate in QuickC 2.00 and QuickC 2.01
    * and should NOT be used. Use the method below for these
    * compilers and for calculating the difference between pointers
    * when a signed integer may be unable to hold the result.
    *
    **************************************************************/

    /* Find the difference (in elements) between two pointers using
       signed integer arithmetic. This arithmetic is incorrect under
       QuickC 2.00, and is not valid in cases where the difference
       exceeds 32,767 (the maximum for a signed integer).
    */

    x = (long) (endptr - beginptr) ;

    printf("beginning pointer = %p\n", beginptr) ;
    printf("ending pointer    = %p\n", endptr) ;

    printf("endptr - beginptr (hex) is: %lX\n", x) ;
    printf("endptr - beginptr (dec) is: %ld\n", x) ;

    /***************************************************************
    *
    *  This is the correct method, and is accurate to find
    *  differences up to 2,147,483,648 (signed long integer).
    *
    ***************************************************************/

    /* Find the differences (in elements) between two pointers using
       long arithmetic, not relying on pointer arithmetic, which is
       done using signed integers. This could be put into a macro,
       and is valid only under DOS (where segments are contiguous.
    */

    tmp = (long) (((((long) FP_SEG(endptr))<<4)+FP_OFF(endptr)) -
                  ((((long) FP_SEG(beginptr))<<4)+FP_OFF(beginptr))) ;

    printf("beginning pointer = %p\n", beginptr) ;
    printf("ending pointer    = %p\n", endptr) ;

    printf("endptr - beginptr (hex) is: %lX\n", tmp/sizeof(ELTYPE)) ;
    printf("endptr - beginptr (dec) is: %ld\n", tmp/sizeof(ELTYPE)) ;

    /* Free huge buffer. */
    hfree( beginptr );
          exit( 0 );
 }

 Microsoft has confirmed this to be a problem with QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.


 283. Some Toshibas Cannot Highlight Text for Edit with QuickC 2.00

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01 QC
 Last Modified: 10-OCT-1989    ArticleIdent: Q49004

 With QuickC Versions 2.00 and 2.01 and MS-DOS Version 3.30, Toshiba
 1200 HB cannot select text using SHIFT+<arrow> keys for editing.

 The Toshiba T1000 with MS-DOS Version 2.11 behaves in the same way.

 To workaround this problem, hold down the SHIFT and CTRL keys, then press a
 letter key (SHIFT+CTRL+<letter>) as follows:

    Key   Function
    ---   --------

    S     Cursor left
    D     Cursor right
    X     Cursor down
    E     Cursor up

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information as it becomes available.


 284. Changing Default Character in QC 2.00 Presentation Graphics

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm
 Last Modified: 10-OCT-1989    ArticleIdent: Q49063

 You can change the default characters used by QuickC Version 2.00's
 presentation graphics library routines to any other character. To
 change the default character, insert the following lines of code
 before you display the graphic:

 charmap  chartemp1;

 /* '*' is default character */
 /* change '*' to ASCII character '+' */

 _pg_getchardef ('+', chartemp1);
 _pg_setchardef ('*', chartemp1);

 The first line gets the new character that you want to use. The second
 line sets the new character to the character that you want to replace.

 You cannot display each point in a data series as a different
 character, but you can change the default characters for each data
 series.

 The following code is the _pg_chartscatter() example from the QuickC
 2.00 on-line help. The lines of code mentioned above have been added
 to the code example to demonstrate this feature.

 Code Example
 ------------

 #include <conio.h>
 #include <graph.h>
 #include <string.h>
 #include <stdlib.h>
 #include <pgchart.h>

 #define ITEMS  5
 #define SERIES 2
 float far employees[SERIES][ITEMS] = {{235., 423., 596., 729., 963.},
                                       {285., 392., 634., 801., 895.}};
 float far profits[SERIES][ITEMS] =   {{0.9,  2.3,  5.4,  8.0,  9.3},
                                       {4.2,  3.4,  3.6,  2.9,  2.7}};
 char far *companies[SERIES] = { "Goodstuff, Inc.", "Badjunk & Co."};

 charmap  chartemp1;

 main()
 {
     chartenv env;
     short mode = _VRES16COLOR;

     while( !_setvideomode( mode ) )
         mode--;
     if (mode == _TEXTMONO )
         exit( 1 );

     _pg_initchart();

     /* Change '*' to '+' */

     _pg_getchardef ('+', chartemp1);
     _pg_setchardef ('*', chartemp1);

     /* Single-series scatter chart */

     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.maintitle.title, "Goodstuff, Inc." );
     strcpy( env.xaxis.axistitle.title, "Employees" );
     strcpy( env.yaxis.axistitle.title, "Profitability" );
     _pg_chartscatter( &env, employees[0], profits[0], ITEMS );
     getch();
     _clearscreen( _GCLEARSCREEN );

     /* Multi-series scatter chart */

     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.xaxis.axistitle.title, "Employees" );
     strcpy( env.yaxis.axistitle.title, "Profitability" );
     _pg_chartscatterms( &env, (float far *)employees,
                         (float far *)profits, SERIES, ITEMS, ITEMS,
                         companies );
     getch();

     exit( !_setvideomode( _DEFAULTMODE ) );
 }


 285. /Zr Switch Causes Incorrect Code Generation

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C buglist2.00 buglist2.01 S_QuickASM
 Last Modified:  6-NOV-1989    ArticleIdent: Q49631

 When the /Zr switch is used to generate pointer checking instructions
 for Quick C, the generated code can cause problems with long
 arithmetic.

 The following example shows that the code generated with the /Zr
 switch can cause incorrect results:

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

 void main (void)
 {
   long *lp;
   lp = (long *)malloc(sizeof(long));
   *lp = 65530L;
   *lp += 65530L;
   if( *lp != (65530L + 65530L) )
   {
         printf("*lp not added correctly\n");
         exit(1);
   }
   else
   {
         printf("*lp added correctly\n");
         exit(0);
   }
 }

 When compiled without the /Zr switch, the code generated for the line
 "*lp += 65530;" is as follows:

     MOV     BX, WORD PTR [lp]
     ADD     WORD PTR [BX], -06  ; 65530
     ADC     WORD PTR [BX+02],+00

 When compiled with the /Zr switch, the code generated is as follows:

     MOV     BX, WORD PTR [lp]

     AND     BX, BX              ; Code inserted by /Zr
     JNZ     _main+3c (005C)     ;   "      "     "   "
     CALL    0010                ;   "      "     "   "

     ADD     WORD PTR [BX], -06  ; 65530

     AND     BX, BX              ; Code inserted by /Zr
     JNZ     _main+46 (0066)     ;   "      "     "   "
     CALL    0010                ;   "      "     "   "

     ADC     WORD PTR [BX+02],+00

 The problem with the inserted code is that the AND instruction sets
 the carry flag to 0 (zero). Therefore, prior to the ADC instruction,
 which adds in the initial state of the carry flag, the carry flag is
 set back to zero producing the incorrect results.

 Microsoft has confirmed this to be a problem with with QuickC Version
 2.00 and 2.10. We are researching this problem and will post new
 information as it becomes available.


 286. Expressions in Switch Block Must Be Integral

 Product Version(s): 1.00 1.01 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C docerr
 Last Modified: 17-JUL-1990    ArticleIdent: Q49756

 The "switch" statement is a control-flow statement that causes
 execution to jump to a different location based on case values. The
 destinations must be specified as integral values; therefore, they
 cannot evaluate to floats, doubles, or pointers. This is not
 documented in the on-line help facility.

 Code Example
 ------------

 switch (expression)             /* This expression must evaluate */
   {                             /*   to an integral value. */
     case constant_expression_1:
             statement body 1
             break ;

     case constant_expression_2:
             statement body 2
             break ;
     .
     .
     .
     case constant_expression_n:
             statement body n
             break ;

     default:
             statement
             break ;
   }


 287. Using Graphics in Mixed-Language Calls between QC and QB

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | b_quickbasic
 Last Modified: 17-JUL-1990    ArticleIdent: Q49779

 Problem:

 I want to use _imagesize(), _getimage(), and _putimage() in the C
 graphics library after loading the graphics image from QuickBASIC.

 Response:

 The C module does not recognize that the screen is in graphics mode if
 the video mode is set in the BASIC module. Instead, set the video mode
 in a C module using the following steps:

 1. Start from the main in BASIC.

 2. Call a C function to initialize the video mode.

 3. Return to BASIC and load in the graphics image.

 4. Call a C function to use functions from the C graphics library.

 For more information about QuickBasic and QuickC graphics
 compatibility, search on the following words:

    QuickBASIC and QuickC and link and graphic


 288. Not All Extended ASCII Characters Are Mapped by QuickC Fonts

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 17-JUL-1990    ArticleIdent: Q50339

 Problem:

 When I display the extended ASCII character set with a QuickC font,
 the characters do not match my chart for the characters. However, when
 I watch an array of the extended characters in the watch window, they
 are the same as my chart.

 Response:

 There are three parts to this response:

 1. What happens in the watch window, versions 2.00 and 2.01

 2. The fonts and Presentation Graphics (PG) default font in QuickC
    version 2.00

 3. The fonts and PG default font in QuickC Version 2.01

 What Happens in the Quick Environment
 Watch Window, Versions 2.00 and 2.01
 -------------------------------------

 The Quick environment's watch window uses the system character set,
 not fonts. The default system character set in the United States is
 codepage 437, a table of 256 character correspondence codes. Codepage
 437 matches the IBM extended character set so the watch window
 displays the standard characters.

 It is possible to override the default system character set with DOS's
 command to change codepage (CHCP). However, a call to _setvideomode()
 -- required when you use fonts -- will reset the system character set
 to the default.

 The Fonts and PG Chart Default Font in QuickC Version 2.00
 ----------------------------------------------------------

 The .FON files contain the ANSI character set, not the extended ASCII
 character set. They match the ASCII character set only from hex 20
 through hex 7E. When you use _outgtext() to display any of the
 extended characters, only characters from hex 20 through hex 7E will
 match your ASCII chart; for example, the function _outgtext() displays
 the ANSI characters. The function _outtext() displays the ASCII
 characters.

 The PG Chart default font uses a bitmap that is the same as codepage
 437. Extended characters you display with the default font will match
 the extended ASCII chart.

 The Fonts and PG Chart Default Font in QuickC Version 2.01
 ----------------------------------------------------------

 The .FON files are the same as Version 2.00 .FON files. However, in
 QuickC Version 2.01, the _outgtext() function maps the ANSI character
 set onto codepage 850. Codepage 850 is a multilingual character set
 (as distinct from codepage 437, which is the U.S. character set).

 While not an exact match of the extended ASCII character set, codepage
 850 matches more ASCII chart characters than the ANSI character set
 does. Specifically, codepage 850 and the ASCII chart share the
 accented vowels used in European languages. When you use _outgtext()
 to display extended characters using fonts in Version 2.01, more of
 the characters will match the ASCII chart than when you use Version
 2.00. (The function _outtext() displays the ASCII characters in
 Version 2.01 as it does in Version 2.00.)

 In Version 2.01 the PG Chart default font maps to codepage 850
 (instead of codepage 437).

 The QuickC .FON files are identical to the .FON files used in the
 Microsoft Windows operating environment. You can use any fonts files
 that are compatible with Windows with QuickC. You can find more
 information on fonts in "C for Yourself," Chapter 14, "Fonts."

 For more information on the ANSI characters, refer to Page 152 in
 "Programming Windows," Chapter 4, "The Keyboard."

 You can find additional information on codepages in "The MS-DOS
 Encyclopedia."


 289. Resizing QuickC and QuickPascal Windows Using Cursor Keys

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickAsm S_QuickPas Quick C
 Last Modified: 17-JUL-1990    ArticleIdent: Q49936

 The following steps will help you resize a window in QuickC 2.00 using
 the cursor keys:

 1. Use F6 to select the window to resize.

 2. Press CTRL+F8.

 3. Use the UP and DOWN ARROW keys to resize the window.

 4. Press the ENTER key to select the current size or press ESC to undo
    the window resize command.

 In QuickPascal Version 1.00, the following steps allow you to resize
 the windows:

 1. Use F6 to select the window to resize.

 2. Press CTRL+F8.

 3. Use the UP and DOWN ARROW keys to resize the window in any
    direction.

 4. Press the ENTER key to select the current size or press ESC to undo
    the window resize command.


 290. C2205: Cannot Initialize Extern Block-Scoped Variables

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickASM
 Last Modified:  6-NOV-1989    ArticleIdent: Q50212

 The error message "C2205 : <filename> : cannot initialize extern
 block-scoped variables" occurs when compiling a submodule that both
 declares and initializes an external global variable on the same
 statement line. This error is caused by the incorrect placement of a
 declaration.

 The following are two suggestions for proper declaration:

 1. The external declarations should be outside the submodule file
    scope (for example, move the declaration from the local area to the
    global area).

 2. Declare the external variable on one line, then initialize it on
    the next statement.

 The following program illustrates the compiler error when compiled
 with the C 5.10 optimizing compiler or QuickC Version 2.01.

 Program Sample
 --------------

 #include <stdio.h>

 int  n;                  /* global variable */
 void submodule (void);   /* routine in separate .OBJ file */

 void main (void)
 {
    submodule ();
    printf ("n = %d", n);
 }

 void submodule (void)
 {
    extern int n = 10;
 }

 Applying the two suggestions for proper declaration results in the
 following:

 1.
       extern int n = 10;

       void submodule (void)
       {
       }

 2.

       void submodule (void)
       {
       extern int n;
       n = 10;
       }


 291. C2205 : Cannot Initialize Extern Block-Scoped Variables

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QUICKASM
 Last Modified: 17-JUL-1990    ArticleIdent: Q50239

 The error message "C2205 : <filename> : cannot initialize extern
 block-scoped variables" occurs when compiling a submodule that both
 declares and initializes an external global variable on the same
 statement line. This error is caused by the incorrect placement of a
 declaration.

 The following are two suggestions for proper declaration:

 1. The external declarations should be outside the submodule file
    scope (for example, move the declaration from the local area to the
    global area).

 2. Declare the external variable on one line, then initialize it on
    the next statement.

 The following program illustrates the compiler error when compiled
 with the C 5.10 optimizing compiler or QuickC Version 2.01.

 Sample Program
 --------------

 #include <stdio.h>

 int  n;                  /* global variable */
 void submodule (void);   /* routine in separate .OBJ file */

 void main (void)
 {
    submodule ();
    printf ("n = %d", n);
 }

 void submodule (void)
 {
    extern int n = 10;
 }

 Apply the following two suggestions for proper declaration:

 1.
       extern int n = 10;

       void submodule (void)
       {
       }

 2.
       void submodule (void)
       {
       extern int n;
       n = 10;
       }


 292. QuickC .FON Files Identical to Windows .FON Files, Not .FNT

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm docerr QC
 Last Modified: 17-JAN-1990    ArticleIdent: Q50515

 Chapters 12-14 of the "C for Yourself" text is almost identical to
 Chapters 2-4 of the Version 2.00 "Microsoft QuickC Graphics Library
 Reference", but there is some conflicting information. In general, if
 there is a conflict of information, the graphics library reference is
 correct.

 On Page 265 of the "C for yourself" text and on Page 87 of the
 graphics library reference, the information on QuickC (QC) .FON font
 file compatibility is incorrect.

 QuickC's .FON files are identical to Windows .FON files, not .FNT
 files.

 This error in "C for yourself" is documented in the QuickC Version
 2.00 README.DOC file, Part 2, "Notes on 'C for Yourself.'"


 293. Default Optimization for QuickC Compiler Is /Od (None), Not /O

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM docerr
 Last Modified: 17-JAN-1990    ArticleIdent: Q50706

 Page 95 of the "Microsoft QuickC Tool Kit" manual that accompanies
 QuickC Version 2.00 and QuickC with QuickAssembler Version 2.01
 incorrectly states that the default optimization for the QuickC
 compiler is /Ot (or /O). QuickC does NO optimization by default. Thus,
 the default is /Od (no optimization).


 294. Executing QuickC Under Windows Operating Environment

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified: 17-JAN-1990    ArticleIdent: Q50715

 Question:

 When I execute QuickC 2.00 from the Windows environment, the mouse
 cursor does not appear on the screen. The cursor does appear when I am
 in the Windows environment. Is there a problem with the mouse in
 QuickC 2.00 when executing from a Windows program?

 Response:

 No. The Windows operating environments (Windows 286/386) have an
 internal mouse driver available to Windows operating
 environment-specific programs. QuickC 2.00 and 2.01 require the mouse
 driver supplied with QuickC 2.00 and 2.01 to be loaded.

 Since the mouse driver in the Windows environment is internal, only
 programs written specifically for the Windows environment can use the
 Windows mouse driver. All other DOS applications will have to load a
 mouse driver through DOS.

 If you have MOUSE.SYS, then in your CONFIG.SYS file, add the
 following:

    device=c:\mouse.sys

 If you have a MOUSE.COM, then type "mouse" at the DOS prompt or add
 the following line to your AUTOEXEC.BAT file:

    mouse


 295. QuickC 2.00: C1007: Switches Not Recognized by QCCOM

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm s_link
 Last Modified: 15-MAR-1990    ArticleIdent: Q51073
 The QuickC Version 2.00 environment does not recognize the following
 QuickC Version 2.00 switches in the CL environment variable:

    Switch      Operation                Workaround
    -------     ---------------------    ----------------------------

    /Fe         Names executable file    Not supported in environment.

    /Fo         Names object file        Not supported in environment.

    /Fm         Creates link map file    Set MAP FILE option in
                                         Options.Make Linker Flags.

    /FPi        Selects emulator libs    QC Default.

    /link       Passes linker options    Supported options can be set
                                         in Options.Make Linker Flags.

    /Oailt      Specifies Optimizations  QC does not recognize options
                                         in combined form. Separate
                                         options (i.e., /Ot /Oa /Ol).

    /Lr         Specifies real mode lib  Not supported in environment.

    /Lc         Specifies real mode lib  Not supported in environment.

    /Lp         Specifies prot mode lib  Not supported in environment.

 Using any of these switches results in the following fatal error
 message, where <switch> is the switch in the CL environment variable:

    fatal error C1007: Unrecognized flag '<switch>' in 'qccom'

 The QCL command-line compiler will accept these switches.


 296. _arc() Generates Run-Time Error R6003

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist5.10 buglist2.00 buglist2.01 s_c
 Last Modified: 17-JAN-1990    ArticleIdent: Q51124

 The C run-time function _arc() will generate the following error
 message if the sum of the absolute value of each coordinate in the
 bounding rectangle is greater than 32767:

    run-time error R6003
    -integer divide by 0

 For example, the function is prototyped with the following parameters:

    short far _arc (x1, y1, x2, y2, x3, y3, x4, y4);

 For the function to work properly, the following statement must be
 true:

    |x1| + |x2| <= 32767
    |y1| + |y2| <= 32767

 The following program generates the R6003 error message:

 #include <stdio.h>
 #include <graph.h>

 /* COMMAND LINE:
 */

 main()
 {
       _setvideomode ( _VRES16COLOR );
       _arc ( -20000, -120, 12768, 4480, 342, 346, 205, 315 );
       getch();
       _setvideomode ( _DEFAULTMODE );
 }

 Microsoft has confirmed this to be a problem in QuickC Versions 2.00
 and 2.01 and in C Version 5.10. We are researching this problem and
 will post new information here as it becomes available.


 297. "C For Yourself" Documentation Error -- Long Double

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr s_quickasm
 Last Modified: 17-JAN-1990    ArticleIdent: Q51125

 On Page 48 (fourth paragraph from the bottom) of the "C for Yourself"
 manual, it states that a long double has 19 digits of precision. This
 statement is incorrect.

 A long double has 15 digits of precision and is the same as a double
 in the current implementation. The same error occurs on the following
 page (Page 49) under Table 4.1.


 298. Shift Left Assignment Operator "<<=" Does Not Work Correctly

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC S_QUICKASM buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q51472

 The shift left assignment operator, "<<=", does not operate correctly
 on variables that are not in the default data segment in the small and
 medium memory models.

 The following code reproduces the problem:

 #include<stdio.h>

 /* must be compiled in small or medium memory model */

 /* variables must be declared global so that "far"  */
 /* modifier will not be ignored                     */

 int a = 1;           /*  int "a" will be in default data segment */
 int far b = 1;       /*  int "b" declared "far" in far segment   */

 void main( void )
 {
    a <<= 4;          /*  left shift 4 of 1 should be 16          */
    b <<= 4;          /*  this operation causes bad value         */
    /*  output results  */
    printf( "A: %d (should be 16)\nB: %d (should be 16)\n", a, b );
 }

 Output:

 A: 16 (should be 16)
 B: 1 (should be 16)

 The reason that the bad value is returned is that the left shift
 operation always assumes a near pointer in the small and medium memory
 models, i.e., only an OFFSET value. When performed on a far value, the
 address of that value is truncated to be only an OFFSET instead of
 SEGMENT:OFFSET, and the segment becomes the default data segment. The
 resulting pointer points to an unpredictable point in that data
 segment, and the operation is carried out there instead of on the
 intended value. In the large and compact memory models, the shift
 operation performs as desired.

 To work around the problem, the program should be recompiled in the
 large or compact memory model, or the left shift operation should be
 rewritten as follows:

    b = b << 4;

 Microsoft has confirmed this to be a problem with the QuickC compiler
 Versions 2.00 and 2.01. We are researching this problem and will post
 new information here as it becomes available.


 299. Run-Time Function fabs() Is Prototyped in MATH.H

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr S_QUICKASM
 Last Modified: 14-MAR-1990    ArticleIdent: Q51528

 The on-line help in QuickC 2.00 and QuickAssembler 2.01 incorrectly
 states that the run-time function fabs() is prototyped in the STDLIB.H
 header file. The function is actually prototyped in the MATH.H header
 file.

 The other two run-time functions abs() and labs() are prototyped in
 STDLIB.H header file.


 300. QuickC 1.0x and the CL= and LINK= Environment Settings

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JAN-1990    ArticleIdent: Q51612

 You can add QCL command-line options to the default options that the
 QuickC Versions 1.00 and 1.01 environments use when building a program
 by setting an environment variable called CL at the DOS prompt. For
 example, if at the DOS prompt you type

    set cl=/FPi87

 the QuickC compiler will generate floating point instructions and
 select an 8087/80287/80387 library. Similarly, you can set linker
 options by setting the LINK= variable at the DOS prompt. If you type

    set link=/M

 each time you execute the QuickC linker, it will create a linker map
 for your source file that contains all global symbols in your source
 code. Now, if you type

    link foo.obj

 the linker will actually add the /M flag to its list of options for
 this execution. The linker will now do the same things it would do if
 you had typed the following:

    link /M foo.obj

 However, there are a few situations when the QuickC environment does
 not react as you might expect to setting environment variables. Three
 of these software limitations are described below:

 1. The CL= variable is not checked if there are multiple modules in
    the program list.

 2. You will not receive an error message if you have an invalid
    setting for the CL= variable with or without a program list.

 3. Settings for the LINK= environment variable are ignored entirely by
    the environment.

 All of these limitations have been corrected in QuickC Versions 2.00
 and 2.01. In each of these cases, the environment variable settings
 are found correctly in QuickC Versions 2.00 and later.

 1. CL= not checked in multiple-module programs.

    QuickC Versions 1.00 and 1.01 fail to look at the environment table
    for a CL environment variable if there is more than one source
    module in the program list. Even if you edit the makefile to add
    the option to the list of QCL options, QuickC will not look at the
    changed options, but will compile with the default options in the
    original makefile.

    The following sequence of events will demonstrate this limitation.
    These steps will attempt to force QuickC to use the MLIBC7.LIB
    library. If this library is in your LIB subdirectory, temporarily
    rename it so that QuickC cannot find it. Also rename the MLIBCE.LIB
    file so that you are prompted for it at link time.

    a. At the DOS prompt, type the following:

          set cl=/FPi87

    b. Create one source code module as follows:

          /* FOO.C */
          #include <stdio.h>
          void other(void);
          void main(void)
          {
               printf("Executing main procedure.\n");
               other();
          }

    c. Create another source module as follows:

          /* OTHER.C */
          #include <stdio.h>
          void other(void)
          {
               printf("Executing other module.\n");
          }

    d. Set a program list for FOO.C that contains FOO.C and OTHER.C.

    e. Build the program from the environment.You are prompted for the
       MLIBCE.LIB library instead of MLIBC7.LIB, as you would expect.
       QuickC has ignored the CL= environment variable.

 2. Environment ignores invalid flag.

    If you set the CL= variable to an invalid option, the QuickC
    environment ignores the flag even if you are in a single module
    program.

    a. Type the following line at the DOS prompt:

          set cl=/JUNK

    b. Create the following file:

          /* HELLO.C */
          #include <stdio.h>
          void main(void)
          {
               printf("Hello?!\n");
          }

    c. Build the program from within the environment. The environment
       should give you an error concerning the invalid switch, but it
       does not.

 3. Environment ignores LINK= flag.

    a. Type the following line at the DOS prompt:

          set link=/M

    b. Build HELLO.C (above) from within the environment.

    c. Exit to DOS and notice that there is no HELLO.MAP file created.
       You can also set the LINK= variable to a junk setting and notice
       that you still receive no invalid flag errors.

    Notice that these errors occur only when you build a new program in
    the environment. If you compile and link at the DOS prompt, the
    environment settings are found correctly.


 301. QuickC Err Msg: Cannot Load Binary File

 Product Version(s): 1.00 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist1.00 buglist1.01 buglist2.00 buglist2.01
 Last Modified: 21-MAR-1990    ArticleIdent: Q51638

 Microsoft QuickC Versions 1.0x and 2.0x are unable to open data files
 created by fopen() and written to by fprintf() functions.

 The following program demonstrates this problem:

      #include <stdio.h>

      FILE *fooptr;

      void main (void)
      {
           fooptr = fopen ("foo.dat","wt");

           if (fooptr == NULL)
                puts ("Can't open file.");

           fprintf (fooptr, "This is a test");

           fclose (fooptr);
      }

 After running the program, load "foo.dat" into the QuickC environment.
 QuickC will report back with the following:

    Cannot load binary file:
              foo.dat

 Use the DOS TYPE command to see that the data file was written in text
 format. This file can also be loaded by other text editors such as the
 Microsoft Editor.

 Running CRLF.EXE to translate or remove any control characters does not
 resolve this problem.

 Microsoft has confirmed this to be a problem with QuickC Versions
 1.00, 1.01, 2.00, 2.01. We are researching this problem and will post
 new information here as it becomes available.


 302. QuickC 2.00: /Ot Code Generation Error

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01
 Last Modified: 21-MAR-1990    ArticleIdent: Q51642

 The following small program, when compiled under QuickC Version 2.00
 or 2.01, with /Ot included in the optimizations, generates the wrong
 code.

 With /Ot, the output is as follows:

    array [0] = 0

 The correct output is as follows:

    array [0] = 1

 The error occurs in the code generated for the following:

    array[index] = test;

 /* Ot.c: /Ot optimization error */

 #include <stdlib.h>
 #include <stdio.h>

 int array[4];

 void main(void)
 {
      int index = 0,
           test;

      test = atoi("1");

      array[index] = test;

      printf("array [%d] = %d \n", index, array[index]);
 }

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.


 303. Use _pg_setpalette() to Modify the Plot Characters

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | presentation graphics pgchart
 Last Modified: 17-JAN-1990    ArticleIdent: Q51654

 To modify the default character used for plotting line and scatter
 charts, use the _pg_getpalette() and _pg_setpalette() functions. These
 functions expect a variable of type palettetype, which is an array of
 structures (defined in pgchart.h). Palettes are discussed in Section
 3.4 of the "Microsoft QuickC Graphics Library Reference" manual for
 Version 2.00. Below is an an example of how to use _pg_setpalette to
 modify the default plot character for single and multiseries charts.

 /* PLOTCHAR.C - Modifies the default plotting characters.      */
 /* Note: To modify the array, start with index 1 -- see below. */

 #include <conio.h>
 #include <graph.h>
 #include <string.h>
 #include <stdlib.h>
 #include <pgchart.h>

 #define ITEMS  5
 #define SERIES 2
 float far employees[SERIES][ITEMS] = {{235.0F, 423.0F, 596.0F,
                                        729.0F, 963.0F},
                                       {285.0F, 392.0F, 634.0F,
                                        801.0F, 895.0F}};

 float far profits[SERIES][ITEMS] =   {{0.9F,  2.3F,  5.4F,
                                        8.0F,  9.3F},
                                       {4.2F,  3.4F,  3.6F,
                                        2.9F,  2.7F}};

 char far *companies[SERIES] = { "Goodstuff, Inc.", "Badjunk & Co."};

 /* This type is defined in pgchart.h */
 palettetype pal ;

 void main( void )
 {
     chartenv env;
     short mode = _VRES16COLOR;

     while( !_setvideomode( mode ) )
         mode--;
     if (mode == _TEXTMONO )
         exit( 1 );

     _pg_initchart();

     /* Single-series scatter chart */

     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.maintitle.title, "Goodstuff, Inc." );
     strcpy( env.xaxis.axistitle.title, "Employees" );
     strcpy( env.yaxis.axistitle.title, "Profitability" );

     /* Get old palette and modify plotchar for first series */
     _pg_getpalette( pal ) ;
     pal[1].plotchar = '+' ;
     _pg_setpalette( pal ) ;

     _pg_chartscatter( &env, employees[0], profits[0], ITEMS );
     getch();
     _clearscreen( _GCLEARSCREEN );

     /* Multi-series scatter chart */

     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.xaxis.axistitle.title, "Employees" );
     strcpy( env.yaxis.axistitle.title, "Profitability" );

     /* Get old palette and modify plotchar for second series */
     _pg_getpalette( pal ) ;
     pal[2].plotchar = 'X' ;
     _pg_setpalette( pal ) ;
     _pg_chartscatterms( &env, (float far *)employees,
                         (float far *)profits, SERIES, ITEMS, ITEMS,
                         companies );
     getch();

     exit( !_setvideomode( _DEFAULTMODE ) );
 }


 304. /Ot Generates Incorrect Code on JMP SHORT $+2

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01 s_quickasm
 Last Modified: 17-JAN-1990    ArticleIdent: Q51708

 In the example below, with the following compile options

    /AS /G2 /Ot /Zp2

 a reference to the "$" (current location counter) symbol from within
 the scope of an _asm directive results in an incorrect assignment.
 This problem occurs with QuickC Versions 2.00 and 2.01.

 With any optimization switch other than /Ot, the short jump is
 correctly resolved to $+2. With /Ot, the short jump is incorrectly
 resolved to _main+2.

 To work around the problem, compile and link separately. Compile with
 /Zi (embedding CodeView information, thus altering the code
 generation) and link without /CO (so that the CodeView information is
 not passed to the .EXE file).

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.

 The following example demonstrates the problem:

 main()
 {
    _asm
    {
       MOV DX, 0x21
       IN  AL, DX
       JMP SHORT $+2
       OR  AL, 0x10
       OUT DX, AL
    }
 }


 305. Locals Can Be Viewed Only When Compiling with CodeView Info

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified: 14-MAR-1990    ArticleIdent: Q51746

 For debugging purposes, Microsoft QuickC Versions 2.00 and 2.01 allow
 you to open a watch window that displays all the local variables
 currently in scope by selecting the View.Windows.Locals menu options.
 The information in this window is generated from CodeView debugging
 information. Therefore, you must compile and link with the CodeView
 flag set in the "Debug Flags" sections of both the
 Options.Make.Compiler Flags menu and the Options.Make.Linker Flags
 menu to be able to see the local variable information.

 The locals window is accessible only if you have set the Full Menus
 option on the Options menu. To see how CodeView information affects
 the locals window, compile the following program after turning
 CodeView information off in the Options.Make.Compiler Flags menu. Open
 the locals window, then press F8 to begin tracing into the main
 procedure and note that no locals are viewable. Recompile after
 turning CodeView information on, and locals will then be available.
 This is expected behavior for Microsoft QuickC.

 Code Example
 ------------

 #include<stdio.h>

 void main( void )
 {
    int   test1=5;
    float test2=3.6;

    printf( "This is a test...\n" );
 }


 306. C1126 - <Identifier>: Automatic Allocation Exceeds <Size>

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM
 Last Modified: 17-JAN-1990    ArticleIdent: Q51763

 The QuickC Versions 2.00 and 2.01 error

    C1126 - <identifier>: automatic allocation exceeds <size>

 is similar to the C2126 error in C 5.10 as well as QuickC 1.0x. In
 each case, it indicates that the space allocated for the local
 variables of a function exceeds the given limit (usually 32K).
 However, in QuickC 2.00 or 2.01, the error is fatal (hence, the C1xxx
 id).

 The error is documented in the QuickC 2.00 or 2.01 "Microsoft QuickC
 Tool Kit Version 2.0" manual, Page 232.

 When the compiler encounters this error, it stops parsing the program
 and outputs any error messages found up to that point. No object file
 is produced.


 307. QuickC Environment Does Not Control Output Scrolling

 Product Version(s): 1.00 1.01 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified: 17-JAN-1990    ArticleIdent: Q51833

 QuickC Versions 1.00, 1.01, 2.00, and 2.01 does not scroll the output
 window when running a program in the environment. QuickC displays a
 frame-like fixed window on top of the DOS screen. If the DOS screen
 scrolls, the display will scroll through the output window. Likewise,
 if the DOS screen does not scroll, the display will not scroll through
 the output window.

 To illustrate QuickC's behavior with the output window, follow the
 steps below:

 1. Write a program to print numbers 1-100 on the screen and then
    compile the sample program to generate a SAMPLE.EXE file. For
    example:

       use: printf("%d\n", num);  /* don't forget the "\n" */)

 2. From the DOS prompt clear the screen with "cls".

 3. Run your program and DOS will start to scroll the screen when the
    screen runs out of lines to display the output.

 4. Clear the screen once again as in Step 2.

 5. Invoke QuickC and open the output window (View.Window.Output with
    full menus). Single step through the print loop and watch the
    output window. It will behave exactly the same as the actual output
    screen.


 308. "Error C2410: 'var' : Ambiguous Member Name Operand 2"

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.01
 Last Modified: 14-MAR-1990    ArticleIdent: Q51835

 The following code generates the following error:

    file.c(x) : error c2410: 'var' : ambiguous member name operand 2

 Code Example
 ------------

 void main (void)
 {
      struct tag1
      {
           int  member;   <---|
      } name1;                |
                              |---- two different structures with
      struct tag2             |     same member name
      {                       |
           int  member;   <---|
      } name2;

      _asm      mov  bx, name2.member;
 }

 The compiler is confused by the two members with the same name.
 However, this behavior is observed only when referencing the structure
 member in an in-line assembly statement. If the member is referenced
 in a C statement, no error will occur. The only current workaround is
 to have different member names.

 Microsoft has confirmed this to be a problem in QuickC Version 2.10.
 We are researching this problem and will post new information here as
 it becomes available.


 309. _PG_CHART Fails to Graph Some Y-Axis Categories

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc
 Last Modified: 21-MAR-1990    ArticleIdent: Q51866
 _PG_CHART sometimes fails to correctly graph all y-axis values. The
 program included below demonstrates this problem. The lowest bar on
 the chart should be labeled n-1 with n assumed at the origin. However,
 when n is equal to the following values

    28, 30, 44, 45, 48, 51, 52, 56, 60, 63, 66, 69, 74,
    75, 78, 79, 80, 84, 85, 88, 90, 91, 92, 95, and 96.

 the graph actually drawn has n-2 as the lowest bar. This is
 independent of the video mode setting.

 The following program demonstrates the problem:

 #include <conio.h>
 #include <graph.h>
 #include <pgchart.h>

 float far value[] = {1.0f,2.0f,3.0f,4.0f,5.0f,6.0f,7.0f,8.0f,9.0f,
                      10.0f,11.0f,12.0f,13.0f,14.0f,15.0f,16.0f,17.0f,
                      18.0f,19.0f,20.0f,21.0f,22.0f,23.0f,24.0f,25.0f,
                      26.0f,27.0f,28.0f,29.0f,30.0f,31.0f,32.0f,33.0f,
                      34.0f,35.0f,36.0f,37.0f,38.0f,39.0f,40.0f,41.0f,
                      42.0f,43.0f,44.0f,45.0f,46.0f,47.0f,48.0f,49.0f,
                      50.0f,51.0f,52.0f,53.0f,54.0f,55.0f,56.0f,57.0f,
                      58.0f,59.0f,60.0f,61.0f,62.0f,63.0f,64.0f,65.0f,
                      66.0f,67.0f,68.0f,69.0f,70.0f,71.0f,72.0f,73.0f,
                      74.0f,75.0f,76.0f,77.0f,78.0f,79.0f,80.0f,81.0f,
                      82.0f,83.0f,84.0f,85.0f,86.0f,87.0f,88.0f,89.0f,
                      90.0f,91.0f,92.0f,93.0f,94.0f,95.0f,96.0f,97.0f,
                      98.0f,99.0f,100.0f};

 char far *category[] ={"1","2","3","4","5","6","7","8","9","10","11",
                         "12","13","14","15","16","17","18","19","20",
                         "21","22","23","24","25","26","27","28","29",
                         "30","31","32","33","34","35","36","37","38",
                         "39","40","41","42","43","44","45","46","47",
                         "48","49","50","51","52","53","54","55","56",
                         "57","58","59","60","61","62","63","64","65",
                         "66","67","68","69","70","71","72","73","74",
                         "75","76","77","78","79","80","81","82","83",
                         "84","85","86","87","88","89","90","91","92",
                         "93","94","95","96","97","98","99","100"};
 void main(void)
 {
     int i = 27;
     chartenv env;
     short mode = _HRES16COLOR;
     _setvideomode(mode);
     _pg_initchart();                 /* Initialize chart system */
     for (; i<101; i++)
     {
      _pg_defaultchart(&env, _PG_BARCHART, _PG_PLAINBARS);
      _pg_chart(&env, category, value, i);
      getch();
     }
     _setvideomode(_DEFAULTMODE);
 }

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


 310. File Not Found: line#.c While Viewing Errors

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q52037

 While viewing errors in the QuickC environment, it is possible to get
 a pop-up error message that looks similar to the following

            __________________________
           |                          |
           |     File not found:      |
           |         C:\##.c          |
           |--------------------------|
           |    < OK >    < HELP >    |
           |__________________________|

 where ## is the line that the error occurred on before it was erased.

 This error occurs only if you delete the line that the error was found
 in before trying to view the now deleted line with SHIFT+F3.

 Microsoft has confirmed this to be a problem in QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.

 Sample Code
 -----------

 1:  void main (void)
 2:     {
 3:     printf()  /* Causes fatal error since there's no semicolon. */
 4:     }

 To see the pop-up error message, use the following steps:

 1. Compile the above program using the QuickC environment.

 2. After the compilation has aborted due to the fatal error, delete
    the line that caused the error (in this case it is line #3).

 3. Press SHIFT+F3 to view the next error. The pop-up error message
    should now be on your screen.


 311. /Zr Generates Error When Assigning to Video Memory

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JAN-1990    ArticleIdent: Q52101

 Question:

 Why does the following code generate run-time error R6013 (illegal far
 pointer use) for the second reference to farptr, but not the first,
 when compiled with /Zr or when compiled within the QuickC environment
 with pointer checking turned on?

 Sample Code
 -----------

 void main(void)
 {
     int far *farptr;
     int n=0;
     farptr=(int far *)0xb8000000lu;
     *(farptr+n)=177 | 0x0700; /* no error */
     n=12;
     n -= 11;
     *farptr=178 | 0x0700;      /* error  */
 }

 Response:

 This is expected behavior from the /Zr option.

 The code generated for pointer checking (/Zr) checks for out-of-range
 pointers. As farptr is pointing to segment b800 (video memory), it
 assumes that this is an error because b800 is larger than the variable
 __asegh, which is defined as the highest segment in memory owned by
 the program.

 This variable gets updated if an _fmalloc, for example, allocates a
 new segment higher than __asegh. When an assignment is made, for
 instance "farptr=0xb8000000", __asegh is not modified.

 Therefore, when the pointer assignment is made and the code is
 generated to check for invalid pointers, the compiler thinks that this
 pointer is invalid, since its segment (0xb800) is greater than
 __asegh.

 To use this code, you need to compile without /Zr (or turn off pointer
 checking in the environment) when assigning pointers to memory higher
 than the value __asegh. (Similarly, __aseglo marks the lowest segment
 in use in memory.) This is valid code.

 The pointer checking does not have any effect on the line *(farptr+n)
 in the code because, since QuickC is a one pass compiler, QuickC
 recognizes this line as one of incremental nature; its purpose in this
 case is to increment the pointer. Due to the precedence of the "()"
 over the "*" operator, and since this is a line of incremental nature,
 QuickC does not generate the code to check the segment and offset with
 _asegh and _aseglo.

 It does generate the correct code to make the assignment; however, it
 is too late to then generate the code for the segment:offset checking.


 312. Accessing Strings from Local (Stack) Pointers with _asm

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified: 17-JAN-1990    ArticleIdent: Q52139

 To access strings and other variables through auto pointers using the
 _asm keyword, WORD PTR should be used in place of OFFSET. The WORD PTR
 keyword will access the memory pointed to by the operand of the WORD
 PTR. This results in the desired indirection. See the program example
 below

 Program Example
 ---------------

 /* STRING.C -- compile with /AS (small memory model)
 /* Notice the added \r and $ are added for int 21  */

 char string_var1[] = "This is string 1\r\n$" ;

 void main ( void )
 {
   char *string_var2 = "This is string 2\r\n$" ;
   _asm {
     push dx

     mov dx, word ptr string_var2
     mov ah, 09h
     mov al, 00h
     int 21h

 ; Notice that offset is used properly below (with the array).
 ; In the case of *string_var1 (instead of string_var1[]),
 ; word ptr should again be used as above.
     mov dx, offset string_var1 ;
     mov ah, 09h
     mov al, 00h
     int 21h

     pop dx
   }
 }


 313. PG Chart Legend Window Is Restricted to Default Coordinates

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q52140

 In Microsoft QuickC Versions 2.00 and 2.01 Presentation Graphics, the
 size of the legend window (like the key on a map) is restricted to the
 default. Setting "env.legend.autosize=FALSE" and manually setting
 coordinates prevents the chart from being displayed. Also, the global
 variable, errno, is set to 105, meaning "Invalid legend window
 specified."

 Microsoft has confirmed this to be a problem in QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.

 The example below demonstrates the problem:

 /* PIE.C:  Create sample pie chart.  */
 #include <conio.h>
 #include <string.h>
 #include <graph.h>
 #include <pgchart.h>

 #define MONTHS 12

 typedef enum {FALSE, TRUE} boolean;

 float far value[MONTHS] =
 {
    33.0, 27.0, 42.0, 64.0,106.0,157.0,
   182.0,217.0,128.0, 62.0, 43.0, 36.0
 };
 char far *category[MONTHS] =
 {
   "Jan", "Feb", "Mar", "Apr",
   "May", "Jun", "Jly", "Aug",
   "Sep", "Oct", "Nov", "Dec"
 };
 short far explode[MONTHS] = {0};

 main()
 {
   chartenv env;
   int mode = _VRES16COLOR, errno = 0;

   /* Set highest video mode available */
   printf ("This section displays a chart\n");
   getch();
   while(!_setvideomode( mode ))
      mode--;
   if(mode == _TEXTMONO)
      return( 0 );

   /* Initialize chart library and a default pie chart */
   _pg_initchart();
   _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );

   /* Add titles and some chart options */
   strcpy( env.maintitle.title, "Good Neighbor Grocery" );
   env.maintitle.titlecolor = 6;
   env.maintitle.justify = _PG_RIGHT;
   strcpy( env.subtitle.title, "Orange Juice Sales" );
   env.subtitle.titlecolor = 6;
   env.subtitle.justify = _PG_RIGHT;
   env.chartwindow.border = FALSE;

   if(( errno = _pg_chartpie( &env, category, value,
                     explode, MONTHS )) != 0)
   {
      _setvideomode( _DEFAULTMODE );
      _outtext( "Error:  can't draw chart" );
      printf ("\nerrno = %d\n", errno);
   }
   else
   {
      getch();
      _setvideomode( _DEFAULTMODE );
   }

   printf ("The autosize coordinates are:\n");
   printf ("x1 = %d  y1 = %d  x2 = %d  y2 = %d\n",
           env.legend.legendwindow.x1,
           env.legend.legendwindow.y1,
           env.legend.legendwindow.x2,
           env.legend.legendwindow.y2);
   printf ("The following section will fail to display a chart\n"
           "even though I set manual coordinates = autosize coordinates\n");
   getch();
   _setvideomode( mode );
   env.legend.autosize = FALSE;
   env.legend.legendwindow.x1 = 573;
   env.legend.legendwindow.y1 = 36;
   env.legend.legendwindow.x2 = 631;
   env.legend.legendwindow.y2 = 192;
   if(( errno = _pg_chartpie( &env, category, value,
                     explode, MONTHS )) != 0)
   {
      _setvideomode( _DEFAULTMODE );
      _outtext( "Error:  can't draw chart" );
      printf ("\nerrno = %d\n", errno);
   }
   else
   {
      getch();
      _setvideomode( _DEFAULTMODE );
   }
   printf ("The manual coordinates are:\n");
   printf ("x1 = %d  y1 = %d  x2 = %d  y2 = %d\n",
           env.legend.legendwindow.x1,
           env.legend.legendwindow.y1,
           env.legend.legendwindow.x2,
           env.legend.legendwindow.y2);
    return(0);
 }


 314. Optimization Can Cause Integer Division to Always Return 1

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q52198

 When optimizing code under QuickC (using either the Options menu from
 within the environment, or the -Ot or -Ox switches from the command
 line), integer division can generate incorrect code. This occurs only
 when all of the following conditions are satisfied:

 1. The -Ot or -Ox optimization level is chosen.

 2. The dividend and the divisor are both variables.

 3. The divisor is the product of a multiply (or shift) operation that
    immediately precedes the division.

 To work around this problem, compile modules that meet all the above
 criteria with either -Od or -Ol.

 When this problem occurs, the divisor is being divided into itself.
 Therefore, if the returned value for the division is not exclusively
 1, you are not experiencing this problem.

 The sample program below demonstrates the problem. Microsoft has
 confirmed this to be a problem in QuickC Versions 2.00 and 2.01. We
 are researching this problem and will post new information here as it
 becomes available.

 The following program demonstrates this problem when compiled as
 specified (compile the module with either -Od or -Ol to generate code
 that runs correctly):

 /*
     DIVISION.C
     Compile: qcl -Ot (or -Ox) division.c
 */

 #include <stdio.h>

 void main ( void )

 {
     int a, b, c, d ;

     a = 100 ;
     b = 5 ;
     c = b*5 ;
     d = a/c ;

 /*
     When compiling with -Ot or -Ox, the failed error message will
     result AND the value of d will be set to one.
 */

   if (d == 4)
     printf("Success, d is %d, should be 4!\n", d) ;
   else
     printf("Failed, d is %d, should be 4!\n", d) ;

 }


 315. Inline Assembly May Cause Debugger to Skip Lines

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q57220

 The following code causes the debugger to skip (or jump) over a line
 of source code. The statement that causes this action is the "_asm in
 ax,21h;" inline assembly statement. This problem happens only when you
 are debugging with the integrated debugger and loading the 21h port
 using the "in" instruction. If you run the program from the DOS
 prompt, the program will execute properly.

 Code Example
 ------------

  1: void main (void)
  2:    {
  3:    _asm in ax, 21h;
  4:    printf ("Test1\n");
  5:    printf ("Test2\n");
  6:    }

 Compile the above program and trace through it using F8. Line #4 will
 be skipped. The "_asm in ax,21h;" inline assembly statement is what
 causes the line to be skipped; however, this program will run as
 expected when executed outside the integrated environment. It will
 also run as expected from within the environment as long as the trace
 (F8) command is not used.

 Microsoft has confirmed this to be a problem in Versions 2.00 and
 2.01. We are researching this problem and will post new information
 here as it becomes available.


 316. Graphics Library Code Limited to One Code Segment

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JAN-1990    ArticleIdent: Q57482

 The total amount of code an application calls from the graphics
 library must not exceed 64K in length. Therefore, if many different
 graphics functions are called from GRAPHICS.LIB and/or PGCHART.LIB,
 there is a possibility that you will receive the following link error
 message:

    l1070 segment size exceeds 64K

 This limitation is related to the fact that the graphics library was
 built to be compatible with all memory models. The graphics library
 forces the use of the segment _TEXT for its code because all memory
 models can access this segment. As a result, if too many different
 graphics library functions are called, this segment may overflow and
 the only workaround is to reduce the number of functions needed from
 the graphics libraries.


 317. The Suffix "F" or "f" Causes a Syntax Error for Floats

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr s_quickasm
 Last Modified: 17-JAN-1990    ArticleIdent: Q57483

 On Page 50 (third entry from the bottom of Table 4.2) and Page 51
 (second paragraph) of the "C For Yourself" manual, it incorrectly
 states that a float can be a number that has the suffix "F" or "f".
 For example:

    float a = 123F;

 This causes the following error at compile time:

    C2061: syntax error:

 The correct syntax is as follows:

    float a = 123.0F
 or
    float a = 123.F
 or
    float a = 123e0F

 According to the ANSI specifications (3.1.3.1 Floating constants), "F"
 and "f" are used to force a variable to be a float instead of a
 double. However, the suffix alone is not enough and the decimal point
 or "e" notation is required.


 318. Cannot Move Upper Left Corner in PG Chart Scatter Functions

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm chart
 Last Modified: 17-JAN-1990    ArticleIdent: Q57511

 By changing the defaults in the windowtype structure, you can
 customize charts for use in Presentation Graphics (PG) as described in
 "C for Yourself" on Pages 251-260. However, when changing the default
 values for x1 and y1 in the windowtype structure for use with the
 _pg_chartscatter or _pg_chartscatterms functions, the function will
 either ignore the change, or fail.

 By changing the value for x1 in the windowtype structure, you can set
 the location of the left edge of the window. By changing y1, you can
 change the location of the top edge of the window. If you change one
 and not the other, the change will be ignored. If you change both of
 them, the chart scatter functions will fail and return 107, which
 means "chart window is too small." The following program demonstrates
 the problem:

 Sample Program
 --------------

 /*
  * This is part of the sample program, SCAT.C, from the online help
  * of QuickC 2.00 and QuickC 2.01.
  */

 #include <conio.h>
 #include <graph.h>
 #include <string.h>
 #include <stdlib.h>
 #include <pgchart.h>

 #define ITEMS  5
 #define SERIES 2

 float far employees[SERIES][ITEMS] = { { 235., 423., 596., 729., 963. },
                                        { 285., 392., 634., 801., 895. } };
 float far profits[SERIES][ITEMS] =   { { 0.9,  2.3,  5.4,  8.0,  9.3  },
                                        { 4.2,  3.4,  3.6,  2.9,  2.7  } };
 char far *companies[SERIES] = { "Goodstuff, Inc.", "Badjunk & Co." };

 void main(void)
 {
     int x;       /* for return value from _pg_chartscatter() */
     chartenv env;
     short mode = _VRES16COLOR;

     while( !_setvideomode( mode ) )     /* Find a valid graphics mode   */
         mode--;
     if (mode == _TEXTMONO )
         exit( 1 );                      /* No graphics available     */

     _pg_initchart();                    /* Initialize chart system   */

     /* Single-series scatter chart */
     _pg_defaultchart (&env, _PG_SCATTERCHART, _PG_POINTONLY );
     strcpy( env.maintitle.title, "Goodstuff, Inc." );
     strcpy( env.xaxis.axistitle.title, "Employees" );
     strcpy( env.yaxis.axistitle.title, "Profitability" );

 /*  Change the value for x1 and y1.  Note that if only one is changed, the
     value will be ignored.  If both are changed, _pg_chartscatter will fail *

     env.chartwindow.x1 = 1;  /* left */
     env.chartwindow.y1 = 1;  /* top  */

     x = _pg_chartscatter( &env, employees[0], profits[0], ITEMS );
     if (x != 0)
         printf("error! chartscatter returned %d\n",x);
     getch();
     _clearscreen( _GCLEARSCREEN );

     exit( !_setvideomode( _DEFAULTMODE ) );
 }


 319. Cannot Print Source Code If Notepad or Errors Window Active

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00
 Last Modified: 17-JAN-1990    ArticleIdent: Q57512

 Printing source code while the active window is either the Notepad or
 Errors window will produce unexpected results in QuickC 2.00 and 2.01.
 If you choose the Print option (ALT+F P) and select Source File, only
 a portion of your source code will be printed.  Printing from within
 the Debug, Locals, Registers, Help and Output windows will print the
 entire file.

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information here as
 it becomes available.

 If you select File.Print.Source File from within the Notepad window,
 QuickC will print lines of source code equal to the number of lines
 plus one (or two) in the Notepad window.

 Printing from the Errors window produces similar results. If there are
 no errors in the Error window, two lines of the source code will be
 printed. If there are errors in the window, QuickC will print lines of
 source code equal to the number of errors plus one.


 320. Misspelling "mov" in _asm Creates C4405 and C2400

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01
 Last Modified: 17-JAN-1990    ArticleIdent: Q57513

 When using the inline assembly features of QuickC Versions 2.00 and 2.01,
 incorrectly typing "mov" as "move" will create C4405 and C2400.

 The following code demonstrates the problem:

 Sample Code
 -----------

 void main(void)
 {
      _asm move al, 0
 }

 Compiling this file returns the following two messages:

    C4405: 'al': identifier is reserved word
    C2400: inline syntax error opcode, found 'al'

 Microsoft has confirmed this to be a problem in Versions 2.00 and
 2.01. We are researching this problem and will post new information
 here as it becomes available.


 321. Casting Pointer Subtraction May Yield Incorrect Code

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-FEB-1990    ArticleIdent: Q57780

 Microsoft QuickC Versions 2.00 and 2.01 will produce incorrect code if
 pointer subtraction is immediately cast to a long integer. The
 resulting value is not the number of elements between the two
 pointers, as it should be.

 The following code fragment demonstrates this problem:

 #include <stdio.h>
 #include <stddef.h>
 char
    chArray [20],
    *p1,
    *p2;
 long
    pdif;

 void main(void)
 {
    p2 = &chArray[0];
    p1 = &chArray[19];

    printf("dif:  %lx\n", (long)(p1 - p2)); /* Invalid count */

    pdif = (p1 - p2);
    printf("dif:  %lx\n", pdif);  /* Correct count */
 }

 In the first printf(), the compiler does not clear out the high-order
 word when the cast is performed, so the resulting long value is
 incorrect. The workaround is to use the second form and calculate the
 count in a temporary variable first.

 According to the ANSI standard, pointer subtraction is defined between
 two pointers when they both are of the same type and they both point
 to the same array. The return value is the number of elements
 separating the two pointers. The resulting type is defined inside
 "stddef.h" with "ptrdiff_t". Microsoft C and QuickC define "ptrdiff_t"
 to be a two-byte signed integer.


 322. _pg_chartpie Fails on { 1.0, 0.0 } Set Elements

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01 100% 0%
 Last Modified: 20-FEB-1990    ArticleIdent: Q57937

 Calling the Presentation Graphics function _pg_chartpie with a set of
 values that contain a 100-percent and one or more 0 (zero) percent
 elements fails to draw a full pie chart as expected but draws a
 diameter line from the center of the circle to the circumference.

 The following is a workaround:

 If your chart is being drawn in Hercules monographics mode,
 (_HERCMONO), you can give the illusion of having a full graph. Set the
 elements to { 1.0, 0.00113 } or { 100.0, 0.113 } to allow _pg_chartpie
 to draw a circle that appears to be full. If the smaller element is
 0.113 percent or more of the larger element, the chart will draw
 correctly.

 The same trick does not appear to work in other modes. _VRES16COLOR
 and _ERESCOLOR modes were tested and the full circle illusion could
 not be duplicated. In _VRES16COLOR mode, a line is drawn at sets with
 0.0795 and smaller second elements, and a broken circle is drawn in
 sets with 0.07975 or larger second elements. In _ERESCOLOR mode, a
 line is drawn for sets with 0.112 and smaller values for the second
 element. A broken circle is drawn for sets with 0.113 and larger
 second element values.

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.

 The following code demonstrates this problem:

 #include <stdio.h>
 #include <stdlib.h>
 #include <graph.h>
 #include <pgchart.h>
 #include <conio.h>
 #include <string.h>

 #define NUMVALS 2

 float far value[NUMVALS] = { 100.0f, 0.0f };
 /* float far value[NUMVALS] = { 100.0f, 0.113f } ;  this is the
                                             fix in HERC mode */

 char far *category[NUMVALS] = { "First", "Second" };
 short far explode[NUMVALS] = { 0, 0 };

 void main(void)
 {
       int returnval;
       chartenv env;
       if( (returnval = _setvideomode(_HERCMONO)) == 0)
       {
           printf("Video mode not supported.\n");
           exit (-1);
       }
      _pg_initchart();
      _pg_defaultchart( &env, _PG_PIECHART, 2);
      _clearscreen(_GCLEARSCREEN);
       strcpy(env.maintitle.title, "TEST TITLE");
      _pg_chartpie(&env, category, value, explode, NUMVALS);
       getch();
      _setvideomode(_DEFAULTMODE);
 }


 323. An Example of a delay() Function in C 5.10 or QuickC 2.00

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C
 Last Modified:  7-MAR-1990    ArticleIdent: Q57946

 The Microsoft C or QuickC run-time library does not include a delay()
 function. The sample code below demonstrates a function that could be
 used to generate a delay within a program.

 Sample Code
 -----------

 #include <stdio.h>
 #include <time.h>        /* needed for delay()    */

 void delay (clock_t ms); /* prototype for delay() */

 void main (void)
 {
      puts("This is a test of a delay function.");

      delay(5000);        /* 5 second delay        */

      puts("Back from delay function.");
 }

 void delay (clock_t ms)
 {
      clock_t stop;

      stop = ms + clock();
      while(stop > clock());
 }

 The delay() function generates a delay in milliseconds. For example,
 to have a 10 second delay, pass the value 10000 to the function.


 324. Using INT with _asm Does Not Output Text in Debugger

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00
 Last Modified: 26-FEB-1990    ArticleIdent: Q58672

 Question:

 If I trace (using F8) through the DOS or BIOS interrupt functions
 designed to output information to the screen, I do not receive any
 output from the program. I can run the program (using F5) and my
 output is displayed properly. C run-time screen output functions also
 properly display my output. How can I correct this problem?

 Response:

 To work around this problem, turn on Screen Swap. This option is found
 under Options.Run/Debug. When you press F5 or use C run-time
 function, the screen is swapped to the output window before executing
 the statement. In the case of an interrupt call through _asm, QuickC
 does not switch to the output window when Screen Swap is set to Auto
 or Off.

 Sample Code:

 /*
 DEBUGGER.C:
 To see the problem, use .Option.Run/Debug.Screen Swap set to either
 Auto or Off. Setting this to On will cause output to appear properly.
 */
 #include <string.h>

 char *str1 = "Print using INT 21H, Function 09H$" ;
 char *str2 = "Print using INT 21H, Function 40H" ;

 void main ( void )

 {
   int len ;

   len = strlen(str2) ;

 /*  Display String - outputs a string to standard out (must be */
 /*                   terminated with '$').                     */
   _asm {
          push dx
          mov  dx, word ptr str1
          mov  ah, 09h
          int  21h
          pop  dx
   }

 /*  Write File or Device - outputs a string to a file, use bx = 1 */
 /*                         to write to standard out.              */
   _asm {
          push dx
          push cx
          push bx
          mov  ah, 40h
          mov  bx, 01h
          mov  cx, len
          mov  dx, word ptr str2
          int  21h
          pop  bx
          pop  cx
          pop  dx
   }

 /*  Write Character and Attribute at Cursor - Displays 40h X's */
 /*                                            at the cursor.   */
   _asm {
          push cx
          push bx
          mov  bh, 0
          mov  bl, 0f0h
          mov  cx, 40h
          mov  ah, 0ah
          mov  al, 'X'
          int  10h
          pop  bx
          pop  cx
   }

 The code is generated properly, but the debugger does not recognize
 the need to swap to the output screen on these interrupts.

 Microsoft has confirmed this to be a problem with QuickC Version 2.00.
 We are researching this problem and will post new information here as
 it becomes available.


 325. Backing Up QuickC Files in the Editor

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-FEB-1990    ArticleIdent: Q58783

 Question:

 Is it possible to configure QuickC 2.00 or 2.01 to automatically back
 up my source file, or must I use the Save As command whenever I want
 to save a .BAK file?

 Response:

 QuickC does not offer a built-in automatic backup feature. However,
 there are several ways to make a backup file from inside the
 environment.

 1. Use the Save As command. This allows you to save the current file
    under a different name.

 2. Select the Run DOS Command option under the Utility menu to access
    the DOS COPY command.

 3. Take advantage of QuickC's ability to customize the Utility menu. A
    backup program option can be installed on the utility menu.

 Below is one way to add a backup option to the Utility menu:

 1. Create a batch file called BACK.BAT in the QC2\BIN subdirectory.
    The file should contain one line, as follows:

       COPY %1 *.BAK

 2. Bring up QuickC and select the Utility.Customize Menu option.

 3. Select <Add> to add a menu option.

 4. Fill in the screen as shown below:

       Menu Text: [Backup Routine            ]
       Path Name: [C:\QC2\BIN\BACK.BAT       ]
       Arguments: [$FILE                     ]
       Initial Directory: [                  ]
       [ ] Prompt Before Returning
       Accelerator Key: ( ) None  (*) Key F[10]

    Modify the pathname and accelerator key as needed for your setup.

 5. Select <Ok> and <Save> to get back to the main screen.

 From now on, whenever you press the accelerator key or select the
 Utility.Backup Routine menu option, the file in the current screen
 group will be saved with an extension of BAK. You can modify this
 behavior by changing the BACK.BAT batch file to fit your needs.


 326. _asm Needed for Each Line of Inline Assembly Macros

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified: 21-FEB-1990    ArticleIdent: Q58802

 In QuickC Version 2.00, the _asm keyword is needed between each code
 line of inline assembly macros. _asm works as a statement separator
 similar to the C comma or semicolon operators.

 When writing #define macros in C, they must be written on a single
 logical line. The escape character allows you to extend this logical
 line over more than one source line in your program. However, it is
 important to remember that the preprocessor is simply going to
 concatenate the macro into one logical line before compilation.

 Since assembly code is usually separated only by a new line, this
 causes a problem with multi-line assembly macros. Putting the _asm
 keyword before each assembly command forces the needed separation and
 allows the macro to behave properly. This is described briefly in "C
 For Yourself" on Page 277.

 Sample Code
 -----------

 The following macro causes errors C4405 and C2400 when compiled under
 QuickC:

 #define SETPAGE( page )  _asm \
                          {    \
                               mov ah, 5 \
                               mov al, byte ptr page \
                               int 10h \
                          }

 In the preprocessor, this concatenates to the following:

 _asm { mov ah, 5 mov al, byte ptr page int 10h }

 The correct syntax for the macro, as it appears on Page 277 of "C for
 Yourself," is as follows:

 #define SETPAGE( page )  _asm \
                          {    \
                               _asm mov ah, 5 \
                               _asm mov al, byte ptr page \
                               _asm int 10h \
                          }

 Note that the first _asm statement before the opening curly brace ({)
 is not needed.


 327. Returning to QuickC from PM May Corrupt Screen

 Product Version(s): m2.00 2.01
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.00 buglist2.01
 Last Modified:  6-MAR-1990    ArticleIdent: Q59005

 If you are doing graphics in QuickC, returning to the DOS box from
 Presentation Manager (PM) and then exiting Quick C may generate red
 and white stripes on a flashing background in the DOS compatibility
 box. Mouse support will be disabled for the DOS compatibility box.
 This problem occurs when you exit from QuickC without returning the
 video mode to _DEFAULTMODE. Restoring the video mode to default
 prevents the problem.

 The effect can be demonstrated by doing the following:

 1. Execute the program (shown below) at the command line,

        QCL BOX.C GRAPHICS.LIB

 2. Run the resulting .EXE either from the command line or in the
    environment.

 3. Enter QuickC, as follows:

        QC  (no file required to demonstrate the problem)

 4. Press CTRL+ESC to Presentation Manager.

 5. Re-enter the DOS compatibility box.

 6. Exit Quick C, as follows:

       ALT+F.Exit

 Sample Code
 -----------

 #include <graph.h>
 void main()
 {
    _setvideomode(_VRES16COLOR);
 /* _setvideomode(_DEFAULTMODE);  uncomment to correct behavior */
 }

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.

 This problem has been reproduced on a WYSE 386 with a FastWrite VGA
 and on a WYSE 286 with a Genoa Super VGA board. It has not been
 reproduced on a Compaq.


 328. Error C2094: Label "xxx" Was Undefined

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm S_C
 Last Modified: 18-NOV-1990    ArticleIdent: Q59086

 The following error occurs with inline assembly if one of the operands
 is a hexadecimal value that starts with an alphanumeric character
 (A-F, a-f):

    error C2094 : label 'xxx' was undefined

 Sample Code
 -----------

 void main(void)
 {
    _asm mov ah, f0h
 }

 This is expected behavior in inline assembly since "f0h" is a valid C
 variable and it is also a valid label name. In the sample code, since
 "f0h" was not declared as a variable and there is no label defined as
 "f0h", the compiler returns with an error C2094.

 To use a hexadecimal value that starts with an alphanumeric character
 into a register, there are two options as follows:

 1. Assign the value to a variable, then move the contents of the
    variable into the register, as follows:

       unsigned char hex_value = 0xf0;
       void main (void)
       {
          _asm mov ah, hex_value
       }

 2. Instead of using Assembler notation (F0h), use C notation for
    the hex value, as follows:

       void main(void)
       {
          _asm mov ah, 0xf0
       }

 3. Use a leading 0 (zero) [or multiple leading 0s (zeros)] on the
    MASM-style hex constant. This procedure sets the value for the high
    and low portion of the register, as follows:

       void main(void)
       {
          _asm mov ax, 000f0h
       }


 329. _setactivepage() and _setvisualpage() May Corrupt Display

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified: 15-MAR-1990    ArticleIdent: Q59088

 Interrupting execution of the following code, then attempting to step
 through the program with F10, may cause the mouse to be temporarily
 frozen and the video display to be corrupted. The problem is caused by
 an unresolved swapping between _setactivepage() and _setvisualpage().
 The solution is to either press F4 twice or allow the program to
 terminate normally, thereby resetting the default video mode.

 Sample Code
 -----------

 #include <stdio.h>
 #include <graph.h>

 #define DELAY 1

 void main(void)
 {
    int x=0, y=0, time=DELAY, loop=0, pages;
    struct videoconfig config;

    _setvideomode(_MRES16COLOR);
    _getvideoconfig( &config );
    pages = config.numvideopages;

    while ( !kbhit() )
    {
       _setactivepage( loop % pages );
       _setcolor( loop % 16 );
       _rectangle( _GFILLINTERIOR, ++x, ++y, x+160, y+100 );
       _setvisualpage( loop++ % pages );
       while( time-- );
       time = DELAY;
    }
    _setvideomode (_DEFAULTMODE);
 }

 The sequence of events causing the situation to occur is listed below:

 1. Open the above source code in QuickC 2.00 or 2.01.

 2. GO (using F5 or a mouse click).

 3. CTRL+BREAK to interrupt execution in the first few seconds of the
    run. The Source window appears.

 4. Press F10. The cursor may disappear, and the mouse will be locked
    out.

 5. CTRL+BREAK again. The mouse is now active, but the screen display is
    corrupted. Dragging the mouse around the screen leaves a trail of
    blocks.

 6. Toggle F4 to restore the source window and refresh the screen.


 330. Help on ungetch Not Available from Help Topics List

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 15-MAY-1990    ArticleIdent: Q59253

 Due to a misspelling, help is not available on the function "ungetch"
 by selecting the function from the Help.Topics List.

 To demonstrate the problem, select Run-Time Library from the Contents
 list. From the Run-Time Library, select I/O Console and Port. In the
 list of functions displayed, "ungetch" is misspelled as "ungecth";
 thus, no help is found for the function when the function name is
 selected and F1 is pressed for specific help.

 To work around the problem, there are two solutions:

 1. Type "ungetch" in the editor window and press F1. The help engine
    will correctly find the information on the function.

 2. Using HELPMAKE.EXE, decode the QC.HLP file, correct the
    misspelling, and encode it again with the change.


 331. _setcliprgn() Fails to Clip _putimage() Operation

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c
 Last Modified: 12-MAR-1990    ArticleIdent: Q59382

 Question:

 When an image is placed on the display using the _putimage function,
 and this image spans the border of a clipping region, it is not
 clipped properly. Why does this happen?

 Response:

 First, the _setcliprgn() function operates on single objects. If any
 part of an object lies outside of the clipping region, it will not be
 displayed. Second, a graphic block (image) used by the _getimage() and
 _putimage() functions is treated as a single object by the graphic
 functions. Therefore, the entire image must fit in the clip region for
 any of it to be displayed. This is in contrast to lines and circles,
 which are a collection of objects and are clipped as expected.


 332. _setcliprgn Bad Definition in QC Graphics Library Reference

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 14-MAR-1990    ArticleIdent: Q59383

 In the "Microsoft QuickC Graphics Library Reference" the _setcliprgn
 function on Page 181 is defined as follows:

      void far _setcliprgn(x1,y1,x2,x2);
      short x1,y1;
      short x2,y2;

 It should be as follows:

      void far _setcliprgn(x1,y1,x2,y2);

 Note that the last parameter is different.


 333. ICE Error When Casting Pointer Arithmetic Result

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01
 Last Modified: 29-MAY-1990    ArticleIdent: Q59539

 When casting the result of pointer arithmetic to either a double or a
 float, QuickC Version 2.00 or QuickAssembler Version 2.01 may produce
 the following internal compiler error when compiling in small, medium,
 compact, or large models:

    ice.c(7) : fatal error C1001: Internal Compiler Error
          (compiler file 'gencode.c', line 389)
          Contact Microsoft Technical Support

 Turning off all optimizations by use of the /Od switch does not help.

 Sample Code
 -----------

 void main(void)
 {
    char * foo = "abcdef",
         * bar = foo + 5 ;
    double dbl;

    dbl = (double) (foo-bar) ;
 }

 Substituting "float" for "double" produces the same error.

 The problem can be solved by using a temporary variable of type int to
 store the result of the pointer arithmetic. Type int is used because
 in all models (except huge), pointer arithmetic is done in 2-byte
 signed (that is, int) arithmetic.

 The following is the same as the above example, but uses a temporary
 variable to store the result of the pointer arithmetic.

 void main(void)
 {
    char * foo = "abcdef",
         * bar = foo + 5 ;
    double dbl ;
    int    temp ;

    temp = foo-bar ;
    dbl  = (double) temp ;
 }

 Microsoft has confirmed this to be a problem with QuickC Versions 2.00
 and 2.01. We are researching this problem and will post new
 information here as it becomes available.


 334. li, lu, and ld Replace I, U, and D as Format Specifiers

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm s_c docsup
 Last Modified: 29-MAY-1990    ArticleIdent: Q59891

 When scanning long values with the scanf() function, use %li, %lu, and
 %ld.

 Since the format specifiers %I, %U, and %D are not part of the ANSI
 standard, they will not be supported in compilers released after the C
 Version 5.10 Optimizing Compiler.

 You must follow the ANSI standard and use %l[x] for long values.

 If you use %I, %U, or %D as a format specifier for a long value, the
 scanf() function family will not return an indication of an error.
 Instead the format specifier will be treated as its lowercase
 counter part. For example:

    %I --> %i
    %U --> %u
    %D --> %d


 335. Error R6001 Generated by Compiler in Huge Model

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 buglist2.01 fixlist2.50 fixlist2.51
 Last Modified: 15-APR-1990    ArticleIdent: Q59928

 When casting the result of pointer arithmetic to either a double or a
 float, QuickC Version 2.00 or QuickAssembler Version 2.01 may produce
 the following error when compiling in the huge model:

    run-time error R6001
    - null pointer assignment

 This error occurs in the huge memory model only. Turning off all
 optimizations using the /Od switch does not help.

 The compiler does produce an OBJ file, but this file is not valid. If
 an attempt is made to link this OBJ into an executable, the following
 error will be issued by the linker:

    xxx.obj (xxx.c) : error L2029 : '__' : unresolved external

 The following code reproduces the error:

 void main(void)
 {
         char * foo = "abcdef",
              * bar = foo + 5 ;
         double dbl;

         dbl = (double) (foo-bar) ;
 }

 Substituting "float" for "double" produces the same error.

 In memory models other than huge, this same situation generates the
 following error message:

    fatal error C1001: Internal Compiler Error
    (compiler file 'gencode.c', line 389)
    Contact Microsoft Product Support

 For more information, query on the following words:

    ICE and error and casting and pointer and arithmetic

 Workaround
 ----------

 The problem can be solved by using a temporary variable of type long to
 store the result of the pointer arithmetic. The temporary variable
 used to store the result of the pointer arithmetic is of type long
 because all huge pointer arithmetic is done using 4-byte signed (that
 is, long) arithmetic.

 The following is the same as the above example, but uses a temporary
 variable:

 void main(void)
 {
         char * foo = "abcdef",
              * bar = foo + 5 ;
         double dbl ;
         long   temp ;

         temp = foo-bar ;
         temp = (double) temp ;
 }

 Microsoft has confirmed this to be a problem with QuickC Version 2.00
 and QuickAssembler Version 2.01. It has been corrected in QuickC
 Version 2.50 and Quick Assembler 2.51.


 336. Qccom Cannot Parse Combined /G* Options from Environment

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.00 buglist2.01 fixlist2.50 fixlist2.51
 Last Modified: 18-APR-1990    ArticleIdent: Q60254

 If you set the cl environment variable to include the /G2s, /G2w,
 /Gsw, or /G2sw option and then compile any program within the QuickC
 2.00 or 2.01 environment, you will receive the following compiler
 error:

    Fatal Error C1007: Unrecognized flag '<flag>' in 'qccom'.

 <flag> is replaced by the cl option you set in the environment
 variable (/G2s, /G2w, /Gsw, or /G2sw). If you break up the switch to
 separate components (for example, /G2w becomes /G2 /Gw), qccom parses
 the options correctly.

 If you are using QuickC 2.50 or 2.51, the environment variables are
 parsed correctly.

 1. Type the following line at the DOS prompt:

       set cl=/G2sw

 2. Enter QuickC, and bring up any source file. Compiling the file will
    give you the error message shown above.

 3. Now, exit QuickC and break up the environment variable by typing
    the following:

       set cl=/G2 /Gs /Gw

    If you attempt to compile a new program, the error will not occur.


 337. __STDC__ Is Undefined If Microsoft Extensions Are Allowed

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm s_c
 Last Modified: 15-APR-1990    ArticleIdent: Q60255

 The __STDC__ macro is defined if a C compiler is ANSI C-standard
 conforming, and is undefined in QuickC Versions 2.50 and 2.51 if
 Microsoft extensions are allowed (default). To allow the macro to be
 defined, go to Options.Make.Compiler Flags.C Language and check ANSI
 compatibility. If you are compiling from the command line, add the /Za
 switch.

 This macro may be used as in the following code fragment:

 Code Example
 ------------

 #ifdef __STDC__
   void foo_bar (void);
 #endif


 338. Using Second _ellipse() Call to Erase Text Can Fail

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-APR-1990    ArticleIdent: Q60335

 Using the _ellipse() function with the _GFILLINTERIOR flag to create a
 color-filled background upon which to display text using the font
 functions, everything may appear to work correctly until you attempt
 to erase the text you have written by placing an identical ellipse
 over the original. The second ellipse function call apparently will
 have no effect.

 The problem lies in the way the ellipse function creates a filled
 ellipse. For example, if you instruct _ellipse() to draw a blue-filled
 ellipse, the function first draws a hollow blue ellipse then does a
 floodfill until it reaches a blue boundary.

 If you then write text on it and try to erase the text with another
 blue-filled ellipse, it will not work properly; the second ellipse
 tries to do a blue floodfill but has nowhere to go because the place
 it is writing to is already blue.

 Workaround
 ----------

 There are essentially three workarounds for this situation.

 1. The first workaround is to use three ellipse calls, as follows:

    a. Draw the colored ellipse.

    b. Draw the text.

    c. Draw an ellipse identical to the first one except for the color.

    d. Draw the last ellipse identical to first one.

 2. The second workaround is an enhancement of the first.

    To achieve the originally desired effect without seeing a second
    different-colored ellipse flicker in between, you can remap the
    palette so that the second fill color matches the first EXACTLY.
    Visually, they are identical, but the color indices (which is what
    floodfill goes by) are different.

    You can then either refill with the original color-index, or leave
    it painted in the second (visually identical).

    If the operation is repeated, you could alternate between two
    (identical-looking) color indices.

 3. Finally, you could use _polygon() to simulate the ellipse, since
    _polygon() uses a scanfill, not a floodfill.


 339. Cannot Set Breakpoint Warning Due to Wrong Linker

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q61614

 QuickC will give warnings of "no symbolic information" and "cannot
 set breakpoint filenam.c:linenum" when the wrong linker is used. For
 instance, using LINK.EXE version 5.05 from Basic 7.00 or version 5.10
 from C 6.00 will cause these warnings.

 QuickC will prompt you to respond to "rebuild with symbolic
 information?" If yes is selected, the program recompiles, links, and
 again warns: "no symbolic information." Care should be taken to verify
 that the correct linker is executed. LINK.EXE version 4.06 is the
 correct version for QuickC 2.00 and LINK.EXE version 4.07 is the
 correct version for Quick Assembler 2.01.


 340. Behavior of Tabs in QuickC 2.50

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified:  9-JUL-1990    ArticleIdent: Q63567

 The "Keep Tabs" option controls how tabs are displayed on the screen
 and saved to disk.

 The effect of "Keep Tabs" in the editor is as follows:

 With "Keep Tabs" selected all tabs are represented as actual tabs on
 the display (HEX 09), that is, when you backspace over a tab, the
 cursor leaps to the next tabstop to the left.

 When "Keep Tabs" is not selected, a series of spaces (HEX 20) will be
 placed on the display instead of an actual tab character, that is,
 when you backspace over a tab it moves the cursor only one space to
 the left instead of to the next tabstop.

 The saved files behave in the following way:

 In the saved file with "Keep Tabs" on and with leading whitespace
 before the tabs/spaces, tabs will be saved as tab characters (HEX 09)
 and spaces will be saved as spaces (HEX 20). With no leading
 whitespace, tabs will be saved as tab characters (Hex 09) and spaces
 will be saved as spaces (HEX 20).

 In the saved file with "Keep Tabs" off and with leading whitespace,
 the leading whitespace is converted to tabs (and spaces if necessary),
 and all other whitespace is converted to spaces.


 341. Library Sizes for QuickC 2.50

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-JUL-1990    ArticleIdent: Q63704

 The following are sizes for QuickC version 2.50 combined libraries, as
 created by LIB.EXE 3.17:

                                           Standard
                              Standard     + Graphics
    Library       Standard    + Graphics   + PgChart
    -------       --------    ----------   ---------

    SLIBCE.LIB    252235      338211       389125
    MLIBCE.LIB    251721      340769       392195
    CLIBCE.LIB    256365      345925       396839
    LLIBCE.LIB    259949      348997       399911

    SLIBC7.LIB    236363      325411       376325
    MLIBC7.LIB    238921      327969       379395
    CLIBC7.LIB    243565      332613       384039
    LLIBC7.LIB    247149      336197       387111


 342. "C For Yourself" Documentation Error

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 15-AUG-1990    ArticleIdent: Q63722

 On Page 246 of the "C For Yourself" manual supplied with QuickC
 version 2.50 and Quick Assembler version 2.51, there is a macro under
 the heading "EGA Color Mixing."

 The macro is incorrectly defined as follows:

    #define EGARGB( r, g, b ) (0x3F3F3FL & ((long)(b) << 20 | (g) << 12 \
    | (r << 4)))

 This macro should read as follows:

    #define EGARGB( r, g, b ) (0x303030L & ((long)(b) << 20 | (g) << 12 \
    | (r << 4)))

 Note that the backslashes can be omitted if you put the #define all on
 one line.


 343. Using Unary "+" in QuickC Gives Incorrect Results

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.50 plus
 Last Modified: 25-JUL-1990    ArticleIdent: Q63959

 The ANSI C standard now defines the unary + operator. However, using
 this operator on a float or double precision float data type in QuickC
 version 2.50 gives inaccurate results. The following code will
 reproduce these results:

 /* This code will print out an inaccurate value for
  * variable t
  */

 static double t = +.5, tt = .5;

 void main(void)
 {
         printf("t = %lg tt = %lg\n", t, tt);
 }

 The output from this program is as follows:

    t = 0 tt = 0.5

 This behavior occurs only when using floating point numbers or
 doubles. Integers behave as expected.


 344. Watch Value Can Display Incorrect Value of Far Memory

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified: 25-JUL-1990    ArticleIdent: Q64022

 If the sample code is compiled with debug information, a watch window
 set on the "fptr" pointer will display incorrect values.

 Sample Code
 -----------

 #include <stdio.h>
 unsigned char far * fptr;
 void main()
 {
      int c;
      fptr=(unsigned char far *)0xd0000600;
      for (c=0; c < 50; c++)
           printf("%d\n", fptr[c]);
 }

 When fptr[c] is displayed as a watch value entry, it will show values
 that are different than the output screen. QuickC 2.00 and CodeView
 show the same watch value as the output screen.

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


 345. Adding Dependencies to QuickC 2.50 Make File Disrupts QuickC

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.51 s_quickasm
 Last Modified: 31-AUG-1990    ArticleIdent: Q64027

 Adding dependencies directly to a Microsoft QuickC version
 2.50-generated make file can cause unpredictable results when
 rebuilding from within the environment. The results observed so far
 include the following:

 1. The machine hangs.

 2. A Fatal Internal Error is produced.

 3. The error u1073 -- "don't know how to make Learn QuickC" occurs.

 The problems mentioned above are unpredictable but stem from the same
 cause. The make files generated by Microsoft QuickC are intended to be
 modified solely through the use of certain editor menus, that is, the
 make/edit program list. When direct changes are made to these make
 files, any subsequent use of them by QuickC will meet with
 unpredictable results.

 If you want to make changes to a make file created by QuickC and still
 use the integrated environment for building your program, you must do
 so through the menu system. The other alternative is to make the
 changes to the make file and then rebuild from the command line with
 the NMAKE utility.


 346. 8087 Registers Not Viewable in QuickC

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm buglist2.50
 Last Modified:  1-AUG-1990    ArticleIdent: Q64068

 In Microsoft QuickC version 2.50 and QuickAssembler version 2.51, you
 cannot watch the 8087 registers while debugging.

 If you select Display from the QuickC Options Menu and activate the
 "Show 8087" option, the debug window will always claim that the
 floating point package has not been loaded. The problem seems to be
 with the built-in QuickC debugger, rather than the compiler and linker
 that produce the symbolic information. The same executable can
 successfully be debugged under CodeView version 3.00, which uses the
 same symbolic information format.

 Microsoft has confirmed this to be a problem with QuickC version 2.50.
 We are researching this problem and will post new information here as
 it becomes available.


 347. View.Source Truncates Long Pathnames

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50 buglist2.51
 Last Modified: 31-AUG-1990    ArticleIdent: Q64562

 The pathname of source files may be truncated when the View menu is
 selected and Source is chosen in QuickC versions 2.50 and 2.51.

 This truncation usually results in the wrong file being opened, or
 QuickC will ask if you want to create a new file with the truncated
 name.

 To reproduce this problem, do the following:

 1. Set a program list (select Set Program List from the Make menu).

 2. Add a file with a very long pathname (greater than 36 characters)
    to the program list.

 3. Now choose Source from the View menu and select the file with the
    long pathname. The pathname will be truncated and an incorrect file
    will be opened.

 Although QuickC should be able to accept longer pathnames, the limit
 of the drive/pathname is 36 characters for the View.Source menu item.
 This length limit is not apparent in any other QuickC menu items or
 functions.

 A workaround for this problem is to make the pathname shorter.

 Microsoft has confirmed this to be a problem in QuickC versions 2.50
 and 2.51. We are researching this problem and will post new
 information here as it becomes available.


 348. _pg_chartpie() Fails to Free Memory in QC 2.00 and QC 2.50

 Product Version(s): 2.00 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50
 Last Modified: 17-DEC-1990    ArticleIdent: Q64786

 The presentation graphics function _pg_chartpie() fails to return
 memory allocated from DOS.

 Successive calls to _pg_chartpie() will cause three paragraphs of
 memory to be allocated from DOS for each call. Because there is no
 companion to _pg_initchart() [for example, _pg_closechart()], the
 memory allocated by _pg_chartpie() is not returned to DOS until the
 program finishes execution.

 The program below demonstrates this problem.

 Sample Code
 -----------

 #include <stdlib.h>
 #include <graph.h>
 #include <pgchart.h>
 #include <stdio.h>

 #define COUNTRIES 5
 float _far value[COUNTRIES] = { 42.5F,  14.3F, 35.2F,  21.3F,
                                 32.6F   };
 char  _far *category[COUNTRIES] = { "USSR", "GDR", "USA",  "UK",
                                     "Other" };
 short _far explode[COUNTRIES] =   { 0,      1,     0,      1,     0 };

 void main()
 {
     char stringbuff[80];
     chartenv env;
     unsigned sized=0;
     unsigned seg=0;
     /* Get Dos Memory Available on far heap-wait for key hit */
     _settextposition(4,4);
     _dos_allocmem(0xffff,&seg);
     sprintf(stringbuff,"Memory : %u\n",seg);
     _outtext(stringbuff);

     getch();
     if( !_setvideomode( _VRES16COLOR ) )
         exit( 1 );

     _pg_initchart(); /* Initialize chart system    */

     while(1)
         {

     /* Pie chart */

         _pg_defaultchart( &env, _PG_PIECHART, _PG_PERCENT );
         strcpy( env.maintitle.title, "Widget Production" );
         _pg_chartpie( &env, category, value, explode, COUNTRIES );

     /* Display available memory- wait for key hit */

         _settextposition(4,4);
         _dos_allocmem(0xffff,&seg);
         sprintf(stringbuff,"Memory : %u\n",seg);
         _outtext(stringbuff);
         getch();

     }
     _setvideomode( _DEFAULTMODE );
 }

 Microsoft has confirmed this to be a problem in QuickC version 2.50.
 We are researching this problem and will post new information here as
 it becomes available.


 349. QC 2.0x Incorrectly Stores Uninitialized Global Data in DGROUP

 Product Version(s): 2.00 2.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 fixlist2.50
 Last Modified: 31-AUG-1990    ArticleIdent: Q65329

 Microsoft QuickC version 2.00 and Microsoft QuickAssembler version
 2.01 both store uninitialized global data in the default data segment
 for the program (DGROUP). This is an error for compact and large model
 programs according to standard Microsoft segment-ordering conventions.
 In versions 2.50 and 2.51, this was corrected and uninitialized global
 data is now stored in FAR_BSS for compact and large models.

 Sample Code
 -----------

 int global;

 void main()
 {}

 To see this concept demonstrated, compile the above program under
 QuickC versions 2.0x and 2.5x. If the .MAP file from each is examined,
 the results will be obvious.

 Microsoft has confirmed this to be a problem with QuickC version 2.00.
 This problem was corrected with QuickC versions 2.50 and 2.51.


 350. Building Windows 3.00 Applications with QuickC

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickasm
 Last Modified:  1-OCT-1990    ArticleIdent: Q65490

 You can build Windows applications with Microsoft QuickC and the
 Windows Software Development Kit (SDK) version 3.00. However, to do
 this, you must use certain utilities that are not packaged with either
 QuickC or the SDK. To receive a disk containing these utilities, call
 the Information Center at (800) 426-9400 and ask for the Supplemental
 Compiler Utility Disk, part number 050-150-168. The disk includes
 LINK, LIB, IMPLIB, EXEHDR, and MAKE along with documentation, in Write
 format, for each utility.

 To build the sample applications that come with the SDK, change all
 references of CL in the supplied .MAK files to QCL. In addition, some
 applications may require changes to the link step in the make file.
 For instance, to build the MULTIPAD application, add SLIBCEW to the
 libraries line in the supplied .LNK file.

 Because of the large size of most Windows applications, it is almost
 always necessary to build these applications outside of the QuickC
 environment on the command line. Finally, although it is possible to
 use the SDK with QuickC, it is recommended that you use version 5.10
 or 6.00 of the Microsoft Optimizing C Compiler. The optimizing
 compiler contains the necessary utilities, has a higher capacity, and
 produces production-quality code.


 351. Some Windows 3.00 Fonts Don't Work with QuickC

 Product Version(s): 2.00 2.01 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50 buglist2.51 s_c docerr
 Last Modified: 24-OCT-1990    ArticleIdent: Q65648

 Certain Windows version 3.00 font files do not display correctly when used
 with the QuickC font routines, although the manuals state that the
 .FON files from Windows are identical to the .FON files from QuickC.
 The .FON files from Microsoft Windows versions earlier than 3.00 work
 correctly.

 The vector-mapped fonts from Windows version 3.00 work correctly with
 QuickC, but most of the bit-mapped fonts will display corrupted
 characters if used with the QuickC font routines.

 Sample Code
 -----------

 The following program reproduces this problem by using one of the
 Windows 3.00 bit-mapped font files, HELVE.FON:

 #include <graph.h>

 void main()
 {
   _registerfonts("HELVE.FON");
   _setvideomode( _VRES16COLOR );
   _clearscreen( _GCLEARSCREEN );

   /* Set font to the first font in the font file (n1) */
   _setfont("n1");
   _moveto(0,0);
   _outgtext("Test abcdefgABCDEFG12345!@#$%");
 }

 Compile this program using "qcl test.c graphics.lib" and execute in
 the directory containing the Windows 3.00 font files. The test text
 will be displayed as a line of corrupted characters.

 Microsoft has confirmed this to be a problem with QuickC versions 2.50
 and 2.51. We are researching this problem and will post new
 information here as it becomes available.


 352. "QuickC with QuickAssembler" Is 2.51, "QuickC" Alone Is 2.50

 Product Version(s): 2.00 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickASM C assembler Quick
 Last Modified: 24-OCT-1990    ArticleIdent: Q66288

 Microsoft QuickC version 2.50 and Microsoft QuickC with QuickAssembler
 version 2.51 are two separate products.

 Shorthand references to "QuickAssembler" or "QuickC" version 2.51 (or
 2.01) actually refer to the official product name "Microsoft QuickC
 with QuickAssembler version 2.51 (or 2.01)."

 The only difference between QuickC 2.50 and 2.51 is the addition of a
 QuickAssembler, to create and assemble stand-alone assembly programs.
 The QuickC portion of the 2.51 product is exactly the same as in
 QuickC 2.50. (Also, the QuickC portion of the 2.01 product is exactly
 the same as in QuickC 2.00.) Thus, QuickC is optionally available
 without the QuickAssembler, but the QuickAssembler is only available
 bundled with the "QuickC with QuickAssembler" product.

 Any problems regarding QuickC version 2.50 also apply to version 2.51.

 Any problems regarding QuickC version 2.00 also apply to version 2.01.


 353. Accessing Online Help for C and Assembly Topics with Same Name

 Product Version(s): 2.01 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM
 Last Modified: 23-OCT-1990    ArticleIdent: Q66307

 QuickC with QuickAssembler versions 2.01 and 2.51 include online help
 for both C and Assembly topics. The Microsoft Advisor searches for C
 topics in the help file, QC.HLP, and for Assembly topics in QA.HLP.
 The manner in which the Advisor searches for topics is governed by the
 Language and Smart Help settings in the Display box under the Options
 menu.

 The following three possible Language settings determine the search
 order through the help files:

    If Language Is:      Then:
    ---------------      -----

    C                    QC.HLP is searched first, then QA.HLP.

    Assembler            QA.HLP is searched first, then QC.HLP.

    Auto                 The file extension of the current file determines
                         the search order. If it is not .ASM, the C
                         defaults are used.

 Smart Help causes the Advisor to be insensitive to the presence or
 absence of leading underscores. For example, with Smart Help on,
 _dos_findfirst and dos_findfirst will bring up the same topic, while
 no help will be displayed on dos_findfirst with Smart Help turned off.
 In addition, Smart Help makes the search case insensitive.

 With the possible combinations of Language and Smart Help settings,
 attempting to access the online help system for topics defined in both
 C and Assembly may result in receiving help for only one language. For
 example, with the Language set to C and Smart Help activated, the
 following table shows a few instances where seeking help on certain
 Assembly topics results in help for the corresponding C topics:

    Assembly Help Desired     C Help Actually Received
    ---------------------     ------------------------

       .EXIT                       exit()
       SEGMENT                     _segment
       IF                          if
       IFNDEF                      #ifndef
       INCLUDE                     #include

 The solution to this problem is changing the search order of the help
 files by changing the Language setting or forcing the search to be
 case sensitive by disabling Smart Help.


 354. Using /F Switch with No Argument May Disable Debug Switch

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.50 s_c
 Last Modified: 11-NOV-1990    ArticleIdent: Q66495

 If you use the /F (set stack size) switch without an argument, you may
 overwrite the next switch on the compile line. In QuickC, the /F
 switch is entered by selecting Compiler Flags from the Options menu
 and then choosing Global Flags.

 For instance, if you add /F to the above mentioned screen and select
 the debug build option, the resultant compile line will ignore the
 CodeView option and you will not be able to debug your program. This
 occurs because the /F option is expecting an argument, which is
 intended to be the size you want the stack to be. Instead, the /Zi
 option, which comes next on the command line Quick C generates, gets
 interpreted as the argument specifying the stack size and doesn't get
 seen by the compiler as a compiler flag.

 Sample Command Line Generated by QuickC
 ---------------------------------------

    QCL /AL /Ze /F /Zi filename.c

 To correct this problem, add a number for the stack size.

 Microsoft has confirmed this to be a problem with QuickC version 2.50.
 We are researching this problem and and will post new information here
 as it is available.


 355. QuickC Quickwatch Has Three Help Pages

 Product Version(s): 2.50 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 11-NOV-1990    ArticleIdent: Q66515

 In QuickC, under the help for Quickwatch, there are only three pages
 to step through. However, the first and second pages incorrectly
 indicate that they are Pages (1 of 4) and (2 of 4). The third screen
 correctly indicates that it is Page (3 of 3).


 356. QuickC Version 2.50 Packing List (5.25-Inch Disk Set)

 Product Version(s): 2.50
 Operating System:   MS-DOS
 Flags: ENDUSER | packing.lst
 Last Modified: 18-NOV-1990    ArticleIdent: Q66901

 The following is the packing list located on disk 1 of the Microsoft
 QuickC Compiler, version 2.50, 5.25-inch disk set:

 Disk 1: Setup
 -------------

    Files                        Description
    -----                        -----------

    setup.exe                    Setup program -- installs compiler
    readme.doc                   Release notes for QuickC
    fixshift.com                 Fixes BIOS problem for some compatible
                                 keyboards
    msherc.com                   TSR to support Hercules card graphics
    qcc.ovl                      QuickC overlay for the integrated
                                 environment
    dospatch\patch320.doc        Patch files for PC-DOS 3.2 and MS-DOS
                                 3.20
    dospatch\setrhs.exe          " -- read the .DOC files for details
    dospatch\rmrhs.exe           "
    dospatch\stkpat.bat          "
    dospatch\stkpat.scr          "
    dospatch\patch87.doc         "
    dospatch\patch87.exe         "
    samples\samples.doc          Sample C programs
    samples\grdemo.mak           " -- read SAMPLES.DOC for details
    samples\grdemo.c             "
    samples\mouse.c              "
    samples\mouse.h              "
    samples\menu.c               "
    samples\menu.h               "
    samples\turtle.c             "
    samples\turtle.h             "
    samples\chrtdemo.mak         "
    samples\chrtdemo.c           "
    samples\chrtopt.c            "
    samples\chrtdemo.h           "
    samples\chrtsupt.c           "
    samples\life.mak             "
    samples\life.c               "
    samples\tools.c              "
    samples\tools.h              "

 Disk 2: Microsoft QuickC Advisor
 --------------------------------

    Files                        Description
    -----                        -----------

    qc.hlp                       Part 1 of Help on C and library functions

 Disk 3: Learning the Microsoft QuickC Environment
 -------------------------------------------------

    Files                        Description
    -----                        -----------

    qc.hl2                       Part 2 of Help on C and library functions
    learn.com                    Online tutorial and introduction to
                                 QuickC
    lc.pgm                       Tutorial support files
    qccbt.ctx                    "
    qccbt.scn                    "
    qccbt.sob                    "
    qcenv.hlp                    Help on the QuickC environment
    qa.hlp                       Stub help file for QuickAssembler

 Disk 4: Integrated Development Environment
 ------------------------------------------

    Files                        Description
    -----                        -----------

    qc.exe                       QuickC integrated programming environment
    qc.ini                       Default .INI file for QuickC(R)
    graphics.hlp                 Help on graphics functions

 Disk 5: Utilities
 -----------------

    Files                        Description
    -----                        -----------

    lib.exe                      Library maintenance utility
    qlink.exe                    Quick Linker
    nmake.exe                    Program maintenance utility
    nmk.com
    ilink.exe                    Incremental linker
    ilinkstb.ovl                 ILINK overlay
    mouse.com                    Mouse driver
    crlf.exe                     Removes CTRL characters and inserts CR/LF
    mkkey.exe                    Creates customized keyboard command files
    brief.key                    Keyboard files
    emacs.key                    "
    me.key                       "
    qc.key                       "
    epsilon.key                  "
    qcc.dat                      Data file used by QC environment
    qcl.msg                      Help on QCL

 Disk 6: Compiler
 ----------------

    Files                        Description
    -----                        -----------

    c1.err                       Error messages for QCL and QC
    qcl.err                      "
    qcl.exe                      Command-line compiler
    _qcl.exe                     Driver for command-line compiler
    errors.hlp                   Help on error messages
    include\assert.h             Include files -- read each file for
                                 details
    include\bios.h               "
    include\conio.h              "
    include\ctype.h              "
    include\direct.h             "
    include\dos.h                "
    include\errno.h              "
    include\fcntl.h              "
    include\float.h              "
    include\graph.h              "
    include\io.h                 "
    include\limits.h             "
    include\locale.h             "
    include\malloc.h             "
    include\math.h               "
    include\memory.h             "
    include\pgchart.h            "
    include\process.h            "
    include\search.h             "
    include\setjmp.h             "
    include\share.h              "
    include\signal.h             "
    include\stdarg.h             "
    include\stddef.h             "
    include\stdio.h              "
    include\stdlib.h             "
    include\string.h             "
    include\time.h               "
    include\varargs.h            "
    include\sys\locking.h        "
    include\sys\stat.h           "
    include\sys\timeb.h          "
    include\sys\types.h          "
    include\sys\utime.h          "

 Disk 7: Libraries 1
 -------------------
    Files                        Description
    -----                        -----------

    slibcr.lib                   Library for small model
    mlibcr.lib                   Library for medium model
    clibcr.lib                   Library for compact model
    slibfp.lib                   Floating point math library (small model)
    mlibfp.lib                   Floating point math library (medium
                                 model)
    mgraphfp.lib                 Graphics FP library (medium/large model)
    sgraphfp.lib                 Graphics FP library (small/compact model)
    c51stubs.lib                 Stub for Windows 2.03 libraries

 Disk 8: Libraries 2/Fonts
 -------------------------

    Files                        Description
    -----                        -----------

    llibcr.lib                   Library for large model
    clibfp.lib                   Floating point library (compact model)
    llibfp.lib                   Floating point library (large model)
    libh.lib                     General helper library
    87.lib                       Floating point library for math
                                 coprocessor
    em.lib                       Floating point library for emulator
    graphics.lib                 Graphics library
    pgchart.lib                  Presentation Graphics library
    crtcom.lib                   Library file for generating .COM files
    binmode.obj                  Changes default I/O from text to binary
    fileinfo.obj                 Allows child programs to inherit files
    setargv.obj                  Expands wildcard in command line
                                 arguments
    rmfixup.obj                  Removes interrupts, forces coprocessor
                                 math
    varstck.obj                  Allows heap and stack to compete for
                                 space
    txtonly.obj                  Allows graphics calls to be stubbed out
    font\courb.fon               Font files
    font\helvb.fon               "
    font\modern.fon              "
    font\roman.fon               "
    font\script.fon              "
    font\tmsrb.fon               "


 357. QuickC Version 2.51 Packing List (5.25-Inch Disk Set)

 Product Version(s): 2.51
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKASM packing.lst
 Last Modified: 18-NOV-1990    ArticleIdent: Q66902

 The following is the packing list located on disk 1 of the
 Microsoft QuickC Compiler with QuickAssembler, version 2.51,
 5.25-inch disk set:

 Disk 1: Setup
 -------------

    Files                        Description
    -----                        -----------

    setup.exe                    Setup program -- installs compiler
    readme.doc                   Release notes for QuickC
    fixshift.com                 Corrects BIOS problem for some compatible
                                 keyboards
    msherc.com                   TSR to support Hercules card graphics
    qcc.ovl                      QuickC overlay for the integrated
                                 environment
    dospatch\patch320.doc        Patch files for PC-DOS 3.2 and MS-DOS
                                 3.20
    dospatch\setrhs.exe          " -- read the .DOC files for details
    dospatch\rmrhs.exe           "
    dospatch\stkpat.bat          "
    dospatch\stkpat.scr          "
    dospatch\patch87.doc         "
    dospatch\patch87.exe         "
    samples\samples.doc          Sample C programs
    samples\grdemo.mak           " -- read SAMPLES.DOC for details
    samples\grdemo.c             "
    samples\mouse.c              "
    samples\mouse.h              "
    samples\menu.c               "
    samples\menu.h               "
    samples\turtle.c             "
    samples\turtle.h             "
    samples\chrtdemo.mak         "
    samples\chrtdemo.c           "
    samples\chrtopt.c            "
    samples\chrtdemo.h           "
    samples\chrtsupt.c           "
    samples\life.mak             "
    samples\life.c               "
    samples\tools.c              "
    samples\tools.h              "

 Disk 2: Microsoft QuickC Advisor
 --------------------------------
    Files                        Description
    -----                        -----------

    qc.hlp                       Part 1 of Help on C and library functions

 Disk 3: Learning the Microsoft QuickC Environment
 -------------------------------------------------

    Files                        Description
    -----                        -----------

    qc.hl2                       Part 2 of Help on C and library functions
    learn.com                    Online tutorial and introduction to
                                 QuickC
    lc.pgm                       Tutorial support files
    qccbt.ctx                    "
    qccbt.scn                    "
    qccbt.sob                    "
    qcenv.hlp                    Help on the QuickC environment

 Disk 4: Integrated Development Environment
 ------------------------------------------

    Files                        Description
    -----                        -----------

    qc.exe                       QuickC integrated programming environment
    qc.ini                       Default .INI file for QuickC (R)
    graphics.hlp                 Help on graphics functions

 Disk 5: Utilities
 -----------------

    Files                        Description
    -----                        -----------

    lib.exe                      Library maintenance utility
    qlink.exe                    Quick Linker
    nmake.exe                    Program maintenance utility
    nmk.com
    ilink.exe                    Incremental linker
    ilinkstb.ovl                 ILINK overlay
    mouse.com                    Mouse driver
    crlf.exe                     Removes CTRL characters and inserts CR/LF
    mkkey.exe                    Creates customized keyboard command files
    brief.key                    Keyboard files
    emacs.key                    "
    me.key                       "
    qc.key                       "
    epsilon.key                  "
    qcc.dat                      Data file used by QC environment
    qcl.msg                      Help on QCL

 Disk 6: Compiler
 ----------------

    Files                        Description
    -----                        -----------

    c1.err                       Error messages for QCL and QC
    qcl.err                      "
    qcl.exe                      Command-line compiler
    _qcl.exe                     Driver for command-line compiler
    errors.hlp                   Help on error messages
    include\assert.h             Include files -- read each file for
                                 details
    include\bios.h               "
    include\conio.h              "
    include\ctype.h              "
    include\direct.h             "
    include\dos.h                "
    include\errno.h              "
    include\fcntl.h              "
    include\float.h              "
    include\graph.h              "
    include\io.h                 "
    include\limits.h             "
    include\locale.h             "
    include\malloc.h             "
    include\math.h               "
    include\memory.h             "
    include\pgchart.h            "
    include\process.h            "
    include\search.h             "
    include\setjmp.h             "
    include\share.h              "
    include\signal.h             "
    include\stdarg.h             "
    include\stddef.h             "
    include\stdio.h              "
    include\stdlib.h             "
    include\string.h             "
    include\time.h               "
    include\varargs.h            "
    include\sys\locking.h        "
    include\sys\stat.h           "
    include\sys\timeb.h          "
    include\sys\types.h          "
    include\sys\utime.h          "

 Disk 7: Libraries 1
 -------------------

    Files                        Description
    -----                        -----------

    slibcr.lib                   Library for small model
    mlibcr.lib                   Library for medium model
    clibcr.lib                   Library for compact model
    slibfp.lib                   Floating point math library (small model)
    mlibfp.lib                   Floating point math library (medium
                                 model)
    mgraphfp.lib                 Graphics FP library (medium/large model)
    sgraphfp.lib                 Graphics FP library (small/compact model)
    c51stubs.lib                 Stub for Windows 2.03 libraries

 Disk 8: Libraries 2/Fonts
 -------------------------

    Files                        Description
    -----                        -----------

    llibcr.lib                   Library for large model
    clibfp.lib                   Floating point library (compact model)
    llibfp.lib                   Floating point library (large model)
    libh.lib                     General helper library
    87.lib                       Floating point library for math
                                 coprocessor
    em.lib                       Floating point library for emulator
    graphics.lib                 Graphics library
    pgchart.lib                  Presentation Graphics library
    crtcom.lib                   Library file for generating .COM files
    binmode.obj                  Changes default I/O from text to binary
    fileinfo.obj                 Allows child programs to inherit files
    setargv.obj                  Expands wildcard in command line
                                 arguments
    rmfixup.obj                  Removes interrupts, forces coprocessor
                                 math
    varstck.obj                  Allows heap and stack to compete for
                                 space
    txtonly.obj                  Allows graphics calls to be stubbed out
    font\courb.fon               Font files
    font\helvb.fon               "
    font\modern.fon              "
    font\roman.fon               "
    font\script.fon              "
    font\tmsrb.fon               "

 Disk 9: Microsoft QuickAssembler Advisor
 ----------------------------------------
    Files                        Description
    -----                        -----------

    qa.hlp                       Part 1 of Help on Assembler and DOS&BIOS
                                 functions

 Disk 10: Assembler
 ------------------
    Files                        Description
    -----                        -----------

    qa.hl2                       Part 2 of Help on Assembler, DOS & BIOS
                                 functions
    qas.ovl                      QuickAssembler overlay for integrated
                                 environment
    samples\qasample.doc         Sample Assembler programs
    samples\filedemo.mak         " -- read QASAMPLE.DOC for details
    samples\filedemo.c           "
    samples\file.asm             "
    samples\mathdemo.mak         "
    samples\mathdemo.c           "
    samples\math.asm             "
    samples\miscdemo.mak         "
    samples\miscdemo.asm         "
    samples\misc.asm             "
    samples\common.asm           "
    samples\demo.h               "
    samples\demo.inc             "






 Microsoft Programmer's Work Bench [Development Environment]
 =============================================================================


 1. Using the Features of PWB to Build a Program with Overlays

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q60050

 A MAKE file built with PWB can be modified (within reason) with the
 user supplied information section. This section, coded as

    # << User_supplied_information >>

 can contain other instructions that PWB (actually NMAKE or NMK) is
 supposed to carry out during the MAKE cycle. All instructions that
 follow this "fence" are not changed by PWB.

 The following instructions detail two implementations of that "fence"
 to allow PWB to build a program that uses overlays.

 While the following steps appear tedious, they are simple in practice.

 Once the changes are made, the only time you need to edit the MAKE
 file directly is to change your overlay structure, or to add or delete
 modules. When adding or deleting modules, you must both edit the
 program list with Make.Edit Program List and modify the commands in
 the user section. If you are only modifying the overlay structure, you
 change just the user section.

 The overlay structure in the example is as follows:

    HELLO.OBJ  (root)
        |
        +----A.OBJ (first  overlay)
        |
        +----B.OBJ (second overlay)

 All of the .OBJs are built from .C files with the same base name.

 1. Use PWB to build the program list in the normal way. This step is
    the same for any new program list.

    a. Start PWB.

    b. Choose Make.Set Program List and specify a new name -- HELLO.MAK
       in this example.

    c. Add HELLO.C, A.C, and B.C to the list. (If you have additional
       .C or .OBJ files, you would add them as well.) When all the
       files are listed, select Set Dependencies.

    d. Choose Options.Build Options and click on the Set Initial
       Build Options button and select DOS EXE.

    e. From Options.Compile Options, select the proper memory model.

    f. From Options.Link Options.Set Debug Options, turn off
       Incremental Link.

    g. From the Options.Browse Options dialog box, turn Generate Browse
       Information on.

    h. Choose Make.Rebuild All to make sure that the program builds
       properly without overlays. If it doesn't, review your work in
       previous steps.

 2. Now that you have a working program list, add the non-PWB
    information to the end.

    a. Choose Make.Clear Program List so that you can edit the MAKE
       file. Attempting to edit the current program list results in the
       message "No-edit file may not be modified."

    b. Choose File.Open to open the MAKE file so you can modify it.

    c. Go to the end of the file and start a blank line.

       Starting in column 1, add the following line:

          # << User_supplied_information >>

       Be sure to enter the line exactly as shown -- spacing is
       significant. This line is a "fence". Everything below the fence
       is yours and is not modified by PWB. Conversely, you should not
       modify anything above the fence because that section belongs to PWB.

    d. Below the fence starting in column one, add the pseudo-target:

          OVERLAID : $(OBJS)

       Be sure it starts column 1. Do not put a blank line after this line.

    e. Copy the command section from the $(PROJ).EXE description block
       to immediately follow the pseudo-target. The command section begins
       on the line following the line that reads

          $(PROJ).exe : $(OBJS)

       and ends at the next blank line. Do not copy the $(PROJ).EXE
       line, and do not leave a blank after the target. After you have
       copied the commands, your file should appear as follows:

          ... PWB section here, unmodified ...

          # << User_supplied_information >>

          OVERLAID : $(OBJS)
          !IF $(DEBUG)                    # copy of commands...
                  $(LRF) @<<$(PROJ).lrf
          $(RT_OBJS: = +^
          ) $(OBJS: = +^
          )
          $@
          ...

    f. Use the following procedure to modify the commands to link an
       overlaid EXE instead of a normal EXE.

       Note: There are two subsections in this section: a debug section
       that starts at the first "!IF $(DEBUG)" and ends at "!ELSE", and
       a release section that starts after the "!ELSE" and ends at the
       first "!ENDIF".

       You need to make the following modifications to both
       subsections.

       i. Delete the line that reads as follows:

             ) $(OBJS: = +^

          After the right parenthesis on the line that moved up, put
          your list of .OBJ files with parentheses to indicate which
          ones go in which overlays. If you need to use more than one
          line for all of your objects, be sure to put a plus sign (+)
          at the end of each line except the last.

      ii. Replace "$@" on the next line with "$(PROJ).EXE".

          In our example,

                 $(LRF) @<<$(PROJ).lrf
             $(RT_OBJS: = +^
             ) $(OBJS: = +^     # delete this line
             )                  # append OBJ list here ...
             $@                 # replace this line with $(PROJ).EXE

          becomes:

                 $(LRF) @<<$(PROJ).lrf
             $(RT_OBJS: = +^
             ) hello.obj +
             (a.obj) +
             (b.obj)
             $(PROJ).exe

          Remember to make the changes in both branches of the !IF
          $(DEBUG).

    g. The last step is to modify the browser database build commands.
       These are the two lines at the very end of the file that begin
       with "$(NMAKEBSC...". PWB adds and deletes these lines in the
       PWB section as you turn browser information on and off.

       Since PWB won't delete and add these lines in the user section,
       enclose them in !IF $(BROWSE)...!ENDIF so they'll be executed
       only when you ask for browse information. You also need to
       delete the "$(NMFLAGS)" macro from the second line to prevent
       infinite NMAKE recursion.

       The following lines

          $(NMAKEBSC1) MAKEFLAGS=
          $(NMAKEBSC2) $(NMFLAGS) -f $(PROJFILE) $(PROJ).bsc

       become:

          !IF $(BROWSE)
              $(NMAKEBSC1) MAKEFLAGS=
              $(NMAKEBSC2) -f $(PROJFILE) $(PROJ).bsc
          !ENDIF

       If you need special NMAKE options for building the browser
       database, just add them where you removed $(NMFLAGS).

 3. Reactivate the MAKE file by selecting Make.Set Program List.

 4. With these changes, if you select Make.Rebuild All, you will still
    get a non-overlaid program because PWB normally builds the first
    target in the MAKE file. To build the overlaid program, modify the
    command line passed to NMAKE so that NMAKE builds your overlay
    target rather than the regular EXE. Select Options.NMAKE Options
    and specify "OVERLAID" as the target by putting it in the NMAKE
    options box, or use Make.Build Target.

 5. With "OVERLAID" in Options.NMAKE Options you can build your program
    by either selecting Make.Rebuild All or Make.Build *.EXE, as usual.
    If you want to build a non-overlaid program, delete "OVERLAID" from
    the NMAKE options box.

    Note that if you use debug options with overlays you will get a
    linker warning L4047. This warning, and the dialog box that says
    that CRT0DAT.ASM can't be found, are normal when building overlaid
    programs for debugging and can be ignored. You can debug the overlaid
    program normally, with full debugging information available.

    This MAKE file behaves almost identically to a regular PWB MAKE
    file. The only differences are that NMAKE options are NOT  passed
    to the browser build unless you add them to the browser build line,
    and that you must edit the user supplied section if you add or
    delete modules from the project.


 2.

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00 fixlist1.10 s_c
 Last Modified:  5-FEB-1991    ArticleIdent: Q60392

 TOOLS.PRE is a sample Programmer's WorkBench (PWB) initialization file
 that is installed (and modified) when C 6.00 is installed by running
 the Setup program. On pages 19 and 20 of "Microsoft C: Installing and
 Using the Professional Development System," it states that the
 contents of TOOLS.PRE can be merged with an existing TOOLS.INI file,
 if one exists, or it can be renamed to TOOLS.INI, if there isn't one.
 To work correctly, you must make sure that the contents of this file
 are preceded by a PWB tag (for example, [PWB]) because the supplied
 TOOLS.PRE lacks this tag.

 When merging the PWB 1.00 TOOLS.PRE file into an existing TOOLS.INI
 file, a [PWB] tag should be added just above the area where the file
 is merged. For example:

 [PWB]
   .
   .
   .
   (TOOLS.PRE contents)
   .
   .
   .

 [NEXT-TAG]

 If TOOLS.PRE is being renamed to TOOLS.INI, the tag should be added as
 the first line in the file. In either case, failure to add the tag
 will result in PWB ignoring the initialization information.

 Microsoft has confirmed this to be a problem in PWB version 1.00. This
 problem was corrected in PWB version 1.10.


 3. How to Abort Compilation When Using PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_c
 Last Modified: 17-JUL-1990    ArticleIdent: Q60500

 Question:

 How do I abort a compile that is in progress when using the
 Programmer's WorkBench (PWB) environment?

 Response:

 Under MS-DOS (or the OS/2 3.x compatibility box), use CTRL+C to abort.

 Under OS/2, use "Arg Meta Compile" to abort a compilation taking place
 in the background.

 The default keystrokes for Arg Meta Compile are ALT+A F9 CTRL+F3.

 You can also create a macro and assign it to a key to abort the
 compile process. Below is a sample macro that you could place in your
 TOOLS.INI file under the [pwb] tag.

    [pwb]
    Abort:=Arg Meta Compile
    Abort:Ctrl+F5

 Note: In either OS/2 or MS-DOS, the ESC key and CTRL+BREAK do not
 abort a compilation.


 4. PWB Makefiles Are Read-Only When Set as Active Program List

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q60749

 When you choose the Make.Set Program List option within the
 Programmer's WorkBench (PWB) environment to set a program list for the
 current project, the makefile associated with the current program list
 is marked as read-only and is not editable.

 Code Example
 ------------

 // FOO.C

 #include <stdio.h>
 void main ( void )
 {
    printf ( "Foobar\n" ) ;
 }

 1. Using the above sample program, choose the Make.Set Program List
    menu options and call the program list FOO.MAK.

 2. Save the list.

 3. Choose the File.Open menu, and enter FOO.MAK as the file you want
    to open.

 4. Place your cursor anywhere in the file and press ENTER. You will be
    greeted with the following a pop-up message:

       No-edit file may not be modified.

 If you want to edit the makefile, choose the Make.Clear Program List
 options, and you can edit the makefile as you want.


 5. Why Zero-Length .SBR Files Are Left on the Disk by the PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 16-JAN-1991    ArticleIdent: Q61056

 When using the Source Browser functionality within the Programmer's
 WorkBench, you can expect to have zero-length .SBR files on your disk.
 This is by design of the PWBRMAKE utility.

 PWBRMAKE.EXE is a utility that converts the .SBR files created by the
 compiler for each program module into a single database file that can
 be read by the Programmer's WorkBench (PWB) Source Browser. The
 resulting Source Browser database file has the extension .BSC.

 When a Source Browser database (a .BSC file) is built from .SBR files,
 the .SBR files are truncated to zero length to save disk space since
 they can be quite large. .SBR files are truncated to zero length,
 rather than being deleted, because PWBRMAKE performs incremental
 updates to the database and, therefore, needs the time and date stamp
 from the files.

 When you rebuild part of your project, new .SBR files are built for
 those modules. Each .SBR file that has not been re-created during a
 build is included as a zero-length file. This tells PWBRMAKE that the
 file has no new contribution to make to the database, so no update of
 that part of the database is required.


 6. Do Not Start Programmer's WorkBench by Typing PWBED

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61307

 You cannot start the Programmer's WorkBench by typing PWBED. This is
 incorrect. Type PWB to start the Programmer's WorkBench environment.

 In the REAL MODE directory specified during setup, there will be two
 executables for the PWB, PWB.COM and PWBED.EXE. PWB.COM actually
 spawns PWBED.EXE. If you use PWBED to start the PWB, it will consume
 approximately 500K of memory. By executing a DOS SHELL from within the
 PWB and running CHKDSK, you will notice there is very little memory
 left.

 When you invoke the PWB the correct way (by typing PWB), then shell-
 out and do a CHKDSK, you will see that the PWB has only consumed
 approximately 8K of available memory.

 The PWB appears to work correctly if you invoke it with PWBED.
 However, since it is using so much memory, you will receive memory
 problems, such as "out of memory," "cannot compile," or "cannot
 build." These are caused because there is not enough memory to spawn
 either NMAKE, the compiler, or the linker.


 7. Steps Needed to Make Source Browser Usable

 Product Version(s): 1.00    | 1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61309

 Before using the Browse menu options, you must first define and build
 the database the Source Browser will use. If this database is not
 already built, all options on the Browse menu will be grayed out and
 unusable.

 The following steps must be taken to define a database that is usable
 by the Source Browser menu options:

 1. Generate a program list using the Set Program List command in the
    Make menu. The PWB creates one internally if you do not specify one
    and the program only uses one source file. If a program is larger
    than one source file and a program list is not set, it is
    impossible to generate a Source Browser database.

 2. Choose Browse Options from the Options menu. You must select the
    Generate Browse Information field in the dialog box to create the
    Source Browser database.

 3. Build your program using the Make Menu option. You MUST have a
    successful build (compile AND link) of the program for a Source
    Browser database to be generated.

 The Browse Menu options should now be available for use.

 If, after taking the steps outlined above, the Browse Menu options
 are still unavailable for use, query on the following keywords:

    Browse and Options and Unavailable and Strange and Circumstances
 For printed documentation explaining the setup and use of the Source
 Browser, see Pages 50-52 of "Installing and Using the Professional
 Development System." You can also find information about the Source
 Browser in the online help under Programmer's WorkBench, Using the PWB
 Source Browser.


 8. SYS2070 Issued When Executing PWB.EXE for the First Time

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 13-JUN-1990    ArticleIdent: Q61572

 When running the Programmer's WorkBench (PWB) for the first time, the
 following OS/2 system error may be issued:

    Session Title:
    PWBED.EXE

    SYS2070: The system could not demand load the
    application's segment. MSHELP HELPSHRINK is in error.
    For additional detailed information also see message SYS0127

 This system error is caused by the PWB's use of a version of
 MSHELP.DLL that is not as current as the one that was shipped with C
 version 6.00. For the PWB to function correctly, the correct version
 of MSHELP.DLL must be in the LIBPATH.

 The README.DOC on the C version 6.00 Setup/Compiler 1 Disk warns of
 this potential problem, and suggests that QuickHelp (QH) be terminated
 as a background keyboard monitor before Setup is run.

 This problem is usually caused as a result of the Setup program not
 being able to copy its version of MSHELP.DLL over the old version of
 MSHELP.DLL. If another process (most likely a detached session of
 QH.EXE) was accessing this file during the execution of Setup, the
 Setup program will issue a message similar to the following:

    ERROR: Could not create file C:\OS2\DLL\mshelp.dll
    ERROR: File copy failed: A:\the PWB\mshelp.dll to C:\OS2\dll\mshelp.dll

 To solve this problem, take the following steps:

 1. Disable QH as a keyboard monitor:

    a. Press ALT+Q (to invoke QH).

    b. Press O (for the Options menu).

    c. Press T (to Terminate the monitor).

 2. Copy the up-to-date version of MSHELP.DLL from the distribution
    disk:

    a. Insert the Setup/Compiler 1 Disk into Drive A.

    b. Change the default Drive A.

    c. Run Setup with the /copy option by typing the following:

          setup /copy

    d. Press ENTER

    e. Press ENTER again (unless the setup files are in a drive other
       than A).

    f. At the prompt asking for the name of the file to copy, type
       MSHELP.DLL and press ENTER.

    g. At the prompt asking for the name of the directory to which to
       copy this file, type the directory in which the old MSHELP.DLL
       is located (most likely C:\OS2\DLL).

    h. Setup should then ask for the Programmer's WorkBench/Utilities
       for OS/2 Disk to be inserted into the setup drive.

    i. When Setup is finished copying the file, press ENTER at the
       next prompt.

 The PWB should now start up correctly.


 9. U1355 Bad Command or File Name

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr filename
 Last Modified: 27-SEP-1990    ArticleIdent: Q61607

 The following undocumented error may occur when attempting to run an
 executable file such as CL.EXE, LINK.EXE, NMAKE.EXE, etc., from inside
 the Programmer's WorkBench (PWB).

    U1355 Bad Command or File Name

 The error occurs because the directory containing the .EXE file is not
 specified in the search path or an incorrect LINK.EXE is being
 executed.

 This problem can be corrected by adding the missing directory name(s)
 to the path in the AUTOEXEC.BAT or STARTUP.CMD and rebooting, or
 executing NEW-VARS.BAT or NEW-VARS.CMD. If an incorrect linker is the
 problem, the search path can be rearranged to find the new version of
 the linker first, or the old linkers can be deleted or renamed.
 Finally, it may be necessary to delete the CURRENT.STS and PROG.STS
 files before the PWB will work correctly. This error is not documented
 in the PWB online help.


 10. Saving Compiler Results File in the PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-MAY-1990    ArticleIdent: Q61636

 The Programmer's WorkBench (PWB) deletes the compiler results file
 upon exiting the PWB. In DOS or OS/2, the file can be saved if the
 compiler results window is made current and the File.Save As menu
 option is selected.

 The compiler results file will appear similar to the following:

    +++ PWB  [E:\] Rebuild
            NMAKE  /z /a /f E:\pwb.mak
         cl /c /W4 /Fm /Ot /FoGLOBL.obj GLOBL.C
    Microsoft (R) C Optimizing Compiler Version 6.00
    Copyright (c) Microsoft Corp 1984-1990. All rights reserved.

    GLOBL.C
         echo @GLOBL.lrf > NUL
         link @GLOBL.lrf

    Microsoft (R) Segmented-Executable Linker  Version 5.10
    Copyright (C) Microsoft Corp 1984-1990.  All rights
    reserved.

    Object Modules [.OBJ]: GLOBL.obj,GLOBL.exe,NUL, /NOD:SLIBCE
    SLIBCEP , /NOI /BATCH /EXE /FAR /PACKC;


 11. Programmer's WorkBench Edit Switch Is Unimplemented

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 14-MAY-1990    ArticleIdent: Q61642

 The edit switch for the Programmer's WorkBench (PWB), documented on
 Page 79 of the version 6.00 "Microsoft C Reference" manual, is
 unimplemented in PWB version 1.00. The switch is designed to set the
 active file as read-only so that it cannot be edited.

 If you add an option in your TOOLS.INI file under the PWB tag to read
 either

    Edit:yes
    Edit:no

 PWB will return an error message saying "Edit is not an editor
 switch."

 As a workaround, invoke PWB with the /r option to open up the current
 file as read-only.


 12. Certain Key Sequences Cause R6003 or SYS1943 in PWB 1.00

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00 fixlist1.10
 Last Modified:  4-FEB-1991    ArticleIdent: Q61660

 In the Programmer's Workbench (PWB) version 1.00, it has been observed
 that certain unusual editing sequences can cause the following errors:

 In DOS:

    Run-time error R6003 - integer divide by 0

 In OS/2:

    SYS1943 protection violation, trap number 13

 The following sequences reproduce the errors:

    Procedure                             Keystrokes
    ---------                             ----------

 1. Bring up several files.               ALT+F O x3
    Select the Options menu.              ALT+O
    Select Linker options.                L
    Select Set Debug Options.             ALT+G
    Pull up help on the options.          F1
    Arg-refresh through several files.    ALT+A SHIFT+F7 x3
    Escape back to the Editor screen.     ESC x3

 2. Select the Options menu.              ALT+O
    Select Editor Settings.               S (or K)
    Go down thirteen lines.               DOWN ARROW key x13
    Backspace.                            BACKSPACE
    Undo.                                 ALT+BACKSPACE

 Note: Step 2 reproduces only the R6003 error in DOS, not the SYS1943
 error.


 13. PWB 1.00 Requires Decimal Value for Stack Size in LINK Options

 Product Version(s): 1.00    | 1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist1.00 fixlist1.10
 Last Modified:  5-FEB-1991    ArticleIdent: Q61871

 In the Programmer's WorkBench (PWB) version 1.00, there is a problem
 with changing a program's stack size in some situations. When
 specifying the stack size in the Link Options dialog box (from the
 Options menu), you must enter the value in the form of a decimal
 integer. Although the Help menu tells you this field accepts positive
 integers in octal and hexadecimal form, PWB 1.00 will not accept them.

 When an octal or hexadecimal value is entered in the stack-size field,
 any digits specified as A-F are discarded and replaced by 0 (zero). If
 digits precede a letter, the digits are retained and the letters are
 discarded.

 Microsoft has confirmed this to be a problem in PWB version 1.00. This
 problem was corrected in PWB version 1.10.


 14. SYS0002 Produced If MSHELP.DLL Not Installed

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | pwbhelp
 Last Modified: 23-JAN-1991    ArticleIdent: Q61955

 Under OS/2, if MSHELP.DLL is not installed correctly or is not on the
 LIBPATH, the following error may appear in a window when starting the
 Programmer's WorkBench (PWB):

                     Cannot Autoload Extension
                     e:\c600\binp\pwbhelp.pxt
 MSHELP:  SYS0002:  The system cannot find the file specified

                         < OK >   < Help >

 Make sure that the latest version of MSHELP.DLL (the one that was
 included with the Microsoft C Compiler version 6.00) is installed in a
 directory contained in your LIBPATH.

 If this file was not copied off the disks during setup, you can
 execute the following command with your Setup disk in Drive A:

    a:setup /copy

 Specify the file MSHELP.DLL at the prompt, then specify the
 destination directory.

 The default for SETUP.EXE is to put OS/2 DLLs in the C:\OS2\DLL
 directory. If you choose to install the DLLs in some other directory,
 you must edit the LIBPATH in your CONFIG.SYS file and restart the
 system.


 15. Enabling of Source Browser Menu Related to .BSC and .MAK Files

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-MAY-1990    ArticleIdent: Q61968

 The Source Browser feature of the Programmer's WorkBench (PWB) is
 enabled or disabled depending upon the existence of a database file
 (.BSC file) AND a program list (.MAK file). The existence of a .BSC
 database file alone does not guarantee that the Browse menu will be
 enabled for all modules in a project, even if the .BSC file was built
 from .SBR files for every module. The setting of a program list is
 also required.

 Thus, if a .BSC file is built outside of the PWB with PWBRMAKE, then
 upon entering the PWB, the Browser will be enabled for only one module
 at most (see below). The easiest method to enable the Browse menu for
 ALL modules is to select "Set program list" on the Make menu, then
 type in the base name of the .BSC file (with the .MAK or no extension)
 when it prompts you for the filename. If the .MAK file you enter does
 not exist, then the dialog box appears for adding files to the program
 list, whereas you can just select "Save List" without actually adding
 any files. At this point, the Browser menu will be enabled for all
 files you bring up into the PWB editor.

 The existence of a Source Browser database file means that the Browse
 menu will be enabled for a source file with a matching base name of
 the .BSC file.

 For example, assume a project consists of several modules, with the
 main source module called PROJECT.C. In addition, assume a Browser
 database file called PROJECT.BSC is built from the .SBR Browser
 information files produced by the compiler for every module in this
 project. If the file PROJECT.C is brought up in the PWB, the Browse
 menu will be enabled because the base name (PROJECT) is the same as
 the base name of the database file PROJECT.BSC.

 On the other hand, if any of the other source files in the project are
 opened in the PWB, the Browse menu will be disabled because the base
 names do not match the base name of the database file. Also, if
 PROJECT.C is made the current file (which enables the Browse menu) and
 an option is selected on the browse Menu, such as "Goto Reference"
 (which causes a jump to a different module), the Browse menu will
 become disabled. The only way to re-enable the Browse menu in this
 case is to make PROJECT.C the current file again.

 The way to enable the Browse menu for all modules is to set a program
 list to a file with the .MAK extension and the same base name as the
 .BSC file. Thus, in the example above, setting the program list to
 PROJECT.MAK will enable the Browse menu for all modules. In fact, this
 connection between the .BSC file and the .MAK file enables the Browse
 menu for the modules in the current project, and for ANY file opened
 under the PWB.

 The result is that if you bring up a file in the editor that is
 completely unrelated to the current project (and may not even have a
 related .BSC file), you can still use the Browse menu options.
 However, in this situation, the information available from the Browser
 still only pertains to the original project.

 In summary, the .MAK file and .BSC file relationship is based solely
 on the file existence, NOT the file contents. The program list does
 NOT need to contain the names of the modules in the current project
 (or even be an actual makefile) for the Browser to function.


 16. Modifying TOOLS.INI May Have No Effect on PWB Environment

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q62170

 Changing settings in the TOOLS.INI file to modify the behavior of the
 Programmer's WorkBench (PWB) may not work under certain circumstances.
 For instance, if you decide to change the PWB to 50-line mode by
 setting "height:50" in the TOOLS.INI file, it will not work if the PWB
 was previously used in the 25- or 43-line mode.

 This is because some environment information is also recorded in the
 CURRENT.STS file, which is read in after the TOOLS.INI file --
 overriding the TOOLS.INI settings.

 The following are three workarounds for this problem:

 1. Use the /DS switch when invoking the PWB. This will ignore the
    CURRENT.STS file. However, this option also causes the current file
    history (of files being edited) to be ignored.

 2. Delete the CURRENT.STS file. This also causes the current list of
    programs being edited to be ignored.

 3. The better option is to select Editor Settings from the Options
    menu. When the list of editor switch settings appears, it can be
    changed and saved to the TOOLS.INI file by pressing SHIFT+F2. This
    will save the settings and cause the selection to take effect.


 17. Reversing Mouse Buttons in the PWB Cannot Be Done

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q62330

 Currently under the Programmer's WorkBench (PWB) released with version
 6.00 of the Microsoft C Optimizing Compiler, it is not possible to
 reverse the functionality of the mouse buttons.

 It is possible to change the functionality of the mouse buttons under
 OS/2 and DOS, but this will be overridden by the PWB environment.


 18. Attempting to Expand a Help Dialog Box Hangs DOS

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q62331

 When one of the pull-down menus in the Programmer's WorkBench (PWB)
 version 1.00 is selected (File, Edit, View, etc.) and then F1 is
 chosen for help on that menu, a small help screen appears. If CTRL+F10
 is chosen in an attempt to expand the window to full screen, the
 machine will hang under DOS. If the machine doesn't hang, it may
 require another invocation of CTRL+F10 to cause the problem.

 Under OS/2, the machine may not hang, but the PWB's functionality will
 be disrupted and attempts to free oneself may cause a GP fault. It may
 be possible to exit the PWB, but at the very least, the CURRENT.STS
 file will be corrupted so that future entrances to PWB will result in
 very odd window configurations.

 Microsoft has confirmed this to be a problem with the PWB version
 1.00. We are researching this problem and will post new information
 here as it becomes available.


 19. PWB Doesn't Update Mark Location If Mark Moves Up or Left

 Product Version(s): 1.00 | 1.00
 Operating System:   OS/2 | 1.00
 Flags: ENDUSER | buglist1.00
 Last Modified: 13-JUN-1990    ArticleIdent: Q62388

 If you set a mark in a file, and that location then moves upward or
 toward the left in the file, PWB does not reset the mark location;
 however, it does correctly update marks that move downward or to the
 right in the file.

 Consider the following file:

 /* Test.dat */
 test1

 test2

 test3

 Place the cursor on the "2" in test2. Choose the Search.Define Mark
 menu option. Name the mark "mark1" and press ENTER. Now, move the
 cursor to another location in the file. Choose the Search.Go To Mark
 option from the menus. Go to "mark1". Note that the cursor is back on
 the "2" in test2.

 Next, add another blank line between test1 and test2. Again, move your
 cursor and go to mark1. Note that the cursor is back on the "2" in
 test2.

 Now, delete both the lines between test1 and test2. Select the
 Search.Go To Mark option from the menus. Note that the cursor is on
 the same location as it was before you deleted these lines. The same
 behavior will happen if you delete any of the characters before the
 "2" in the test2 line.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench (PWB) version 1.00. We are researching this problem and will
 post new information here as it becomes available.


 20. PWB 1.00 "Set Dependencies" Fails with Spaces in #include Line

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00 fixlist1.10 s_c
 Last Modified:  5-FEB-1991    ArticleIdent: Q62578

 The Programmer's WorkBench (PWB) version 1.00 (shipped with C version
 6.00) includes a "Set Dependencies" option in the "Set Program List"
 window. This option automatically sets up build dependencies for all
 include files used in the current project. This option will fail with
 a message that the include file does not exist if there are embedded
 spaces between the left angle bracket (<) and the include-file name in
 an include directive line.

 The Set Dependencies option will work correctly if the space(s) are
 removed or if a new build option is added to the TOOLS.INI file.

 Although embedded spaces are legal in C programming syntax, the
 Programmer's WorkBench fails to parse the include line correctly if
 spaces exist before the filename. The following line of code shows the
 situation where the "Set Dependencies" error will occur:

    #include < stdio.h >

 The space before the "s" in stdio.h prevents PWB from finding the
 STDIO.H include file. (The trailing space after stdio.h does not
 affect the behavior of "Set Dependencies".)

 The full text of the error message window for the line above is as
 follows:

         stdio.h does not exist
    Cannot build its dependency tree.
    Abort dependency lists generation?
         <Yes>    <No>    <Help>

 Selecting <Help> displays a help screen that describes the problem as
 being either a mistyped filename or a nonexistent file, but the actual
 file DOES exist. Removing the embedded space will correct the problem.

 You can also add two new "build" lines to the TOOLS.INI file to make
 the PWB recognize include directives that contain spaces. These lines
 should be included under the section with the [PWB] tag, and should
 have the following syntax:

    build: include .c                                              \
        "^[ \t]*#[ \t]*include[ \t]*\"[ \t]*\\([^\"]+[ \t]*\\)\""  \
        case
    build: include .c                                              \
       "^[ \t]*#[ \t]*include[ \t]*<[ \t]*\\([^>]+\\)[ \t]*>"      \
        case system

 (Note: These build switch statements are broken down into multiple
 lines with the line continuation character (\) because of space
 limitations; you may enter each of them into the TOOLS.INI file on a
 single line, rather than multiple lines.)

 There is one drawback to this workaround; you will still get the error
 message shown above because the "old" build switch is applied before
 the new one. To have the new build switch take effect, you need to
 select "No" when prompted to abort the dependency list generation.
 Once you have selected "No" for each file with spaces in the include
 directive, the dependencies will then be generated correctly.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench version 1.00. This problem was corrected in the Programmer's
 WorkBench version 1.10.


 21. PWB 1.10 Dialog Boxes May Blink After Dialog Help Is Obtained

 Product Version(s): 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.10 flicker
 Last Modified: 19-FEB-1991    ArticleIdent: Q69347

 When working with the Programmer's WorkBench (PWB) version 1.10 under
 DOS, there are several instances where a dialog box may start flashing
 incorrectly. This situation occurs when you obtain help on a PWB
 informational pop-up dialog box and then return from the Help dialog
 screen. At this point you may find that the original dialog box is
 rapidly blinking.

 This problem may occur when trying to get help on a topic for which
 there is no help, trying to use an unassigned key, or when PWB informs
 you that you changed a file but didn't save it before you tried to
 exit. In each of these cases, PWB gives you a pop-up dialog box
 informing you of the situation. If you get help on this informational
 dialog box and then press ESC or click Cancel, the original dialog box
 will start blinking.

 This is not normal behavior, however, PWB is still fully functional
 and you may proceed by selecting an appropriate choice from the
 flashing dialog box.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench version 1.10. We are researching this problem and will post
 new information here as it becomes available.


 22. R6000 Stack Overflow After Deleting Current Makefile

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q62668

 If you are viewing your makefile in a window in PWB 1.00, then delete
 the makefile from a shell; attempting to make the window containing
 the makefile active will cause a run-time error R6000, stack overflow.

 To duplicate this problem, bring up a sample program and set the
 program list to that file's makefile. Next, open up another window
 and open the makefile in that window. Now, either from the Run.Run
 <DOS-OS/2> Command menu or the File.<DOS-OS/2> Shell, delete that
 makefile.

 After returning back to the PWB, make the window containing the
 makefile the active program list either by pressing the F6 key to
 toggle windows or by clicking the left mouse button in that window.

 You will be faced with a popup message saying "File has been deleted
 from disk. Delete from memory?" Answering "yes" brings up the popup
 six to eight more times. Then, PWB will abort to the system prompt
 with an R6000 (stack overflow) error message and another message, "File
 has been deleted from disk."

 Microsoft has confirmed this to be a problem in PWB version 1.00. We
 are researching this problem and will post new information here as it
 becomes available.


 23. PWB 1.00 Extensions Only Return True Under DOS

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00
 Last Modified: 15-AUG-1990    ArticleIdent: Q63052

 Extensions written for use by the Programmer's WorkBench (PWB) version
 1.00 under the DOS operating system are recognized as returning true
 regardless of their actual return values.

 The use of return values as a way of providing conditional jumps
 inside PWB macros is a common practice that is affected by the above
 limitation for PWB extensions. The following sample extension and
 macro demonstrate the above problem. Once installed, both the foo()
 and foo2() functions will be seen as returning true to PWB.

 Sample Code
 -----------

 // foo.c

 #include <string.h>
 #include <stdlib.h>
 #include <ext.h>

 PWBFUNC foo( unsigned argData, ARG far *pArg, flagType fMeta );
 PWBFUNC foo2( unsigned argData, ARG far *pArg, flagType fMeta);

 // Switches.
 struct swiDesc swiTable[] =
 {
    { NULL, NULL, 0 }
 };

 // Commands.
 struct cmdDesc cmdTable[] =
 {
    { "foo", foo, 0, NOARG },
    { "foo2",foo2,0, NOARG },
    { NULL, NULL, 0, 0 }
 };

 void EXTERNAL WhenLoaded()
 {
     SetKey( "foo",         "alt+f" );
     SetKey( "foo2",       "ctrl+f" );
     return;
 }

 PWBFUNC foo( unsigned argData, ARG far *pArg, flagType fMeta )
 {
  return(FALSE);  /* FALSE is defined as 0 in ext.h */
 }

 PWBFUNC foo2( unsigned argData, ARG far *pArg, flagType fMeta)
 {
  return(TRUE);   /* TRUE is defined as 1 in ext.h  */
 }

 // End of foo.c

 ; macros in tools.ini to test foo and foo2

 load foo

 test:=foo ->loc1 arg "true" message => :>loc1 arg "false" message
 test2:=foo2 ->loc2 arg "true" message => :>loc2 arg "false" message

 test:alt+t
 test2:ctrl+2

 Microsoft has confirmed this to be a problem with PWB version 1.00. We
 are researching this problem and will post new information here as it
 becomes available.


 24. PWB Text Highlight with Mouse Acts Strange After Search

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q63059

 The click-and-drag method of selecting text with the mouse in the
 Programmer's Workbench (PWB) sometimes works incorrectly when used
 after a search function.

 To reproduce this problem, do the following:

 1. Select a word in the text using the mouse (double-click on a single
    word).

 2. Execute the search function (select the Search menu, choose Find,
    then OK).

 3. Now try to highlight the text a few lines below the word you used
    to search on (using the click-and-drag method).

 The text will be highlighted starting at the original word that was
 searched for, rather than at the starting mouse position.

 To work around this problem, click the left button anywhere in the
 text window, then perform the text highlight.

 Microsoft has confirmed this to be a problem with the Programmer's
 Workbench version 1.00. We are researching this problem and will post
 new information here as it becomes available.


 25. PWB Does Not Return from DOS Shell with ";" in TMP

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q62702

 If there is a semicolon ";" in your TMP environment variable, you may
 not be able to return to the Programmer's Workbench by typing "exit"
 after selecting "DOS Shell" from the File menu in PWB.

 Since the TMP environment variable is used to specify a single
 directory rather than a path, the semicolon character should not be
 used.

 To re-create this situation, type the following at the command line:

    set TMP=C:\TMP;

 Then select DOS Shell from within PWB. Typing "exit" on the DOS
 command line will not bring you back into PWB.

 To correct the problem, remove the semicolon from the end of the TMP
 environment variable.


 26. PWB BACKUP.BAK Does Not Create Backup of Source File Correctly

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER| buglist1.00
 Last Modified: 24-JUL-1990    ArticleIdent: Q63234

 Version 1.00 of the Programmer's Workbench does not create a backup of
 your source file correctly if the PROJECT.MAK has the same base name
 as the SOURCE.C file. When you build or rebuild the project, the file
 saved as your backup is a copy of the CURRENT.STS file.

 A workaround to this problem is to name your PROJECT.MAK with a
 different base name than your SOURCE.C file. This will still save a
 copy of your CURRENT.STS file with the base name of the PROJECT.MAK.
 However, it will correctly save a backup of the SOURCE.C as
 SOURCE.BAK.

 Microsoft has confirmed this to be a problem in version 1.00 of the
 Programmer's Workbench and will post new information here as it
 becomes available.



 27. PWB menukey Switch Resets to ALT When Shelling Out to DOS

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00
 Last Modified: 10-JUL-1990    ArticleIdent: Q63267

 If the "menukey" switch in the DOS version of the Programmer's
 Workbench (PWB) version 1.00 is set to anything other than ALT (which
 is the default), it will be redefined to the ALT key after shelling
 out to DOS. This means the menukey switch will lose its assignment
 anytime you choose Compile, Run Program, Debug Program, or DOS Shell.

 The menukey switch determines which keystroke activates the PWB main
 menu bar. The ALT key is normally used for this, but menukey can be
 redefined to any keystroke. For example, menukey is automatically
 defined to F9 if you select Brief Editor emulation when installing the
 Programmer's WorkBench.

 Whenever you invoke any function (such as Build) that goes out to DOS
 for execution and then returns, the menukey switch is reset to ALT, so
 that both ALT AND the user-defined keystroke invoke the menu.

 To work around this problem, you can use the Restart command to invoke
 a macro that redefines the menukey to the desired value each time you
 return from a DOS SHELL command, which will then keep ALT from
 activating the menu. For example, to make it so that F9 is always
 reset as the only menukey, put the following line in the PWB tagged
 section of the TOOLS.INI file:

    restart:= arg "menukey:F9" assign

 Since the Restart command, if it exists in TOOLS.INI, is invoked
 automatically when returning from a SHELL command, this guarantees
 that the key assignment will always remain consistent.

 Microsoft has confirmed that the automatic reactivation of ALT as the
 menukey is a problem with the Programmer's WorkBench version 1.00. We
 are researching this problem and will post new information here as it
 becomes available.


 28. PWB: Print Does Not Put CR/LF at EOL If Text Selected

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q63318

 Using the Programmer's Workbench version 1.00, when a region of text
 is selected and the Print function is invoked, the resulting output
 contains linefeed characters (0x0A) at the end of each line, rather
 than a carriage return/linefeed (<CR><LF>) combination (0x0D and
 0x0A).

 Some printer drivers do not recognize this as a valid end-of-line
 (EOL) character and do not print correctly.

 To reproduce this problem, open a file that contains the <CR><LF>
 combination at the end of each line. Highlight a region of text in the
 file and from the File menu choose Print. Tab to the second field and
 type in the following:

    copy %s test.txt

 This will copy the region of selected to the file TEST.TXT. Using a
 standard hex file viewer, you can see that the end of a line is
 denoted by a single 0A. If you look at the original file using the hex
 viewer, it will contain 0A 0D at the end of each line.

 The Programmer's Workbench will recognize this type of file (with a
 single 0A at each end of line) and display it correctly if you try to
 open it within the Workbench, but many printer drivers do not
 understand this type of file.
 The workaround for this problem is to write a program that translates
 each 0x0A found in the output file to the bytes 0x0D and 0x0A, or use
 a printer driver that understands this type of file. In fact, most
 printers have an escape sequence or dip switch to make it recognize
 this type of file.

 Microsoft has confirmed this to be a problem with the Programmer's
 Workbench version 1.00. We are researching this problem and will
 post new information here as it becomes available.


 29. Unknown Function psrch with Brief Emulation in PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q63319

 When using the Brief emulation feature of the Programmer's WorkBench
 version 1.00, reinitialization of the TOOLS.INI file will cause a
 number of unknown functions to appear when you try to use them. In
 short, most of the unknown functions that may be reported are related
 to search features such as the psearch switch. The error message
 associated with this search feature is commonly "Unknown function
 psrch."

 This error occurs only after you use the Initialize function.

 The Initialize function discards current macro definitions and rereads
 the appropriate section of TOOLS.INI. This is not exactly the same as
 restarting PWB; the Autostart macro is not executed after Initialize.
 The BRIEF emulation depends on the Autostart macro to define the
 search functions.

 To recover the definition of the missing macros, execute the toggle_re
 BRIEF emulation macro (CTRL+F6). To avoid having to remember to
 execute this macro, you can add this to the main section of TOOLS.INI:

    reinit:=Initialize Autostart
    reinit:Shift+F8

 Or you can define the macros as follows:

    psrch:=arg arg "String to Search for" prompt ->can
                                            psearch => :>can cancel
    msrch:=arg arg "String to Search for" prompt ->can
                                            msearch => :>can cancel
    qrepl:=arg arg qreplace
    srchname:="REoff"


 30. Problems Viewing README.DOC Inside PWB Online Help and QH

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER  |
 Last Modified: 15-AUG-1990    ArticleIdent: Q63661

 Problems can occur when attempting to access the README.DOC from
 within the DOS versions of Programmer's WorkBench (PWB) or QH via the
 online help.

 When attempting to view the README.DOC file using the online help
 inside the DOS version of PWB, the messages "Error displaying help"
 and then "Cannot process cross reference" may be displayed in
 successive dialog boxes.

 When attempting to view the README.DOC file from within QH, the
 message "The database README.DOC is not open, or the topic is not
 found" may be displayed.

 Again, these problems are found only in the DOS version of PWB and QH.
 Access of the README.DOC in this manner does not produce errors under
 the OS/2 versions of PWB or QH.

 The following are two possible workarounds for the problem in PWB:

 1. The README.DOC can be loaded into the help system by typing the
    following

       arg "$PATH:readme.doc!" arg pwbhelp

    with default keys:

       Alt+A $PATH:readme.doc! F1

    Note that this method may fail if there is another file named
    README.DOC in the path before the C 6.00 README.DOC. If this is the
    case, the other README.DOC will be loaded instead of the C 6.00
    README.DOC. This method can also fail if there is not enough memory
    to load the file into the help system.

 2. If the previous method fails, the C 6.00 README.DOC can be loaded
    into PWB as a normal text file via the File.Open menu option. The
    README.DOC can be found in the C 6.00 bound executable directory
    (for example, C:\C600\BINB).

 The following are three possible workarounds for the problem in QH:

 1. Inside QH, select View.Search, type "$PATH:readme.doc!" and press
    ENTER. Again, this will bring up the first README.DOC on the path.

 2. You can also select File.Open and load the the file by giving the
    full path and filename of the C 6.00 README.DOC. QH allows you to
    open any text file under 64K in size.

 3. To enable direct access of the README.DOC from within QH via the
    README.DOC button, it is necessary to point the QH environment
    variable to the directory where the README.DOC is located. For
    example:

       set qh=c:\c600\binb\readme.doc

    The QH environment variable is not documented in the C 6.00 printed
    or online documentation.

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


 31. CTRL+NUM/ May be Read as CTRL+/ in DOS with NUM LOCK On

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.10
 Last Modified: 15-NOV-1990    ArticleIdent: Q66740

 In versions 1.00 and 1.10 of Programmer's WorkBench (PWB), the
 CTRL+NUM/ (CTRL+/ on the numeric keypad) and ALT+NUM/ (ALT+/ on the
 numeric keypad) combinations may be interpreted as CTRL+/ and ALT+/
 (on the main keyboard). This problem happens only in DOS or the OS/2
 DOS 3.x box, and only on certain computers. This behavior will cause
 any macro or function assigned to CTRL+NUM/ or ALT+NUM/ to not execute
 when NUM LOCK is on.

 To reproduce this problem, assign a function or macro to CTRL+NUM/.
 Then execute the TELL function (CTRL+T by default) and press CTRL+NUM/.
 The TELL function prompts for a keystroke, then displays the name of
 the keystroke and the function assigned to it. With NUM LOCK on, TELL
 will return the following:

    unassigned:Ctrl+/.

 With NUM LOCK off, TELL will return the following:

    <function name>:Ctrl+num/.

 This behavior is identical for the ALT+NUM/ key name, but works
 properly for all other key names on the numeric keypad.

 If NUM LOCK is off, or if the protected-mode version of PWB is run,
 this behavior does not occur.

 This behavior has been observed on the following machines:

    Northgate 386-33
    PS/2 Model 70
    PS/2 Model 80-311

 Microsoft has confirmed this to be a problem in PWB version 1.00 and
 1.10. We are researching this problem and will post new information
 here as it becomes available.


 32. PWB Command-Line Option /DP Is Documented But Not Implemented

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 27-JUL-1990    ArticleIdent: Q63951

 The /DP switch for the Programmer's WorkBench (PWB), documented on
 Page 49 of the version 6.00 "Microsoft C Reference," is not
 implemented in version 1.00 of the PWB. This switch is designed to
 ignore the most recent program list upon starting the PWB.

 The /DP switch is mentioned only in the "Microsoft C Reference" and
 not in the online help.

 Upon invocation, the Programmer's WorkBench version 1.00 does not
 automatically set the program list to the last program list used.
 Therefore, the /DP command-line switch was not implemented because it
 would have no purpose.

 With the PWB version 1.00, there is no way to have the last program
 list set automatically at startup.


 33. With the "deflang" Switch PWB Prompts for Setting Program List

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  3-AUG-1990    ArticleIdent: Q64353

 As documented on Page 79 of the "Microsoft C Reference" shipped with C
 version 6.00 and in the online help, the "deflang" switch in the
 Programmer's WorkBench (PWB) sets the default filename extension for
 list boxes in PWB dialog boxes. Another (undocumented) feature of this
 switch is to enable you to be prompted to "Set Program List?" when
 loading a source file with a .MAK file associated with it in the
 current directory.

 By default, "deflang" is not set. You can set the deflang switch in
 the [PWB] tagged section of the TOOLS.INI file, for example:

    deflang:C

 This changes the default filename extension in the PWB's dialog boxes
 (such as Open in the File menu) from "*.*" to "*.c", so that only
 files with the .c extension show up by default. Other languages can be
 specified as well, as shown below:

    Switch Setting     Extension
    --------------     ---------

    no value            .*
    C                   .c
    Asm                 .asm
    BASIC               .bas
    FORTRAN             .for
    Pascal              .pas
    COBOL               .cbl
    LISP                .lsp

 Note that the online documentation specifies "Assembler" as the switch
 to use for .ASM files, but this is incorrect. "Asm" is the correct
 switch to use to make Assembler the default language.

 The deflang switch also enables you to be prompted as to whether or
 not the program list should be set automatically. If you load a file
 that has the extension specified by the "deflang" switch and you also
 have a .MAK file with the same base filename in the same directory,
 the PWB will prompt you about loading the program list.

 For example, assume that deflang is set to C and FOO.MAK and FOO.C are
 in the same directory. If you type PWB FOO.C at the command-prompt,
 the PWB will pause when loading and prompt with "Set Program List?
 FOO.MAK". At this point you can specify <yes> or <no>.

 When already in the PWB, if you select Open from the File menu, and
 select FOO.C as the file to open, the PWB will also prompt you at this
 point regarding whether or not you want FOO.MAK loaded as the program
 list, but only if NO program list is currently set.


 34. Can't Resize a Window with a Macro in PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1990    ArticleIdent: Q64433

 A window cannot be resized using the "resize" function in a macro.
 After Programmer's WorkBench (PWB) performs the resize function, it
 waits for the you to respond with the UP ARROW or DOWN ARROW key.
 Functions that are placed in the macro after the resize function are
 ignored. If "record on" is selected and you try to record the resizing
 of a window, the macro will stop recording until the ENTER key on the
 numeric keypad is pressed.

 The following is an example:

    resizeit:= cancel arg arg nextmsg window resize up up up NumEnter

 The above example stops at the resize function and waits for you to
 resize the window. The remaining functions are ignored.

 To make a window a specified size, move the cursor to a location on
 the screen and then open the window with the "window" function.

 The following is an example of a macro that opens the "<compile>"
 window with a specified size:

 compile_size:= up up up up up up up up up up
 resize_it:=cancel meta down compile_size arg window window arg \
            "<compile>" setfile window
 resize_it:ALT+U

 Note: The size of the compile window can be adjusted by changing the
 number of ups on the compile_size line.


 35. PWB Hangs When Run with Some Communication Programs Under OS/2

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1990    ArticleIdent: Q64435

 When running Programmer's WorkBench (PWB) under OS/2 while
 simultaneously running communication programs, PWB will appear to
 hang. To correct the problem, terminate any communication programs and
 PWB will resume as normal.


 36. "Cannot Open File current.$" May Mean Incorrect INIT Variable

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q64566

 When using the Programmer's Workbench (PWB), the following message may
 appear as a pop-up dialog box when selecting Compile or DOS Shell (or
 OS/2 Shell for OS/2):

    +----- Cannot open file! -----+
    |   D:\TEST\SRC\X\current.$   |
    |  No such file or directory  |
    |-----------------------------|
    |      < OK >   < Help >      |
    +-----------------------------+

 One cause for this error is an incorrect setting of the INIT
 environment variable. To remedy the situation, exit PWB and make sure
 that the INIT environment variable is set to a valid directory name
 (for example, a directory that exists).

 To reproduce this message, set your INIT environment variable to an
 invalid directory, for instance (if a directory named X does not exist
 on your drive):

    SET INIT=X

 Then start PWB and try to compile a program. The message will appear
 in the middle of the screen.

 One possible reason why your INIT environment variable may be set
 incorrectly, even if your AUTOEXEC.BAT sets it correctly, is that you
 might have run out of environment space in the setting of the
 variable. You can refer to the "MS-DOS Encyclopedia," Article 2, for
 more information about increasing your environment space.


 37. How to Use the PWB with the Windows 3.00 SDK

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-AUG-1990    ArticleIdent: Q64788

 Detailed step-by-step instructions on how to set up the Programmer's
 WorkBench (PWB) for use with the Windows version 3.00 Software
 Development Kit (SDK) can be found in a file provided with the SDK
 called PWBINFO.WRI.

 The file explains how to set PWB switches so that Windows applications
 can be built from within PWB. The file also explains how to access the
 SDK's online help.

 This file can be viewed and printed with the WRITE program, which is
 packaged with the Windows 3.00 package.


 38. Tips for Using the Microsoft Advisor Online Help

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc s_c s_qh
 Last Modified: 23-JAN-1991    ArticleIdent: Q64829

 The following are some tips for more effectively using the online
 documentation included with the Microsoft C Compiler version 6.00
 Programmer's Workbench (PWB) as well as the Microsoft Advisor
 command-line help system:

 1. Finding help on a topic for which the exact name is not known.

    If the exact spelling of a topic is not known, the help for that
    topic can't be accessed directly (for instance, by using the F1 key
    in PWB), but it can usually be found indirectly.

    By using the table of contents and selecting links that pertain to
    the subject in question, the topic can usually be found. To get to
    the table of contents from within QuickHelp, select the Categories
    menu, then "C 6.00".  From within PWB, choose the Help menu, then
    select Contents.

    If you know the general spelling of the topic, an alphabetical
    index is available by choosing Index from the main contents screen.

 2. "Paging" through the online documentation.

    The online documentation can be "paged through" like you would page
    through a manual.

    In PWB, CTRL+F1 takes you from one topic to the next sequential
    topic in the help file. In QuickHelp, Choose Next or Back from the
    View menu to move in either direction.

 3. Scanning a list of available topics (as in a printed index).

    There are alphabetical indices for every major component of the
    product. Just choose Index from the main contents screen and select
    the appropriate topic.

 4. Techniques for using the online help.

    For more information on how to use the help system, as well as on
    the general organization and structure of the help system, choose
    Using Help from the main contents screen.

    For additional help, see Chapter 4, "Using the On-Line Reference,"
    of the "Microsoft C Installing and Using the Professional
    Development System" manual that comes with C version 6.00.

 5. Printing out the online help files.

    By using the HELPMAKE utility, the help files can be decoded to
    readable text files, which can then be printed. For more
    information about the HELPMAKE utility, see Chapter 7 of the
    "Microsoft C Advanced Programming Techniques" manual that comes
    with C version 6.00.


 39. Predefined Identifiers in Microsoft C 6.00

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickhelp s_c s_utils
 Last Modified: 24-OCT-1990    ArticleIdent: Q65472

 The following information is contained in the online help for the
 Microsoft C Compiler version 6.00.

 This information below can be accessed by using the following steps:

 1. Obtain help on the text "cl" using either the F1 key from the
    Programmer's WorkBench, or by using "qh cl" from the DOS or OS/2
    command lines.

 2. Select Preprocessor Options, then Predefined Identifiers.
 The compiler automatically defines identifiers useful in writing
 portable programs. You can use these identifiers to compile code
 sections conditionally. These identifiers are always defined unless
 otherwise stated.

    Identifier       Target Identified
    ----------       -----------------

    MSDOS            MS-DOS operating system
    M_I86            Member of the I86 processor family
    M_I86mM          Memory model type
                     <m> = T    Tiny
                           S    Small (default)
                           C    Compact model
                           M    Medium model
                           L    Large model
                           H    Huge model
    M_I8086          8088 or 8086 processor; default or with /G0
                        option
    M_I286           80286 processor; defined with /G1 or /G2 option
    _MSC_VER         Identifies the version of Microsoft C
    NO_EXT_KEYS      Disables Microsoft-specific language extensions
                        and extended keywords; defined only with /Za
                        option
    _CHAR_UNSIGNED   Changes default char type to unsigned; defined
                        only with /J option

 The _MSC_VER identifier has a value of 600 for the Microsoft C Compiler
 version 6.00. This identifier is not defined in Microsoft C versions
 5.10 and earlier.


 40. How to Add Other Language Compilers to PWB's Build Options

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_pascal b_basiccom s_c h_masm h_fortran b_cobol
 Last Modified: 24-OCT-1990    ArticleIdent: Q65568

 The Programmer's WorkBench (PWB) is an environment capable of
 utilizing different compilers for mixed-language programming. When
 installed during BASIC version 7.10 setup, PWB version 1.10 shows
 build options for the BASIC language only. However, it is possible to
 include other language compilers to utilize the full features of the
 PWB utility.

 The following information applies to the Programmer's WorkBench
 version 1.10 utility supplied with Microsoft BASIC Professional
 Development System (PDS) version 7.10 for MS-DOS and MS OS/2.

 Note that the 1.00 version of PWB is shipped with Microsoft C
 Professional Development System (PDS) version 6.00. The steps below
 should also apply to PWB version 1.00.

 The Programmer's WorkBench (PWB.EXE) is an advanced development
 environment capable of integrating several language compilers,
 NMAKE.EXE, LINK.EXE, and the CodeView debugger. It offers the ability
 to accomplish tasks, such as program development under protected mode
 and mixed-language programming. This ability is not available in the
 QuickBASIC extended development environment (QBX.EXE).

 Two special files, PWBC.PX$ (for protected mode OS/2) and PWBC.MX$
 (for DOS mode), reside on the BASIC PDS 7.10 disks and support the
 option of using the C compiler in PWB. Since SETUP.EXE (in BASIC PDS
 7.10) does not copy PWBC.PX$ and PWBC.MX$ during installation, these
 files must be unpacked and transferred to your machine, for example to
 the \BINP subdirectory located in the \BC7 directory. (Note: The
 UNPACK.EXE utility is found on disk 1 of the BASIC PDS package.) After
 unpacking, the files will have the names PWBC.PXT and PWBC.MXT.

 Next, the following command lines must be added to the TOOLS.INI file
 to make the C compiler available to PWB:

    [pwb - .BAS .BI]
       LOAD: LogicalDrive:\[Path]\PWBC.PXT

 For further information about installing PWBC.PXT and PWBC.MXT, see
 Page 54 of the "Microsoft BASIC 7.1: Getting Started" manual.

 If you want to program in languages other than BASIC or C [such as
 Microsoft Macro Assembler (MASM), Microsoft Pascal, Microsoft FORTRAN,
 or Microsoft COBOL 3.00/3.00a], the following steps will insert the
 initial build options to include other languages to PWB's build
 options menu. In the example below, options to include the MASM.EXE
 assembler are specified. If some other language's compiler is desired,
 substitute appropriate changes for that compiler, where noted in the
 specified areas:

  1. In PWB, go to the Options menu and select Build Options.

  2. Choose Save Current Build Options.

  3. Enter a meaningful message, such as "Options to Include MASM" in
     the window's edit field (if some other language is desired, change
     MASM to the appropriate name). Select the OK button from the "Save
     Current Build Options" and "Build Options" windows.

  4. Open the "TOOLS.INI" file in the PWB utility and go down to the
     bottom of the file. Somewhere near the bottom should be the tag
     "[PWB-Build Options: Options to Include MASM]" (or the language
     that was specified).

  5. In this section, add the following NMAKE instructions:

        build: inference .asm.obj masm_asm_obj
        build: command masm_asm_obj "masm $<;"

     Note: For languages other than MASM, distinguish a variable name
     in the inference rule to be used in the commands line (such as
     masm_asm_obj has been used above) and then specify the appropriate
     compiler in the commands line within the quotation marks. The
     special filename macro specified in the quotation marks, "$<",
     applies the command to any object that has an out-of-date
     executable file.

  6. Press SHIFT+F8 to reinitialize the file and then close it.

  7. Go to the File menu and select New (it is a good idea to close any
     files that are currently open before this step).

  8. Go to the Options menu and select Build Options.

  9. Choose Initial Build Options.

 10. Select the "Options to Include MASM" option (it should be near the
     bottom of the list).

 After completing these instructions, the PWB utility will now be ready
 to compile assembler along with BASIC source code, provided that paths
 to the necessary compilers are furnished.


 41. PWB Err Msg: Out of Local Memory. Unable to Recover.

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-OCT-1990    ArticleIdent: Q65913

 When setting a program list inside of the Programmer's WorkBench
 (PWB), the following message may occur:

    Out of Local Memory.  Unable to Recover.

 The error is printed on the screen and the PWB exits to DOS. This
 error may occur when the program list contains too many names. To
 resolve the problem, combine object modules into libraries whenever
 possible. Remove the .OBJ files from the program list and replace them
 with the new libraries. This will reduce the number of object modules
 that need to be defined in the program list.

 Another method that sometimes helps to alleviate the error is to open
 the File menu and close as many unneeded files as possible. This
 should be done before setting the program list.


 42. Situation Where PWB Online Help Text Disappears

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | SR# S901010-118 B_BasicCom S_C B_cobol
 Last Modified: 24-OCT-1990    ArticleIdent: Q66229

 When requesting help in Microsoft Programmer's WorkBench (PWB)
 versions 1.00 and 1.10, the following sequence of events will cause
 the Help screen text to disappear, leaving only the hyperlinks.

 This information applies to Programmer's WorkBench version 1.00 (which
 comes with Microsoft C Professional Development System version 6.00
 for MS-DOS and MS OS/2), and to Programmer's WorkBench version 1.10
 (which comes with Microsoft COBOL Professional Development System
 version 4.00 and with Microsoft BASIC Professional Development System
 (PDS) version 7.10 for MS-DOS and MS OS/2).

 Microsoft has confirmed this to be a problem in PWB. We are
 researching this problem and will post new information here as it
 becomes available.
 Follow these steps to reproduce the problem:

 1. From the DOS or OS/2 prompt, enter PWB. From the File menu, select
    New. Type PLINES and request help by pressing F1 or single-clicking
    the right mouse button.

 2. In the Help dialog, double-click the left mouse button with the
    cursor on the hyperlink "Using PWB Functions."

 3. Double-click the left mouse button with the cursor on the hyperlink
    "PWB Functions by Category."

 4. Double-click the left mouse button with the cursor on the hyperlink
    "Moving Through Files."

 5. The vertical scroll bar will show that you are at the bottom of the
    dialog. Press PGUP and you will notice that the hyperlinks to Up,
    Index, Contents, and Back have disappeared. Double-click the left
    mouse button with the cursor on any of these empty hyperlinks; the
    text on the screen will disappear, with empty hyperlinks appearing
    on the screen.


 43. How to Insert Spaces Before a Block of Text in PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_EDITOR
 Last Modified: 24-OCT-1990    ArticleIdent: Q66231

 It is sometimes desirable to indent or move over a block of text in
 the Programmer's WorkBench (PWB) or the M Editor. The following steps
 can be used to insert spaces before a block of text to indent it:

 1. Get into boxarg mode. You can select this mode from the Edit menu
    under the Programmer's Workbench, or select the boxstream function
    under the Microsoft Editor.

 2. Highlight the area you want to contain the spaces. This may be
    anywhere in the file.

 3. Select the linsert function. By default, this is CTRL+N.

 The highlighted area should now be moved over and replaced by spaces.

 You don't have to be in boxarg mode for this to work; linsert always
 treats its argument as a boxarg regardless of the current mode.
 However, the highlight on the screen won't match the area that is
 going to be inserted unless you use boxarg mode.

 Also, ldelete can be used to unindent a block of text. However, you
 must be in boxarg or streamarg mode for it to work correctly. In
 linearg mode, it will delete entire lines.


 44. PWB's Use of Expanded Memory

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-OCT-1990    ArticleIdent: Q66308

 The DOS version of the Programmer's WorkBench (PWB) will utilize
 expanded memory to swap its own segment overlays if it detects that
 expanded memory is available in the system. When PWB needs a new
 overlay, the existing overlay in memory is first copied into expanded
 memory. If there is not enough room in expanded memory to copy the
 overlay, the least recently used overlay is discarded to make room for
 it. This scheme allows most overlays to be read from expanded memory
 instead of from disk.

 Note that this is the only method by which PWB will take advantage of
 available expanded memory, and that PWB versions 1.00 and 1.10 have no
 internal provisions to make use of extended memory in any way.


 45. PWB May Exit to DOS If TMP Not Set Correctly

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.10
 Last Modified: 24-OCT-1990    ArticleIdent: Q66309

 If the tmp environment variable is set only to a drive (with no path
 specified), the PWB may "crash" out to DOS when a compile is
 attempted. The screen will still show the PWB, but there will be a
 prompt displayed.

 This problem may be reproduced using the following procedure:

 1. Set up the environment to run the PWB.

 2. Set the tmp environment variable to the current drive, without
    specifying a path. For example:

       SET TMP=C:

 3. Execute the PWB and create or load a simple source file.

 4. Attempt to compile the source file. (Note: If the COMPILE option is
    not available on the make menu, make sure the file has a name with a
    .c extension.)

 Microsoft has confirmed this to be a problem with the Programmer's
 WorkBench versions 1.00 and 1.10. We are researching this problem and
 will post new information here as it becomes available.


 46. MASM Build Switches for PWB 1.10

 Product Version(s): 1.10    | 1.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified:  5-DEC-1990    ArticleIdent: Q66339

 When setting a program list containing .ASM files in Programmer's
 WorkBench (PWB) version 1.10, the following error message occurs:

    Program List: file 'filename' will be ignored
    File type unused by current build options

 The .ASM files are not recognized because PWB 1.10 does not contain
 build switches specific to any language. Build switches are now loaded
 from language extension files (.MXT for DOS and .PXT for OS/2). If you
 have an assembly language extension file, you will not see this error
 message. Language extensions are not necessary and are only a
 convenience for controlling the build process; only the build switches
 are really needed.

 The following build switches can be added to a tagged section in your
 TOOLS.INI file. To use these build options, first choose your language
 options from the Options Build Options menu, then initialize this
 section by typing {arg} tag_name {reinitialize} (type the following to
 invoke the sample build switch below:

    ALT+A asm_rules SHIFT+F8

 These switches can also be added to a custom set of build options
 saved by Save Current Build Options. They may then be initialized by
 choosing Build Options from the Options menu, and then selecting Set
 Initial Build Options to choose the new custom language options.

 Sample Build Switches
 ---------------------

 [pwb-asm_rules]
 ;
 ;   MASM build rules
 ;
 build:macro ASM "MASM"
 build:macro AFLAGS_G "/Mx /T"
 build:macro AFLAGS_D "/Zi"
 build:macro AFLAGS_R ""
 build:inference .asm.obj as_asm_obj
 build:release command as_asm_obj  \
             "$(ASM) $(AFLAGS_G) $(AFLAGS_R) $<, $@;"
 build:debug command as_asm_obj  \
             "$(ASM) $(AFLAGS_G) $(AFLAGS_D) $<, $@;"
 build:include .asm "^[ \t]*include[ \t]+\\([^ \t]+\\)"
 build:include .inc "^[ \t]*include[ \t]+\\([^ \t]+\\)"

 These assembly flags can then be modified from PWB by using the
 following macros. The macros must be assigned to keystrokes to be
 activated. This can be done using the <ASSIGN> pseudo file. They can
 then be used to redefine the flags to pass to MASM.

 ;
 ;   MASM option-setting macros
 ;
 setAFG:= arg "Global MASM Options?"  prompt -> cancel lasttext home \
         "build:macro AFLAGS_G \"" endline "\"" assign

 setAFD:= arg "Debug MASM Options?"   prompt -> cancel lasttext home \
         "build:macro AFLAGS_D \"" endline "\"" assign

 setAFR:= arg "Release MASM Options?" prompt -> cancel lasttext home \
         "build:macro AFLAGS_R \"" endline "\"" assign


 47. Unexpected Behavior with the /Gt Switch and the PWB

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C
 Last Modified: 15-JAN-1991    ArticleIdent: Q66828

 Adding the /Gt compiler switch with an argument to the Additional
 Options section of the C Compiler Options on the Programmer's
 WorkBench (PWB) Options menu can cause the value of the argument to be
 changed or dropped.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench version 1.00. We are researching this problem and will post
 new information here as it becomes available.

 When you add the /Gt switch with an argument (for example, /Gt30) and
 click OK, then immediately go back into the Compiler Options dialog
 box; you will see that the /Gt30 switch you just set is now /Gt3.

 If you set a /Gt switch and specify a value, it will compile with that
 correct value because it was written to the file on disk that is used
 to build the program.

 If you go back in and look at the compiler options and see that the
 value is incorrect and Cancel the options dialog, you will still
 compile with your initial correct /Gt value.

 You will compile with the incorrect /Gt value only if you make another
 change in that dialog and select OK. This is because you changed the
 options, so PWB rewrites the options to the file on disk. In the case
 of /Gt, that option is written incorrectly and from that point on, you
 will compile with the incorrect /Gt value.

 Not all values of /Gt are incorrect. The most common incorrect values
 end in zero. The following are examples where the problem occurs:

    /Gt40 will turn into /Gt4
    /Gt0  will turn into /Gt
    /Gt20 will turn into /Gt

 Some other values that get changed are the following:

    /Gt113 will turn into /Gt3
    /Gt305 will turn into /Gt35
    /Gt14  will turn into /Gt4
    /Gt22  will turn into /Gt

 As a possible work around, do not set /Gt in the PWB, and set the
 environment variable CL to the desired threshold, as in the following
 example:

    set cl=/Gt40

 This value will be read by the compiler when it is called from the
 PWB.

 Also, you can set the /Gt switch on the Additional Options line in
 either Set Debug Options or Set Release Options, rather than the
 global Additional Options.


 48. REsearch() Function Prototype Not Found in EXT.H Header File

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.00 buglist1.10
 Last Modified:  4-DEC-1990    ArticleIdent: Q67274

 The Programmer's WorkBench (PWB) function REsearch(), although
 included in EXTSUP.LIB, is not prototyped in the EXT.H header file. To
 call REsearch(), use the following prototype:

 int REsearch( PFILE pFile, flagType fForward, flagType fAll,
               flagType fCase, flagType fWrap, char _far *pattern,
               fl *pflStart );

 For more information, see online help.

 Microsoft has confirmed this to be a problem in PWB versions 1.00 and
 1.10. We are researching this problem and will post new information
 here as it becomes available.


 49. PWB Help Crashes When Using "Moving Through a File"

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.10
 Last Modified: 14-DEC-1990    ArticleIdent: Q67361

 When using the online help through the Programmer's WorkBench (PWB),
 the help system will crash if you do the following:

 1. After entering help, choose Contents.

 2. Select the Microsoft Advisor from the list of contents.

 3. Select the Programmer's WorkBench button followed by the "Moving
    Through a File" selection.

 At this point a header will appear on the screen and the elevator for
 the window will appear as though it is at the bottom of a page.

 The page can be scrolled up and the contents viewed, especially if
 highlighted, but the menu items at the top will be blacked out
 (although they are present). From this point, no further help can be
 accessed.

 If you exit help and then reenter, nothing will come up.
 Re-initializing does not reinstate the help system. Only shelling out,
 exiting, and reentering will allow you to access the help system.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench version 1.10. We are researching this problem and will post
 new information here as it becomes available.


 50. PWB Hangs with Novell NetWare

 Product Version(s): 1.00 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_codeview s_c
 Last Modified: 14-DEC-1990    ArticleIdent: Q67483

 On certain installations of a Novell network, the network will cause
 the Programmer's WorkBench (PWB) to hang. This problem may also occur
 in CodeView or QuickC. The hang usually occurs when an attempt is made
 to use the mouse.

 If you have a peripheral (such as a mouse) that uses Interrupt Request
 Level (IRQ) 3, and your system is part of a network using Novell
 NetWare version 2.15 or earlier, your system may hang when you load
 QuickC, PWB, or CodeView. As a temporary solution, set your peripheral
 to use another interrupt. For more information, contact your Novell
 NetWare dealer.

 If taking these steps does not solve the problem, please contact
 Microsoft Product Support Services.


 51. PWB Menu Hyperlink in PWB.HLP is Inconsistent in Version 1.10

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 23-JAN-1991    ArticleIdent: Q67614

 When selecting help on the Programmer's WorkBench (PWB) version 1.10
 from the Categories menu in QuickHelp version 1.70, the help screen
 for Microsoft Advisor Help System is presented instead. This behavior
 may be duplicated by following the procedure outlined below:

 1. Start QuickHelp without an argument to get help on any topic. This
    will bring up the main help screen.

 2. Select the Programmer's WorkBench choice under the Categories menu.

 Instead of bringing up the help screen for Programmer's WorkBench, you
 will see the screen for the Microsoft Advisor Help System.

 If the PWB.HLP help file is decoded using helpmake as follows

    helpmake /D /T /Opwb.doc pwb.hlp

 we can see that the reason for this is that the .context directive for
 Programmer's WorkBench appears in the wrong section in the decoded
 help file. The following line

    .context Programmer's Workbench

 appears above the section for "Microsoft Advisor Contents." To correct
 the problem, move the .context directive for Programmer's WorkBench to
 the proper section, which is the "Programmer's WorkBench Contents."

 The helpfile must then be recompressed, as follows:

    helpmake /E7 /T /Opwb.hlp pwb.doc

 The choice of /E7 is shown here for demonstration purposes only, and
 is strictly arbitrary in this case. If maximum compression is desired,
 the numerical argument to the /E switch may be left off, or /E15 may
 be specified. Maximum compression will restore the database as close
 to its original size and state as possible.


 52. "missing ':' in ->" Caused by Control Character

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-DEC-1990    ArticleIdent: Q67736

 When invoking the Programmer's WorkBench (PWB), if there is a control
 character at the end of the TOOLS.INI file, [usually a CTRL+Z (ASCII
 26) end-of-file marker] and you only have a [pwb] tagged section, an
 error message will appear stating "missing ':' in ->". Note that the
 "->" is the graphic right-arrow symbol.

 This is not a problem in the PWB. A control character is a legal macro
 name. The message indicates that a macro definition or key assignment
 is expected after the character. To keep this message from appearing,
 place the tag

    [end]

 before the control character at the end of your TOOLS.INI file. With
 this tag at the end of the file, you always suppress the message, even
 if you edit TOOLS.INI with an editor that inserts CTRL+Z's at the end
 of the file. This is because the -> symbol must be within the [pwb]
 tagged section for this error message to be displayed, and the [end]
 tag forces the -> into its own tagged section.

 Simply deleting the control character will work until you edit the
 file with an editor that replaces the CTRL+Z, then this message
 reappears. This may also when using the COPY command to concatenate
 files.


 53. Inconsistent Error Attempting to Load Nonexistent Extension

 Product Version(s): 1.00 1.10
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 28-DEC-1990    ArticleIdent: Q67777

 When attempting to load a Programmer's WorkBench extension through a
 macro definition in the TOOLS.INI file, if the extension file does not
 exist, or is not in the current path, the following error message is
 displayed in a dialog box:

    pwbhelp:  SYS0123:  A file name or volume label contains an
                        incorrect character

 This error message should indicate that the extension file could not
 be found; however, the message is generated by the OS/2 operating
 system's DLL loading code, and therefore, cannot be changed by PWB.

 The following error message is generated in the DOS version of PWB,
 which displays this message in a dialog box:

    No such file or directory

 To correct the problem, make sure that the directory in which the
 extension resides is in the current path.


 54. PWB May Record Incorrect Paths for Dependencies in Makefile

 Product Version(s): 1.00 1.10  | 1.00 1.10
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | buglist1.00 buglist1.10
 Last Modified:  6-FEB-1991    ArticleIdent: Q67780

 Creating a program list with dependencies in directories other than
 the project (makefile) directory may result in the Programmer's
 WorkBench (PWB) recording the wrong paths to these dependencies.

 The following steps illustrate the problem:

 1. Create subdirectories named TEST and TESTA under the same
    directory, with sample files FOO.C in TEST and GOO.C in TESTA.

 2. Invoke PWB from the TESTA directory.

 3. Create a program list.

 4. Add FOO.C and GOO.C with full path.

 5. Save the list.

 The resulting makefile will contain the line:

    OBJS = goo.c foo.c

 The correct line should read:

    OBJS = goo.c ..\TEST\foo.c

 Changing the location of the project makefile or changing the names of
 the subdirectories will generate the correct paths for dependencies in
 the makefile.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench versions 1.00 and 1.10. We are researching this problem and
 will post new information here as it becomes available.


 55. PWB Extensions in DOS Cannot Shell to DOS

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q67792

 Extensions written for the Programmer's WorkBench (PWB) that require a
 call to the operating system do not work correctly under DOS. One
 example of this is the FILTER.C sample extension packaged with
 Microsoft C 6.00.

 When PWB.COM is executed under DOS, it spawns the main editor
 (PWBED.EXE). PWBED.EXE is cleared from memory when a DOS shell is
 executed from within the editor. Once the shell has completed,
 PWBED.EXE is reloaded from disk and initialized. The initialization is
 what causes the problem because it also initializes any extensions to
 the editor at the same time. This means that any information that the
 extension was keeping track of is lost.


 56. Not Enough Core Message Caused by Lack of Memory

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68070

 When loading the Programmer's WorkBench (PWB), a message box may
 appear on the screen containing the message "Cannot Autoload
 Extension, not enough core." The extension file that could not be
 loaded will be indicated. You need to free more memory so that the
 extensions can be loaded.


 57. Windows DLL Build Options Ignore .RC Files in PWB 1.10

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.10 S_C P_WINSDK
 Last Modified: 11-JAN-1991    ArticleIdent: Q68155

 In the Programmer's WorkBench version 1.10, the default build options
 for creating a Windows DLL will ignore any .RC files included in the
 Program List, and therefore, will not build them into the project.

 Use the following steps to correct this problem:

  1. If there is a Program List currently set, clear it.

  2. Set the Main Language to C.

  3. Set the Initial Build Options to Windows DLL.

  4. Create a new Program List containing all the files you want in your
     project.

  5. Save the Program List. At this point, PWB will tell you that your
     .RC file will be ignored. Choose OK when that dialog box appears.

  6. Choose Editor Settings from the Options menu.

  7. Find the line that starts:

        build: target $(PROJ).dll

  8. Change the word "res_dll" on that line to "rc_dll".

  9. Move the cursor off that line to highlight the change. Press SHIFT+F2
     to save the new settings.

 10. Press F2 to exit the ASSIGN pseudofile.

 11. Choose Edit Program List from the Make menu.

 12. Choose Save List. The .RC file will now be saved in the Program
     List and used as expected.

 After these steps are taken, the settings will be saved in the .STS
 file for that project, and will remain correct as long as Set Initial
 Build Options is never selected when this Program List is set. In
 order to keep from repeating these steps for future projects, the
 build options should be saved under a descriptive name, such as
 "Corrected Windows DLL Settings." They can then be chosen for any
 future Windows DLLs.

 Microsoft has confirmed this to be a problem in the Programmer's
 WorkBench version 1.10. We are researching this problem and will post
 new information here as it becomes available.


 58. PWB Build Switch Reference Available as an Application Note

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | appnote softlib SW0330
 Last Modified: 29-JAN-1991    ArticleIdent: Q68367

 The "PWB Build Switch Reference" contains detailed descriptions and
 examples for customizing PWB build switches.

 The Programmer's WorkBench (PWB) can build various types of projects
 based on the information contained in "build switches." These build
 switches are interpreted by PWB in order to create a makefile for a
 project. The switches are normally set for you by PWB for common types
 of projects, but you may define your own build switches to handle an
 advanced project where you require more control over the build
 process. For example, customized build switches will allow you to
 utilize different languages, to incorporate other tools into a
 project, or to build new kinds of targets.

 Although build switch customization is documented in the PWB online
 help, the information is somewhat limited. Therefore, an application
 note was created to cover the customization process in detail. The
 title of this application note is "PWB Build Switch Reference" and it
 can be obtained by calling Microsoft Product Support Services at (206)
 637-7096.

 The "PWB Build Switch Reference" can also be found in the Software/
 Data Library (as file SW0330.ARC) by searching on the keyword SW0330,
 the Q number of this article, or S12875. SW0330 was archived using the
 PKware file-compression utility.

 Note that the application note found in the Software/Data Library is
 an ordinary text file, which lacks the typefaces and formatting of the
 printed version that is available by calling Microsoft Product Support
 Services. Because the printed application note is clearer and easier
 to follow, it is highly recommended that you call for the printed
 version, and that you use the downloaded version only as an interim
 copy.

 Also note that you normally DO NOT need to modify build switches just
 to customize the compile and link operations -- this can generally be
 done by selecting commands from the Options menu. By selecting options
 from the Compile or LINK Options dialog boxes, the correct build
 switches are automatically modified to contain the desired
 information.


 59. Brown Screen Color Changes to Yellow After Running PWB

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c buglist1.00 buglist1.10 remapping
 Last Modified:  6-FEB-1991    ArticleIdent: Q69064

 After running PWB, the brown screen color changes to yellow until the
 system is rebooted or the video mode is reset.

 For example, if you run PWB and then run the Microsoft editor, the
 brown characters will appear yellow.

 To work around this problem, you can create a batch file called
 PWB.BAT. In this file, you can start PWB and then reset the video
 mode. For example:

     pwb.bat
             pwb %1 %2 %3 %4
             mode co80,25

 Microsoft has confirmed this to be a problem in PWB versions 1.00 and
 1.10. We are researching this problem and will post new information
 here as it becomes available.


 60. Reinitializing After Changing Editor Settings Is Very Slow

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-FEB-1991    ArticleIdent: Q69142

 The current editor settings in the Programmer's WorkBench (PWB) may be
 changed by choosing Editor Settings from the Options menu, making a
 change to the <assign> pseudofile, and then saving that file. If
 SHIFT+F8 (initialize) is pressed while the <assign> pseudofile is
 still displayed, PWB may appear as though it is hung; it is actually
 reinitializing each statement of the editor settings (<assign>)
 pseudofile.

 The following steps will reproduce this behavior:

 1. Enter PWB and select the Options menu.

 2. Choose the Editor Settings menu.

 3. Make a change in the <assign> pseudofile and then save it.

 4. Press the "initialize" keystroke combination (SHIFT+F8) and a popup
    box will appear stating "reinitializing...". The reinitialization
    is actually taking place but it is very slow because PWB is
    rebuilding the <assign> pseudofile for each entry in your TOOLS.INI
    file.

 This behavior does not occur in PWB version 1.00. Version 1.10
 includes a change to the earlier version; you can see a new assignment
 (made via "arg textarg <assign>") immediately updated if you are
 viewing the <assign> pseudofile.

 This is expected behavior because the <assign> pseudofile is meant to
 show the settings that were in effect at the time the file was
 displayed. It is not recommended that it be dynamically updated except
 via the mechanism of actually editing the file. If you changed a
 setting via "arg textarg assign" (ALT+A textarg ALT+=), a better way
 to view your new setting(s) is by using "refresh" (SHIFT+F7), or by
 switching away and back again via "setfile" (F2).


 61. PWB Ignores Certain Compiler Switches in Additional Options

 Product Version(s): 1.00 1.10 | 1.00 1.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_c
 Last Modified: 25-FEB-1991    ArticleIdent: Q69145

 The compiler switches

    /Fo, /Fe, /F hexnum, /Fm, and /link link-info

 are ineffective when entered in the Additional Options field of the C
 Compiler Options dialog box from the Options menu of the Programmer's
 Workbench (PWB). This is the intended behavior. The functionality of
 all of these switches is provided through the Compiler, Link, and
 Build Options dialog boxes from the Options menu.

 The /Fo switch is overridden by PWB as it creates the .MAK file needed
 to build the project. To perform this function correctly:

 1. Set a program list from the Make menu.
 2. Choose Build Options from the Options menu.
 3. Choose the Build Directory button.
 4. Enter the destination path in that field, such as:

       C:\C600\PROJECT\

 5. Rebuild the project, and both the .EXE and .OBJ files will be placed
    in that directory.

 The other switches are used only to pass information to the linker
 when the CL command is used outside PWB without the /c option. Because
 PWB always compiles and links separately, these switches are lost. To
 utilize these switches from within PWB, select the appropriate options
 in the Link Options dialog box from the Options menu.


 62. How to Increase the Size of the PWB Build Status Box Under DOS

 Product Version(s): 1.00 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | window dialog
 Last Modified: 22-FEB-1991    ArticleIdent: Q69475

 In the DOS version of the Microsoft Programmer's WorkBench (PWB)
 versions 1.00 and 1.10, the status box displayed in the center of the
 screen during a compile can be made larger by increasing the length of
 the command being executed.

 When Build or Rebuild All is selected from the Make menu in PWB, a
 build status box appears on the screen showing the command currently
 being executed. Unfortunately, this box is often too small and the
 current command being displayed gets truncated. One way to increase
 the size of this box is to increase the length of the NMAKE command
 line.

 To increase the length of the NMAKE command line, add the following
 text (without the quotation marks) to the NMAKE Options dialog box,
 which can be selected from the Options menu:

    "                                                /NOLOGO"

 Be sure to include the spaces when you type this line. Then, when you
 select Build or Rebuild All from the Make menu, the build status box
 will be almost as wide as the screen, allowing most of the subsequent
 commands to fit completely into the box.

 If you use the PWB "compile" command, or choose the Compile File
 option from the Make menu, the build status box behaves similarly --
 the longer the command to be executed command, the larger the box will
 be.






 Microsoft CodeView
 =============================================================================


 1. Sequential Mode Not Available in CodeView Version 3.00

 Product Version(s): 3.00 3.01 3.11  | 3.00 3.01 3.11
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q69065

 The CodeView sequential mode (/T option) is not available in CodeView
 version 3.00.

 In CodeView versions 2.30 and earlier, the /T option caused the
 debugger to operate in "sequential mode," which means that only a
 command-line interface was available. You could then type the command
 "=COM1" to redirect the input and output to the COM port, which
 allowed debugging via a remote terminal.

 The /T option and the "=COM1" command are not available in CodeView
 3.00, 3.10, and 3.11 because of the new windowing environment used in
 these versions.

 However, you can still redirect CodeView output to COM1 using the
 Redirected Output command.

 The Redirected Output command causes the CodeView debugger to write
 all subsequent command output to a device, such as another terminal, a
 printer, or a file. The term "output" includes not only the output
 from commands but also the command characters that are echoed as you
 type them.

 The second greater-than symbol (optional) appends the output to an
 existing file. If you redirect output to an existing file without this
 symbol, the existing file will be replaced. For example:

    >>COM1

 In the example above, output is redirected to the device designated as
 COM1 (probably a remote terminal). You might want to enter this
 command, for example, when you are debugging a graphics program and
 want CodeView commands to be displayed on a remote terminal while the
 program display appears on the originating terminal.

    >>OUTFILE.TXT

 In the example above, output is redirected to the file OUTFILE.TXT.
 This command is helpful in keeping a permanent record of a CodeView
 session.


 2. How Interrupts Are Handled in CodeView

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR55548
 Last Modified:  9-AUG-1989    ArticleIdent: Q11817

 Question:

 How does CodeView handle interrupt vectors? Does it mask any
 interrupts when it runs?

 Response:

 CodeView saves and restores about 60 interrupt vectors as a safety
 feature. However, it only redirects the following nine vectors for its
 own use:

    0       Divide By 0
    1       Single Step
    2       NMI
    3       Breakpoint
    9       Keyboard
    21H     DOS functions
    22H     DOS terminate
    23H     ^C
    24H     Critical Error

 The remaining estimated 51 vectors are never altered by CodeView
 unless something else (e.g. the program being debugged) alters them
 after CodeView has started up. In this case, CodeView restores them to
 their original value as it exits.

 When you enter G(o) and let your program run, CodeView relinquishes
 control and lets all interrupts (except the nine listed above) flow
 into your application for processing. However, when you hit a
 breakpoint, the 8259 Programmable Interrupt Controller is masked. This
 prevents interrupts from coming into your application while your
 program is suspended. If you enter G(o) again, CodeView reenables
 interrupts to your application.

 To avoid a bug in the 8086 family, CodeView masks the interrupt
 controller during T(race) commands and some P(rogram step) commands.
 CodeView Versions 2.00 and above solve this restriction by emulating
 the interrupts for your application.

 You normally do not single-step or trace real-time code, so this
 should not be a problem for developers writing interrupt-driven code.
 However, it is something you should be aware of if you are depending
 on interrupts to get to your application. For example, it will not
 work if you enter "T 1000" and expect your program to catch and
 process interrupts during the trace. You will need to set a breakpoint
 at the instruction with which you are concerned, then enter G(o).


 3. Debugging Routines That Are in Libraries

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER | TAR55321
 Last Modified: 21-AUG-1989    ArticleIdent: Q11877

 Question:

 When CodeView attempts to debug a function from a library module, it
 is unable to find the source even when that module was compiled with
 -Zi. It prompts me to "Enter Directory for Program (CR for None)?". I
 enter the directory in which PROGRAM.C resides, but CodeView cannot
 find it. Is there any solution other than not placing modules I wish
 to debug in libraries?

 Response:

 This is a consequence of the way the LIB utility works. When adding an
 object module to a library, LIB records only the source file's base
 name, not its extension. Therefore, "c:\c\source\module1.c" becomes
 "c:\c\source\module1" (no extension). When you are debugging an
 application that calls "module1", CodeView attempts to find
 "c:\c\source\module1". However, it does not accept the filename you
 give because the file is really named "module1.c".

 One way to work around this restriction is to rename your source file
 from "c:\c\source\module1.c" to "c:\c\source\module1" (no extension)
 after you have compiled it and put it into a library. This way, the
 actual name will match the name CodeView is searching for.

 Another solution is to use Library Manager Version 3.07 (which came
 with MASM 5.00) or later; this solves the problem by not stripping the
 file's extension as it is put into a library.


 4. CVP May Generate a Trap B with Large Programs Under OS/2 1.30

 Product Version(s): 2.20 2.30 3.00 3.10 3.11
 Operating System:   OS/2
 Flags: ENDUSER | gp fault protection violation
 Last Modified: 25-FEB-1991    ArticleIdent: Q69348

 Debugging a large application with CodeView under OS/2 version 1.30
 may result in a Trap B system error. Trap B is a "segment not present"
 exception, which results from changes that were made to this version
 of the operating system.

 In version 1.30 of OS/2, the code for DosPTrace() was made swappable,
 while in previous versions it was not. DosPTrace() is part of the OS/2
 API that allows a parent process to control the execution of a child
 process, and to access the child process's memory directly to insert
 breakpoints or change data.

 Because CodeView relies heavily on DosPTrace(), problems arise if this
 code is swapped from memory. The majority of problems occur when
 execution reaches a breakpoint while the DosPTrace() code is not
 present; control should then jump to code that is not currently in
 RAM.

 Because large programs (or heavily loaded systems) tend to result in
 more swapping, this problem appears much more readily when debugging
 large applications.

 The only sure workaround for this problem is to turn off swapping
 while debugging, but it also may help to increase or free up available
 memory. To disable swapping, modify the MEMMAN switch in CONFIG.SYS as
 follows:

    MEMMAN=NOSWAP

 To increase available memory, either install more memory in the
 computer itself or terminate all other unnecessary processes before
 debugging (to remove them from memory).

 This problem is the result of a design change with OS/2 1.30 and is
 not a problem with CodeView. This change is being reconsidered for
 future versions of OS/2. New information will be posted here as it
 becomes available.


 5. Using Two Monitors with CodeView

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER | TAR56465
 Last Modified: 11-SEP-1989    ArticleIdent: Q11966

 Question:

 How do I use CodeView with two monitors? Where is this option
 documented?

 Response:

 Invoke CodeView with the following command:

    CV /2 PROGRAM

 This command tells CodeView to put its display on your secondary
 monitor and lets your program's output go to the default display. This
 option is documented in the "CodeView Options" section of the
 "Microsoft CodeView and Utilities Software Development Tools for the
 MS-DOS Operating System" manual in all products except Microsoft C
 Version 4.00, where it is documented in the README file.

 You must have two monitors and two display adapters to use this
 feature. You must have a monochrome and a non-monochrome monitor;
 because a monochrome monitor's video memory is in a different
 location than a CGA, EGA, or VGA's. This is how CodeView implements
 the /2 option, by writing to both sets of video memory.

 When you use the /2 option, your program's display appears on the
 current default adapter and monitor, while the debugging display
 appears on the secondary adapter and monitor. You can switch which
 monitor is the current default adapter with the MS-DOS MODE command.
 "MODE MONO" causes standard output to go to the MDA, while "MODE CO80"
 causes standard output to go to your CGA, EGA, or VGA.

 For example, if you have both a CGA and an MDA, you might want to set
 the CGA up as the default adapter. You could then debug a graphics
 program with the graphics display appearing on the graphics monitor
 and the debugging display appearing on the monochrome adapter.


 6. /L Must Give Full Pathname to .DLL Unless in Current Directory

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 16-AUG-1989    ArticleIdent: Q47937

 When debugging dynamic link modules with CodeView Protect (CVP), you
 must use the /L switch. Before invoking CVP, make certain that the
 .DLL is in the LIBPATH specified in the CONFIG.SYS file. When invoking
 CVP with the /L switch, if the .DLL is not located in the current
 directory, you must specify the full drive and pathname to the DLL. An
 example is the following:

    CVP /L d:\os2\dll\stdll.dll stmain.exe

 In this example, the full drive and pathname are given for the DLL to
 be debugged. If the full pathname is not given, CodeView will come up.
 However, you will be unable to step into the DLL. CodeView will simply
 step over that call.


 7. CodeView Cannot Trace into Single-Line Functions

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 15-SEP-1989    ArticleIdent: Q47624

 CodeView Versions 2.20 and 2.30 do not trace into a function that is
 contained in a single line of code. For example, if the following
 program is compiled and loaded into CodeView, an attempt to trace into
 the function funct() results in the trace stepping over the function,
 rather than tracing into it.

 Sample Program
 --------------

 /* SIMPLE.C ... a very simplistic sample program                    */

 int funct(void);
 int x;

 void main(void)
 {
   x = funct()
  }

 /* single-line function. It does nothing more than return a value.  */

 int funct(void){return 1;}

 If the above function is modified so that it performs exactly the same
 task but is located on multiple lines, as follows, then CodeView
 handles it correctly:

 int funct(void)
  {
    return 1;
   }



 8. Trace Stops on Line Following a Loop Before Loop Is Done

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_C
 Last Modified: 15-SEP-1989    ArticleIdent: Q47625

 In trace mode, CodeView stops on the line following a loop that does
 not have open and close braces ({}), before the loop is done.

 When tracing through a loop without the braces ({}), the trace stops
 on the statement immediately following the loop each time through the
 loop, giving the impression that the statement is being executed
 inside the loop. Actual program execution is correct.

 The following program was compiled with C Version 5.10 with the
 command line

    cl /Zi /Od program.c

 and run using CodeView 2.20, as follows:

     cv program.exe

 The trace stops at the printf each time through the loop even though
 printf is not part of the loop, but does not print anything until the
 end of the program.

 Sample Program
 --------------

 #include <stdio.h>

 void main(void)
 {
     int i;
     int count;

     count = 0;

     for(i=0;i<3;i++)
         if(i)
             count++;

     printf("Count is %d\n",count);
 }


 9. The 37th Call Added to the Calls Menu Corrupts CodeView Screen

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.20 fixlist2.30
 Last Modified: 10-NOV-1989    ArticleIdent: Q50496

 The CodeView Calls menu shows the current depth of function calls as
 well as the line number the routine was called from and the parameters
 passed. The current routine is always at the top and the routine from
 which the current routine was called is directly below.

 The routines in the Calls menu are first labeled 0-9, and if you are
 nested more than ten levels deep, CodeView labels the next 26 calls
 A-Z, for a display that can accept 36 levels of subroutine calls. If
 you exceed this limit and then select the Calls menu, the CodeView
 display becomes corrupted.

 If the display is corrupted in this manner, the Redraw ("@") dialog
 command can be used to restore the display to it's original state.

 The Stack Trace dialog command (K) has the same function as the Calls
 menu and correctly handles nesting of more than 36 levels deep.

 Microsoft has confirmed this to be a problem with CodeView Version
 2.20. This problem was corrected in Version 2.30.


 10. Quickwatch Seems to Hang When Expanding Very Large Arrays

 Product Version(s): 3.00 3.10 3.11 | 3.00 3.10 3.11
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified:  6-FEB-1991    ArticleIdent: Q68010

 When expanding an element in a large array (usually greater than 1000
 elements, but system dependent), the quickwatch function appears to
 hang. This apparent problem is caused by the time it takes to re-align
 the data in the window, and is actually normal operation. If you place
 the same array element in the Watch Window, it will expand instantly.


 11. Structures Declared with Near, Far, Pascal, and Fortran

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_C S_QuickC buglist2.20 buglist2.30
 Last Modified: 16-AUG-1989    ArticleIdent: Q47694

 CodeView is unable to display elements of structures declared with the
 following keywords:

    near
    far
    pascal
    fortran

 Using ?? to display a structure yields the structure table with only
 one value inside. This value is the first element in the structure.
 Using w? or ? yields the following error message:

    Operand types incorrect for this operation

 Microsoft has confirmed this to be a problem with CodeView Versions
 2.20 and 2.30. We are researching this problem and will post new
 information as it becomes available.

 To work around this problem, recompile without these keywords, or
 obtain the address of the structure element and put a watch on the
 memory location.

 Consider the following large model program:

 struct { int x;
          int y;
          int z;} near a;    /* or far, pascal, fortran */

 void main(void)
 {
   a.x = 1;
 }

 To put a watch on a.x, you could issue the following commands:

 ? &a
 0x0345:0000       <- result is the address of the structure
 ww 0x0345:0x0     <- address of x
 ww 0x0345:0x2     <- address of y (two byte int from x)

 This puts a watch on the first and second elements (x and y) in the
 structure.


 12. Older Vega VGAs Hang CodeView When in VGA Mode

 Product Version(s): 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q27212

 Question:

 Why does my old Vega VGA card cause CodeView to hang when I start it
 in VGA mode? It works properly when I start CodeView when the card is
 in CGA mode.

 Response:

 Some of the older Vega VGAs do not work correctly with CodeView. The
 Vega VGA card uses the same maskable interrupt for detecting graphics
 mode as CodeView.

 We recommend that you contact Vega by calling 1 (800) 248-1850 for
 advice if you experience this problem.


 13. Ambiguous Documentation of Enter ASCII (EA) Command

 Product Version(s): 2.10 2.20 | 2.10 2.20
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 16-AUG-1989    ArticleIdent: Q47764

 In the "Microsoft C 5.1 Optimizing Compiler" manual, the "CodeView and
 Utilities" section does not thoroughly document the EA command for
 CodeView. The following is a more complete explanation:

    EA address [list]

    The Enter ASCII (EA) command modifies array to the value of [list].
    Address refers to what you want to modify. [list] refers to a
    string literal such as "hello". EA will copy [list] to array. Thus,
    if you specify address by giving an array, such as an array of
    characters, the array will have [list] copied into it. However, if
    you were to give a pointer to a character, then the bytes that make
    up the pointer will be directly modified, not the block of memory
    the pointer is pointing at.

 Consider the following examples:

 char array[] = "Hello";
 char *ptr    = "Hello";

 >EA array "Hi"
 >EA ptr   "Hi"

 The result is that the array would contain "Hillo", and ptr will be
 pointing to some unknown memory location.

 The array is considered a constant pointer to a block of memory, and
 as such, any operations on it can only affect the block of memory.
 However, ptr is a variable; therefore, any operations on it affect the
 value of ptr, which happens to be a two- or four-byte number. That
 number happens to refer to a location in memory.

 If you want to changed the block of memory that ptr points to, you
 must do the following:

    >EA &ptr[0] "Hi"

 Essentially, this takes the address of the character that ptr is
 pointing at, gives a constant address, and thus modifies the block of
 memory there. To clarify, imagine you have a character located some
 place in memory. To move a character, you must make a copy of it to
 some other memory location; it is not possible to take its address and
 modify the address directly to change where the character is located.
 Thus, the address of that character is always a constant value. ptr[0]
 happens to be a character located someplace in memory. As such, the
 address of that specific character is a constant value. Since a
 constant cannot be modified, EA changes the block of memory starting
 at where the constant pointer is pointing.


 14. Debugging of DLLs That Do Not Have the .DLL Extension

 Product Version(s): 2.30   | 2.30
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 21-AUG-1989    ArticleIdent: Q47938

 CodeView Protect (CVP) Version 2.30 has the ability to debug DLLs that
 are called with DosLoadModule(). DosLoadModule() can load DLLs that
 do not have the .DLL extension. However, CVP 2.30 cannot debug DLLs
 that do not have the .DLL extension. If you want to debug DLLs that
 are called with DosLoadModule, they must have the .DLL extension.

 Microsoft is aware of this limitation with CodeView Protect 2.30. We
 are researching this problem and will post new information as it
 becomes available.


 15. Resident Software May Cause "Internal Debugger Error 80"

 Product Version(s): 1.x 2.00 2.10 2.10 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-AUG-1989    ArticleIdent: Q47989

 Question:

 Sometimes when I run CodeView, I get an "Internal Debugger Error 80"
 message. What causes this?

 Response:

 Internal Debugger Error messages are usually caused by problems in
 your MS-DOS environment; the most likely cause is the presence of
 memory-resident software, commonly referred to as TSRs (terminate-
 and-stay-resident software).

 For example, running CodeView with Borland's Sidekick loaded has been
 known to cause "Internal Debugger Error 80" and "R6002: Floating Point
 not loaded" error messages. "Internal Debugger Error 80" has also been
 reported when CodeView was run with Software Solutions' "Software
 Carousel" loaded into memory.

 CodeView Versions 2.00 and later have become increasingly more
 sensitive to TSRs. If you receive an Internal Debugger Error message,
 or you are experiencing strange problems within CodeView, make sure
 you are running CodeView with no memory-resident software loaded
 (including, but not limited to, device drivers, screen savers,
 keyboard enhancers, command-line editors, etc.). Disabling your
 resident software, but not rebooting, may not completely remove its
 interference, so be sure to "boot clean" when trying to resolve a
 problem of this type.

 If you continue to receive the error message without memory-resident
 programs, try running CodeView on some other program to see if the
 error is related to particular code. If the error is related to the
 specific code, and you are unable to determine the cause, you may want
 to call Microsoft Product Support for assistance at (206) 454-2030.

 If the error is not dependent on your code, the problem might be the
 particular sequence of CodeView commands you execute. Make a note of
 what operations you performed, i.e., the sequence of Trace, Go, Watch,
 Tracepoint, etc., commands that were issued, and contact Microsoft
 Product Support via phone, letter, or Microsoft OnLine.


 16. CVP Restart Command (Dialog Version) Doesn't Properly Set argc

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified: 28-AUG-1989    ArticleIdent: Q48000

 When using the dialog version of the Restart command, you can restart
 your program with command-line arguments; however, under CodeView
 Protect (CVP) Versions 2.20 and 2.30, argc does not get properly set.

 The Dialog Restart command is often used to restart a program with
 command line arguments. For example, you could use the following:

    L arg1 arg2 arg3

 This example restarts the current executable file, retaining any
 breakpoints, watchpoints, and tracepoints, with arg1, arg2, and arg3
 loaded into argv[1], argv[2], and argv[3], respectively. Argv[0] is
 always set to the name of the current executable file. Argc, at this
 point, should be set to four. The problem presents itself here; argc
 either remains unchanged from the value it was initially set to when
 CodeView was started, or is decremented by one. If, for example,
 CodeView is started with two command-line arguments (argc would then
 be set to three) and then executed, the previous example argc (which
 should then set argc to four) would remain unchanged. When using the
 Dialog Restart command and specifying fewer arguments than were
 specified at start up, argc sometimes is decremented by one.

 Microsoft has confirmed this to be a problem with CodeView Versions
 2.20 and 2.30. We are researching this problem and will post new
 information as it becomes available.


 17. Cannot Load CTRL+Z-Terminated Files with Less than 129 Bytes

 Product Version(s): 1.00 1.10 2.00 2.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.10 buglist2.00 buglist2.10 qfbv
 Last Modified:  4-NOV-1988    ArticleIdent: Q26548

 Problem:

 When using the F(ile) O(pen) command to load a text file which has
 less than 129 bytes and is terminated with a hex 1A (decimal 26,
 CTRL+Z, EOF), CodeView issues the error message "Not a text file." If
 the CTRL+Z character is removed, or if the file size is 129 bytes or
 greater, CodeView has no problem loading it.

 Response:

 Microsoft has confirmed this to be a problem in Version 1.00, 1.10,
 2.00, and 2.10. We are researching this problem and will post new
 information as it becomes available.


 18. Debugging High Resolution EGA or VGA Graphics

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER | TAR61178
 Last Modified: 14-AUG-1989    ArticleIdent: Q23308

 Question:

 I am trying to debug a program that does EGA or VGA graphics. When I
 continue from a breakpoint after the program has painted the screen,
 the screen is not as it was before the breakpoint. I think that all
 colors have been turned to black, but I am not sure.

 I tried this procedure with no switches, with /s, and with /t. The
 program is using the EGA in 640x350 16-color mode. Is this supposed to
 work? If it does not work, why not? What will you do about supporting
 the higher modes for the new machines such as the Personal System 2
 series from IBM?

 Response:

 This behavior is partly related to the size of the buffer that
 CodeView creates for storing screen information. If you are running on
 a CGA, EGA or VGA board, this buffer is by default 16K. If you are running
 on a monochrome board, this buffer is by default 4K. As you are
 finding, 16K is simply not enough memory for a color image using
 640x350 resolution (the maximum resolution supported would be
 640x200).

 One of the reasons why CodeView does not have the ability to handle
 the buffer requirements of an EGA image is that the EGA registers are
 write only. There is no way for CodeView to detect what mode the EGA
 currently is in so it can adjust the size accordingly. Also note that
 with the different resolutions the image is stored in different memory
 locations. The black on black characters may simply be a blank image
 because CodeView cannot tell that the resolution is different and
 therefore the image is located elsewhere.

 With the PS/2 machines this is not an issue because the EGA registers
 have read capability. We are reviewing this with regard to future
 implementations of CodeView.

 The following are some ways to work around this current limitation:

 1. Try writing a routine that will place the display in the desired
    mode before you invoke CodeView. CodeView will be able to judge
    which mode is currently in effect and can locate the image in the
    correct area of memory. Note that the image will not be displayed
    in color. You will only see the higher resolution since the buffer
    is not big enough.

 2. Debug your applications that run in high resolution graphics with a
    second monitor (use the /2 switch). Since the display is going to a
    different screen, CodeView will not have to worry about changing
    the video modes or the buffering.


 19. CodeView Version 2.20 Is Called CVPCK.EXE by DOS Version 2.10

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | CV CVPCK CVPACK 2.x
 Last Modified: 21-SEP-1989    ArticleIdent: Q48689

 Question:

 When trying to invoke CodeView Version 2.20 under DOS Version 2.10 or
 2.11, I get the messages "Cannot Find CVPCK.EXE" and "Please enter new
 program spec:". How can I get CodeView 2.20 to work under DOS Versions
 2.1x?

 Response:

 If you rename CV.EXE to CVPCK.EXE, you can run CodeView Version 2.20
 under DOS Version 2.10 or 2.11. You must also rename CV.HLP to C.HLP
 to make the on-line help accessible.

 CodeView Version 2.20 is included with C Version 5.10, FORTRAN Version
 4.10, Pascal Version 4.00, and Macro Assembler (MASM) Version 5.10.

 Many people mistakenly assume that CodeView is actually looking for
 CVPACK.EXE, which also comes with the software packages listed above.
 If you rename CVPACK.EXE to CVPCK.EXE and then try to run CVPCK.EXE,
 you will receive the error message "overlay not found." If you receive
 this error, delete CVPCK.EXE, copy both CV.EXE and CVPACK.EXE from the
 installation disks, and follow the instructions above.

 Under DOS Versions 3.x, a C program's name is available from argv[0].
 Under DOS Versions 2.x, argv[0] always equals the letter "C", so
 programs that need to find themselves under DOS Versions 2.x also have
 their own names hard coded as the filename to locate. Unfortunately,
 the hard-coded name within CodeView Version 2.20 is "CVPCK.EXE", so
 this is what it looks for under DOS Versions 2.x.


 20. CodeView String Search Length Limited to 19 Characters

 Product Version(s): 2.10 2.20 2.30 | 2.10 2.20 2.30
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | SR# G890810-24574 P_WinSDK
 Last Modified: 19-SEP-1989    ArticleIdent: Q48863

 CodeView Versions 2.20 and 2.30 and CodeView for Windows Version 2.10
 have a 19-character limit in the "Find..." option of the Search menu,
 even though the dialog box is much longer than 19 characters. Entering
 a search string longer than 19 characters results in one of two error
 messages.

 If the search string entered is 20 or 21 characters long, CodeView
 displays the erroneous message "No match of regular expression," even
 if the search string does exist in the file. If the search string is
 22 characters or more in length, CodeView displays the more
 appropriate message "Regular expression too long."

 Although 19 characters sometimes can be limiting, CodeView does
 substring searches so that searching for the following

    AFunctionWithAVeryL

 finds the following string:

    AFunctionWithAVeryLongName

 You will have problems only if you have both of the following and
 you are trying to locate one, but not the other:

    AFunctionWithAVeryLongName()
    AFunctionWithAVeryLongParameterList(a,b,c,d,e,f,g,h,i,j)

 In this case, you won't be able to specify search strings long enough
 to distinguish between the two. However, you can repeatedly use the
 Next command from the Search menu to find the next occurrence of the
 following:

    AFunctionWithAVeryL

 The Next command will find whichever of the above two function names
 that comes next in the source file.


 21. Files, Environment Inaccessible Only While Running under CVP

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q49313

 Due to combined problems in both protected-mode CodeView (CVP) Version
 2.20 and OS/2 Version 1.00 or 1.10, programs that correctly access
 data files and/or system environment information could fail when
 attempting this same access while running under CVP 2.20. This is
 strictly a protected-mode problem and is unrelated to the use of
 CodeView under MS-DOS. The sample program at the end of this article
 can be used to demonstrate this problem.

 The system environment information includes such items as the path and
 other environment variables, as well as the current working directory
 for each disk drive. This information is normally available to an
 executing program, but for a program being debugged with CVP 2.20
 running under OS/2 1.00 or 1.10, most of this environment information
 is inaccessible.

 This inaccessibility is a result of environment handling problems in
 both CVP 2.20 and OS/2 Version 1.00. Since CodeView is run from the
 command prompt, all the current environment information is available
 to CodeView itself, but the program being debugged is given its own
 new screen group in which to run. It is in this new screen group that
 the current environment information is lost because it is not carried
 over by either OS/2 or CodeView.

 Although the OS/2 problem has been corrected in Version 1.10, the
 CodeView problem still prevents access to the environment. Therefore,
 upgrading either CodeView or OS/2 alone does not solve the problem.
 Only with CodeView Version 2.30 running under OS/2 Version 1.10 is the
 problem eliminated.

 There may be some environment information available to the program
 being debugged, but only if it was set in the CONFIG.SYS file at start
 up. Since each new screen group is begun with a copy of the original
 start-up system environment, any SET commands carried out in the
 CONFIG.SYS file will then be duplicated for all subsequent screen
 groups.

 Otherwise, if a program needs access to environment variables that
 were set in the current screen group where CodeView will be invoked,
 then the only way to make the information available while debugging is
 to temporarily hard code the information into the program. After
 debugging, the program can be changed back to using the actual
 environment strings.

 The only other alternative to temporarily hard code the environment
 information into the program is to set the environment variables in the
 CONFIG.SYS file at boot time, rather than setting them in the current
 screen group.

 The only reason a file access will fail only while the program is
 running under CodeView is if the program is assuming the file is in
 the current working directory on the current or another drive.

 If this is the case, then one of the following workarounds may be used
 to gain access to files while debugging:

 1. Use full pathnames for all file accesses, since this alleviates any
    dependency on knowing the current working directory for the drive
    that is being accessed. If it is not feasible to have hard-coded
    pathnames in the completed program, at least adding the full paths
    temporarily will allow debugging.

 2. Put the files to be accessed in the root directory of the boot
    drive. This allows them to be found even under CodeView because
    with no environment information, the current working directory
    defaults to the root of the boot drive.

 3. Use a two-monitor debugging setup and start CodeView with the /2
    option. In this situation, CVP does not need to start a new screen
    group for the program being debugged because it can run it on the
    second monitor. Thus, the current environment information is
    available to both programs because they are both running in the
    current screen group.

    For more information about debugging with a two-monitor setup, query
    on the following:

       CodeView two monitor debugging

 The following C program can be used to demonstrate this environment
 problem:

 Program Example:
 ---------------

     /* TEST.C - shows inaccessible files under CodeView

        Compile with : CL /Zi /Od test.c
        Run with : test <filename>      where <filename> is any file
                        in the current directory.  The file will be
                        opened properly.
        Begin CVP with : CVP test <filename>     where <filename> is
                        the same as before. The file will not be
                        found when the program is run or traced.
     */

     #include <stdio.h>
     void main(int, char *[]);

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

         if ((dfile = fopen(argv[1], "rb")) == NULL) {
             perror ("") ;
             printf ("Cannot open file '%s'.\n\n", argv[1]) ;
         }
         else {
             printf("File %s opened OK.\n\n", argv[1]) ;
             fclose (dfile) ;
         }
     }


 22. COM Port Time-Out Halts Redirection of CVP to Remote Terminal

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 27-OCT-1989    ArticleIdent: Q49376

 When using protected-mode CodeView (CVP) under OS/2, there is a
 problem with the serial communications (COM) ports timing out after 60
 to 90 seconds of inactivity. This time-out makes it essentially
 impossible to do remote terminal debugging with CVP. Once the time-out
 occurs, no further input is accepted from the remote terminal. The
 only workaround is to quit CodeView and begin again, or to do a break
 and then restart the redirection to the COM port.

 The CodeView Debugger allows redirection of input and output to a file
 or device. This procedure is commonly used to set up a remote (dumb)
 terminal for CodeView input and output, while the PC screen is used
 for displaying the program input and output. The terminal is connected
 through a COM port, which eliminates the need for a second video
 adapter as is required when using two monitors with the /2 option.
 Entering "=COM1" at the CodeView command prompt enables input and
 output redirection to the device designated as COM1.

 This debugging arrangement works great with CodeView under MS-DOS, but
 it becomes unworkable with CVP under OS/2 because the internal calls
 that are used to set up the redirection do not account for time-outs
 due to inactivity. Thus, if you are entering commands from the remote
 terminal at a steady pace, everything proceeds smoothly. However, if you
 stop and wait for more than about 60 seconds without doing any input,
 the port will time-out and leave you stranded because the keyboard no
 longer responds.

 In a normal debugging session, it is quite likely that there would be
 many instances greater than 60 seconds where input is not yet needed
 or desired; therefore, this situation quickly becomes intolerable. The
 only way to regain control is to enter CTRL+C at the PC keyboard,
 which ends the redirection. At that point, you could enter "=COM1"
 again on the PC keyboard to restart the redirection if you so desired.


 23. CVP 2.30 Does Not Allow Pathnames for DLLs Specified with /L

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.30
 Last Modified: 10-OCT-1989    ArticleIdent: Q49377

 Protected-mode CodeView (CVP) Version 2.30 allows debugging of dynamic
 link libraries (DLLs) by specifying their names on the command line
 with the /L switch. Because of a problem exclusive to CVP 2.30, this
 particular version of the debugger does not allow a pathname to be
 used with /L to specify the DLL's location in another directory.
 Therefore, all DLLs to be debugged with CVP 2.30 must reside in the
 current working directory.

 Since DLLs are also required to be in a directory that is on the
 LIBPATH, two copies of the DLL may need to be resident on the disk,
 unless the current working directory is also a LIBPATH directory.

 Microsoft has confirmed this to be a problem with CodeView Version
 2.30. We are researching this problem and will post new information as
 it becomes available.

 When tracing a program under CodeView that calls DLLs, the only way to
 trace into the code of a particular DLL is if the DLL was specified
 ahead of time on the command line with /L when CVP was invoked. If a
 program statement is traced that calls a DLL that was not specified by
 /L, then CodeView executes all the code in the DLL and returns control
 back at the line following the call to the DLL. Thus, the call is
 handled as if the step command, rather than the trace command, had
 been used.

 You can indicate only one DLL with the /L switch, so debugging
 multiple DLLs requires multiple /L switches. Normally, the switch is
 followed by a space and the name of the DLL to be debugged, and if the
 DLL is not located in the current directory, a path may precede the
 DLL name. It is only with CVP 2.30 that this becomes a problem because
 a pathname is not recognized with this version, so tracing into the
 DLL is prevented.

 Unfortunately, CodeView does not display error messages for improper
 use of the /L switch, so if the DLL is not found, there is no message
 indicating this. Instead, CodeView does not allow debugging of the
 improperly specified DLL. Use of a pathname with /L with CVP 2.30
 causes this same behavior.

 The only workaround for DLL debugging with CVP 2.30 is to keep a copy
 of the DLL in the current working directory from which CodeView is
 invoked. Thus, if the current directory is not a directory specified
 on the LIBPATH, there must be two copies of the DLL on the disk. It is
 very important that the two copies are exactly the same because
 differing code makes any attempts at debugging very difficult and
 confusing.

 A common practice is to put a period (.) as the first directory on
 the LIBPATH because this makes the current working directory a LIBPATH
 directory, eliminating the need for two copies of the DLL. More
 information on this practice can be found by querying on the
 following words:

    CodeView DLL debugging and libpath


 24. Label Finding Command Does Whole Word Search, Not Text Search

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 27-OCT-1989    ArticleIdent: Q49378

 In CodeView Versions 2.20 and 2.30, under the Search menu is the Label
 option for searching for a label. Unlike the Find option, which
 searches the source code for any regular expression, the Label option
 searches the executable code for an assembly language label.

 This search is not a text search and does not accept regular
 expressions. The only way to find a label is to specify the entire
 label name as the search string. In addition, if the Case Sense option
 is selected on the Options menu, the label is found only if the case
 of each character matches exactly.

 For example, if you want to find the code for the standard C
 stack-checking function "_chkstk", choose Search Label, and type in
 "__chkstk" (without the quotation marks), and press ENTER. This
 switches you into assembly mode, if you weren't there already, and
 puts the line with the __chkstk label at the top of the window. The
 two underscores are required since C appends an underscore to the
 front of all labels and the original function name is "_chkstk".

 You will receive the error message "Unknown Symbol" if the label
 cannot be found or if you mistype or incompletely type the correct
 name. For example, "_chkstk", "chkstk", "__chk", and "__chkstks" all
 fail to find a match in the above example. If Case Sense is on,
 searching for the label "__CHKSTK" also results in failure.


 25. The Assemble Command with ADD Instructions

 Product Version(s): 2.20 2.30  | 2.20 2.30
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified:  9-AUG-1989    ArticleIdent: Q40225

 Problem:

 In CodeView, I'm using the assemble command to change my ADD
 instruction, and it changes all the code from that point on.

 Response:

 If you had the instruction ADD AL,44, for example, and you wanted to
 change the 44 to 45 (or any other number), you could use the Assemble
 command to do it. The Microsoft Macro Assembler generates a 04 44 for
 that instruction; however, when changing the 44 to 45, CodeView
 generates an 80 C0 45, which is still the correct instruction of ADD
 AL,45. However, it's a 3-byte instruction. Inserting one extra byte
 into your code will cause each op code from that point on to be off by
 one.

 Microsoft has confirmed this to be a problem in Versions 2.20
 and 2.30 of CodeView. We are researching this problem and will
 post new information as it becomes available.



 26. CV Prior to 3.00 Needs /S for Mouse to Appear in OS/2 DOS Box

 Product Version(s): 1.00 1.10 1.11 2.00 2.10 2.20 2.30 2.35
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q23646

 With all versions of real-mode CodeView (CV) earlier than version
 3.00, the mouse cursor does not display when running in a DOS session
 under OS/2 in the DOS compatibility box.

 The situation exists because the mouse draws the pointer only in video
 page zero, while CodeView uses video page one. This problem is caused
 by OS/2 itself because the mouse cursor works normally under DOS.

 To work around this limitation with CV 1.x or 2.x, invoke CodeView
 with the /S switch so screen swapping is used as the method of screen
 exchange. This method forces CodeView to swap in and out of page zero.

 Beginning with version 3.00, CodeView detects whether it is running in
 a DOS session under OS/2, and if so, automatically starts up with /S
 as the default in order to make the mouse visible.


 27. CVPACK /p Causes a More Complete Packing

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-MAR-1989    ArticleIdent: Q38020

 When you are unable to load your program into CodeView, try packing
 the program with CVPACK.EXE. If you want a more complete packing of
 your executable, then run CVPACK.EXE with the /p option. This option
 will take longer to run, but it will generate better results.

 The /p option for CVPACK.EXE is documented on Page update-17 in the
 "Microsoft C 5.1 Optimizing Compiler, CodeView and Utilities,
 Microsoft Editor Mixed-Language Programmer's Guide."

 Normally, CVPACK discards unused debugging information and appends
 it to the file. With the /p option, CVPACK discards the unused
 debugging information, then proceeds to sort it throughout the
 executable file.


 28. Mouse Cursor Disappears After Right Click

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q38021

 Problem:

 I have just clicked my right mouse button to acknowledge a pop-up
 message and my mouse cursor has disappeared. I had just clicked my
 right mouse button before for another operation.

 Note: This also occurs when you hit any button on the three button
 Logitech mouse.

 Response:

 To get your mouse cursor back again, redraw the screen with the "@"
 command.


 29. CVP 2.30 Hangs When /O Is Specified, but Child Is Not Debugged

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.30
 Last Modified: 27-OCT-1989    ArticleIdent: Q49381

 Beginning with protected-mode CodeView (CVP) Version 2.30, you can
 debug child processes from within a parent process's CodeView session
 by invoking CodeView with the /O switch. When the program is executed
 to the point where the child process is invoked, CodeView displays a
 prompt showing you the child's process ID (PID) and asks, "Do you wish
 to debug (y/n)?". Entering "y" brings up the child process and allows
 you to debug it. Pressing "n" should cause the child to execute
 without any debugging.

 Unfortunately, there is a problem in CVP 2.30 that causes CodeView to
 hang if you answer no to debugging the child. The only workaround is
 to always answer yes when prompted to debug a child process, or to
 invoke CodeView without the /O switch because this prevents the prompt
 entirely.

 Microsoft has confirmed this to be a problem with CodeView Version
 2.30. We are researching this problem and will post new information as
 it becomes available.

 If the program you are debugging is not a Presentation Manager (PM)
 application, you may be able to kill the CodeView session if it should
 hang as a result of answering "n" to the debugging child process. You
 must switch to the Task Manager and use it to close the hung CodeView
 session. If you are working on a PM application, the only workaround
 may be to reboot the computer.


 30. Cannot Debug Code in Overlays in Small or Compact Model

 Product Version(s): 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q27128

 Question:

 I have a C program, compiled with Microsoft C Version 5.00, which
 consists of several modules linked together as overlays. I am not able
 to trace into code in the overlays. I compiled in the default memory
 model. What is wrong?

 Response:

 The modules must be compiled in medium or large memory model to be
 overlaid. In the default model (small), or in the compact model, there
 is only one code segment, which cannot be overlaid. The main module is
 always resident and cannot be overlaid. You must use the compile
 option /AH, /AL, or /AM.


 31. Code that Will Hang IBM XTs or Compatibles

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR57675 buglist1.00
 Last Modified:  8-NOV-1988    ArticleIdent: Q23856

 Problem:

 The following code will hang IBM XTs or compatibles if specific
 commands are issued when inside of CodeView:

    #include <stdio.h>
    main()
    {
         int n;
         double f;

         while(1)   {
                    scanf("%d",&n);
                f=1.0;
                while (n>1) f=f*n--;
                   printf("%.101g%c",f,'\n');
                    }
    }

 For the program to fail in CodeView, first set a breakpoint at
 instruction f=1.0. Issue the Go command, then the P command.

 Response:

 This is corrected in CodeView version 2.20.

 A workaround is to place a breakpoint at the instruction before or
 after the assignment to f.


 32. /DOSSEG Link Switch Fails to Make CodeView .exe

 Product Version(s): 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-AUG-1989    ArticleIdent: Q38163

 Question:

 CodeView is failing on an .exe produced using the /DOSSEG linker
 switch. CodeView responded to an attempt to run with this .exe
 with a "not enough space" diagnostic. What is the problem?

 Response:

 The modules below demonstrate the problem. In this case, compiling the
 C source module and assembling the MASM source module with the
 appropriate CodeView switches, then linking with the /CO /DO switches
 generates a bad .exe. The problem is that CodeView displays source
 with extended ASCII characters.

 To work around this problem, put .DOSSEG in the MASM modules
 being linked, and omit the /DO switch rather that trying to
 force the linker to do the work. Also, switching the order of
 the linker switches may solve the problem.

 The following example demonstrates the problem:

 #include <stdio.h>
 main ()
   {
   long int getds(void), getdsq(void);
   printf("ds.DATA  = %lX\nds.DATA? = %lX\n",getds(),getdsq());
   }

 **************************************************************
 ;        DOSSEG could be put here
         .MODEL  small
         .DATA
 array   dd      0
         .DATA?
 arrayq  dd      ?
         .CODE
         PUBLIC  _getds,_getdsq
 _getds  PROC
         mov     ax,SEG array
         mov     dx,ds
         ret
 _getds  ENDP
 _getdsq PROC
         mov     ax,SEG arrayq
         mov     dx,ds
         ret
 _getdsq ENDP
         END


 33. 3270 ERMA Emulator

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-AUG-1989    ArticleIdent: Q24200

 Question:
    Does CodeView support the 3270 ERMA emulator?

 Response:
    CodeView does not directly support any other program. In this case,
 the 3270 ERMA emulator would have to accommodate CodeView. CodeView
 performs some hardware specific routines (e.g. checking to see if an
 EGA is present) and makes some assumptions on the state of the
 machine. If another program changes the state of the machine, it may
 not work with CodeView. It has been reported that CodeView will hang
 if the 3270 ERMA emulator is enabled; we recommend you disable the
 emulator before running CodeView.


 34. Flipping and Swapping Screens

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-AUG-1989    ArticleIdent: Q24201

 Question:
    What is the difference between flipping and swapping in CodeView?

 Response:
    Both are ways of maintaining two alternate screens for display on
 one monitor. The difference is in the way the task is accomplished.
    When swapping is selected, CodeView allocates a 16K buffer (a 4K
 buffer for a monochrome adapter) to hold the alternate screen. When
 the other screen is required, CodeView swaps the screen into the
 display buffer and places the other screen into the storage buffer.
 Swapping takes memory and time, but it does not have the limitations
 of flipping.
    Flipping uses the video-display pages of the graphics adapter to
 store each screen of text. When the alternate screen is required, the
 other page is selected. Flipping is much faster than swapping and does
 not require the 16K buffer. However, it cannot be used with a
 monochrome adapter, or with programs that display graphics or use the
 video pages.


 35. CODEVIEW.DOC Incorrectly States /E Uses Extended Memory

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 10-NOV-1988    ArticleIdent: Q27763

 The CODEVIEW.DOC file included in Microsoft C Version 5.10 states that
 the /E switch enables use of extended memory for CodeView's symbol
 table.

 This is a documentation error in the CODEVIEW.DOC file. CodeView uses
 expanded, not extended memory.


 36. WINDOWCOMPAT Directs CodeView to Create a Window

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER | S_C
 Last Modified: 10-NOV-1989    ArticleIdent: Q49423

 The WINDOWCOMPAT directive in a linker definition file can cause
 strange behavior in non-Presentation Manager (PM) programs being
 debugged under CodeView. WINDOWCOMPAT is one of three application
 types that can be specified after the NAME directive. WINDOWCOMPAT is
 used for OS/2 programs that use VIO, MOU, and KBD calls and can be
 used inside a PM window or as a separate screen group.

 Debugging a non-PM application that was linked with the WINDOWCOMPAT
 option instructs CodeView to create a PM window to run the program. In
 some cases this feature could be desirable, but for most debugging, a
 PM window is only cumbersome. The way to work around this feature is
 to relink without the WINDOWCOMPAT directive.


 37. The CodeView Port Input Command Example Is Unclear

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | H_MASM H_FORTRAN S_Pascal
 Last Modified: 27-OCT-1989    ArticleIdent: Q49537

 The CodeView example for port input command is unclear in the
 following manuals:

 1. Page 150 of Microsoft C 5.10 "CodeView And Utilities, Microsoft
    Editor, Mixed Language Programming Guide"

 2. Page 150 of Microsoft Macro Assembler 5.10 CodeView and Utilities

 3. Page 150 of Microsoft Pascal 4.00 CodeView and Utilities

 4. Page 127 of Microsoft FORTRAN 5.10 CodeView and Utilities

 The example assumes the radix is in hexadecimal. To set the radix to
 hexadecimal, type in the following command:

    >n16

 After setting the radix to hexadecimal, the example works properly.

 If the radix is not in hexadecimal, a "0x" must be present for
 CodeView to recognize the value as a hex format. The following example
 shows how to use the port input command if CodeView is not in
 hexadecimal radix:

    >I 0x2f8


 38. The Difference Among Watch, Watchpoint, and Tracepoint

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q24225

 Question:

 What is the difference between a watch, a watchpoint, and a
 tracepoint?

 Response:

 A "watch" command will monitor an expression or a range of memory
 addresses, and update the watch window each time the expression or any
 location in the range changes. Using a watch never will cause program
 execution to stop; it simply "watches" unconditionally.

 A "watchpoint" monitors an expression (and an expression only) during
 program execution. It will update its value in the watch window
 whenever it changes. However, when the watchpoint expression becomes
 true (nonzero), program execution is stopped.

 A "tracepoint" monitors an expression or a range of memory addresses
 and displays the expression or the range being monitored in the watch
 window. It will stop program execution when the expression or any
 location in the range changes. Please note that writing over the old
 value at a memory location with the same value is not considered a
 change.

 The following example summarizes this information:

 Command     Object To Watch          Conditionally    Condition To
                                      Stops            Stop On
 -------     ---------------          -------------    ------------

 WATCH       expression or            No               (none)
             range of memory

 WATCHPOINT  expression               Yes             expression becomes
                                                      true (nonzero)

 TRACEPOINT  expression or            Yes             expression or
             range of memory                          in range changes
                                                      location

 Note: the "monitoring" described above is done in only window mode. If
 sequential mode is being used, you must use the Watch List command to
 see the values of any of the three types of watch statements.


 39. Tracking Down a Null Pointer Assignment Error

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER | S_C
 Last Modified: 21-AUG-1989    ArticleIdent: Q24270

 Question:

 I consistently get the error number R6001 "null pointer assignment"
 when I run my program. How can I use CodeView to determine the point
 at which the null pointer assignment is occurring?

 Response:

 Use a tracepoint, which can be set to watch a range of memory up to
 128 bytes. It will halt the execution of the program when any value in
 this range is changed. If you set a tracepoint over the entire range
 of the null segment, the program will halt immediately after the
 instruction that wrote over the null segment.

 The location of the null segment is available in the link maps of
 Microsoft compilers. It starts at DS:0 and is 42H bytes long. The
 Microsoft copyright notice is written there at program startup and
 if this area is written to during the course of the program, the
 error r6001 is generated. The most common cause of this error is
 using a pointer that has not been initialized to point to a memory
 area. Pointers that have not had space allocated for them (using
 malloc for example) or that have not been assigned to a specific
 data element (arrays or structures for example) are considered
 uninitialized.

 An example of using CodeView to determine where an unitialized pointer
 is being used follows:

 g main                  /* go to the beginning of main() */
 n16                     /* switch to hexadecimal (base 16) */
 tpb DS:0 DS:42          /* set a Trace Point of type Byte starting
                               at address DS:0 and extending to DS:42 */

 When any value in the specified range changes, CodeView will stop the
 execution of your program. The previously executed line was probably
 the line that caused the R6001 error.


 40. How to Successfully Debug VioPopUp() Code with CodeView

 Product Version(s): 2.20 2.30 2.35
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 27-FEB-1990    ArticleIdent: Q58647

 Debugging programs that take advantage of OS/2's VioPopUp() call can
 present a potentially dangerous situation. Due to the nature of the
 VioPopUp() call, any attempts to trace into the VioPopUp call will cause
 your machine to hang. The workaround for this difficulty is to set a
 breakpoint outside of the VioPopUp() call [after the VioEndPopUp()], and
 then press F5 to instruct CodeView to execute to the next breakpoint.

 The VioPopUp() call brings forward a temporary pop-up text screen group
 that can be used to display text information without altering the
 context of the foreground screen. When a VioPopUp() call is executed, the
 current foreground screen group loses the keyboard focus to the pop-up
 screen. Therefore, when you trace into a VioPopUp() call, the pop-up
 text comes forward and CodeView, running in the foreground, loses the
 keyboard focus and cannot execute a trace instruction. At this time,
 CTRL+ESC or ALT+ESC will not change the deadlock situation and the
 only alternative is to reboot.

 To work around this problem, it is essential that you do NOT step into
 a VioPopUp call. Instead, press F5 to execute to the next breakpoint.
 Setting the breakpoint AFTER the VioEndPopUp() call is critical.


 41. Capabilities of Real Mode CodeView and the 386

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_c, h_masm, h_fortran, s_pascal
 Last Modified:  1-DEC-1988    ArticleIdent: Q38205

 The information below discusses the CodeView debugger and its use
 of 80386 hardware capabilities.

 The DOS CodeView does not keep track of any of this information because
 DOS does not use any of these features. Essentially, a 386 running DOS
 is just a very fast PC and CodeView treats it as such.

 The OS/2 CodeView does not have the privilege to track many of the
 OS/2 functionality.

 The following is a list of CodeView behaviors:

 1. CodeView does not keep track of task states.

 2. CodeView does not handle privilege levels.

 3. CodeView Version 2.20 makes limited use of the 386 debug
    registers. Previous versions do not use these registers.

 4. CodeView does not keep track of interrupt gates and trap gates.

 5. CodeView cannot operate in both real and Virtual 86 mode.

 6. CodeView cannot trace to protected mode and back to real mode.

 7. CodeView does not handle traces in protected mode.


 42. Flip/Swap Setting Crucial to Debugging PM Apps with Children

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 10-NOV-1989    ArticleIdent: Q50514

 Using protected mode CodeView (CVP) to debug Presentation Manager (PM)
 programs that spawn one or more child processes can be rather
 difficult. CVP works correctly for debugging just the parent PM
 process, but once you begin CodeView with the /O option to specify
 that you also want to debug child processes, you may find that you
 hang the computer quite regularly during your debugging session.

 CodeView itself does not have a problem with PM programs even if they
 do invoke child processes. It is only when you use the /O switch to
 debug the children at the same time that you run into difficulty. This
 is because of problems with CodeView conflicting with the OS/2 kernel
 as you bring a process to the foreground for debugging, while a
 system-dependent process like the PM parent is relegated to the
 background where it can become blocked.

 For example, if the parent gets to a point where it is waiting on a
 message, but it is not in the foreground, there is no way to get the
 focus back to this waiting process and you are essentially hung. The
 parent cannot process the message because it must be in the foreground
 to do so, and CodeView cannot continue until the message is processed,
 so it just waits.

 The key to debugging the parent and child processes of a PM program at
 the same time is the setting of Flip/Swap on the Options menu. Under
 CodeView, Flip/Swap ON forces messaging, Flip/Swap OFF does not.
 Therefore, you must turn Flip/Swap on and off as you go, depending on
 which particular part of the program you are currently debugging. The
 Flip/Swap setting is crucial in determining whether you hang the
 system or not.

 The ability to debug child processes from the parent's CodeView
 session became an available option beginning with CVP Version 2.30. By
 specifying the /O switch on the command line, CVP allows you to trace
 into child processes. (See the CVP 2.30 Note below if you are using
 that particular version of CodeView.)

 As far as actually debugging child processes in PM programs, you must
 proceed in an exacting manner. Unfortunately, the specifics are
 different for every program, so an all-encompassing set of debugging
 procedures cannot be devised. Nevertheless, the following general
 guidelines can be used for debugging most PM applications with their
 accompanying child processes:

  1. It is only with the /O option that any of this becomes critical.

  2. You need to debug in a full screen and not a PM window.

  3. Remember, Flip/Swap ON forces messaging, Flip/Swap OFF does not.
     Therefore, while you begin debugging in the parent program, you
     should have Flip/Swap ON, since you need messaging whenever you
     are doing any of the window initialization routines.

  4. Set a breakpoint in the parent somewhere after the window
     initialization code, but before the call to start the child
     process. It varies, but it usually works to put the breakpoint at
     the "while get message - dispatch message" loop or in the
     ClientWndProc procedure at the main switch statement.

  5. You must make sure that the breakpoint is placed in a position
     where you will stop at it before the prompt appears to ask you if
     you want to debug the child, but after ALL the window
     initialization has been completed. You will also probably need to
     set another breakpoint at the point where the parent program is
     going to begin executing again after you have finished working
     with the child.

  6. Do a GO, and when the breakpoint is reached, turn Flip/Swap OFF.
     Make sure that the prompt to debug the child is not already
     visible or you will lock up.

  7. Do a GO (or some traces) and you should get the prompt to debug
     the child. Answer "Y" and you should be able to debug the child
     process at this point.

  8. Use the Process command (the "|") to gain access to the child.
     Never use CTRL+ESC or ALT+ESC to switch to the other processes
     because these will almost assuredly cause you to hang.

  9. Go ahead and set breakpoints, watches, etc. in the child and do
     your debugging.

 10. After the child process is completed, use the Quit command to exit
     the child process's CodeView screen or use the Process command to
     reselect the parent process.

 11. Once you have returned to the parent process, and before you do a
     Restart (or load), or before you do ANY other window
     initialization, you MUST turn Flip/Swap ON again.

 12. Remember to always be aware of where you are in the program and
     what the current state of Flip/Swap is, since turning Flip/Swap on
     or off at the wrong time will almost always cause you to hang.

 Again, this is only the general outline of steps to follow and each
 application requires different specific steps. Don't be too surprised
 if you still run into occasional lock-ups.

 CVP 2.30 Note: When using the /O switch with CVP Version 2.30, there
 is a bug that may also cause you to hang. The problem involves using
 /O on the command line and then saying "No" when asked if you want to
 debug the child. So, with this version of CodeView, you should always
 answer "Yes" when asked if you wish to debug the child.

 For more information on this problem, use the following query:

    CodeView 2.30 hangs debugging child processes


 43. Can't Debug .COM Files in Source Mode

 Product Version(s): 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-AUG-1989    ArticleIdent: Q38288

 The .COM format files created with the Microsoft Macro Assembler
 cannot contain symbolic and source-line information for the CodeView
 debugger. You can only debug these files in assembly mode.


 44. CODEVIEW.DOC File Error: Mouse Works with the /2 Option

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-NOV-1988    ArticleIdent: Q27764

 Question:
    The CODEVIEW.DOC file included with Microsoft C Version 5.10 states
 that using the /2 switch disables mouse support on the debugging
 display. Is this true?

 Response:
    This is an error in the CODEVIEW.DOC file.
    CodeView does support the mouse when using the /2 switch. In fact,
 if you are debugging a program which itself uses the mouse, using the
 /2 switch will allow you to use the mouse on CodeView's debugging
 screen as well as your application's output screen.


 45. "?CANNOT DISPLAY" After Column 135 in Command Window

 Product Version(s): 3.00 3.11 | 3.00 3.11 3.50
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q68696

 The code below demonstrates a limitation of the CodeView debugger.
 When the command "?y" is executed in the COMMAND window, the structure
 "y" is displayed. However, CodeView displays the structure only to
 column 135 and then prints "?CANNOT DISPLAY," ignoring the rest of the
 elements in the structure. The output appears as follows:

    --------------------------command----------------------------
   |>?y                                                          |
   |{this_field_01=0x0000, ... ,this_field_07=?CANNOT DISPLAY    |
   |                        ^                 ^                  |
   |                        |                 |                  |
   |                  Fields 2-6 displayed    Column 135         |
   |                                                             |
    -------------------------------------------------------------

                       CodeView Command Window

 To view all elements of a structure, you should use the QUICK WATCH
 function. In the example below, the contents of the whole structure
 can be seen by typing "??y". A dialog box will appear on the screen
 showing the contents of the structure. By scrolling down in the dialog
 box, the contents of every element of the structure can be seen. The
 structure contents are displayed as follows:

           --------------- Quick Watch -----------------
          |                                             |
          |-y                                           |
          |   this_field_01=0                           |
          |   this_field_02=0                           |
          |   this_field_03=0                           |
          |   this_field_04=0                           |
          |   this_field_05=0                           |
          |   this_field_06=0                           |
          |   this_field_07=0                           |
          |   this_field_08=0                           |
          |   this_field_09=0                           |
          |   this_field_10=0                           |
          |   this_field_11=0                           |
          |   this_field_12=0                           |
          |   this_field_13=0                           |
          |   this_field_14=0                           |
          |   this_field_15=0                           |
           ---------------------------------------------

                       Quick Watch of Variable

 Sample Code
 -----------

 struct x {
    int this_field_01;
    int this_field_02;
    int this_field_03;
    int this_field_04;
    int this_field_05;
    int this_field_06;
    int this_field_07;
    int this_field_08;
    int this_field_09;
    int this_field_10;
    int this_field_11;
    int this_field_12;
    int this_field_14;
    int this_field_15;
    int this_field_16;
    int this_field_17;
    int this_field_18;
    int this_field_19;
    int this_field_20;
 };

 main()
 {
     struct x y;
 }


 46. Debugging PM Apps with Two Monitors Does Not Require /2 Switch

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q49824

 Problem:

 I am using CodeView to debug my Presentation Manager (PM) program and
 I am using the /2 switch to redirect the CodeView screen to a
 monochrome monitor. When I press F5 to start my program, a protection
 violation occurs, but it works correctly when I run it from the OS/2
 command line.

 Response:

 The /2 switch for CodeView is not supported for Presentation Manager
 application debugging. However, you may redirect the CodeView screen to
 a monochrome monitor if you do the following:

 1. Start a full-screen command prompt.

 2. At the prompt, type the following command (this puts the prompt on
    the monochrome monitor):

       mode mono

    Note: You must be in a 25-line screen mode before you attempt the
    mode mono. If you are in a 43- or 50-line mode, the display is
    corrupted.

 3. At the prompt, type the following command, where "appname" is your
    application's name:

       cvp appname

 4. After you are finished debugging, you can return the prompt to your
    primary display by typing the following command:

       mode co80


 47. How CodeView Interprets Values (octal, decimal, hexadecimal)

 Product Version(s): 1.x 2.00 2.10 2.20 | 2.20
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER |
 Last Modified: 23-NOV-1988    ArticleIdent: Q38299

 Problem:

 When trying to watch a portion of memory, I have a problem with
 the following command at the dialog prompt:

    WW DS:0050 L 4.

 I thought this should have created a watch on the four words starting
 at offset 0x50. It actually set the watch starting at 0x28, CodeView
 interpreted the number as if it had been in base 8. Using the N
 command to change the radix doesn't make any difference.

 Response:

 In this case, the 0's before the offset cause CodeView to evaluate the
 expression in octal. CodeView provides three different prefixes for
 numbers to use an explicit base: 0 signifies octal, 0n signifies
 decimal, and 0x signifies hexadecimal. The current radix setting will
 have no bearing on numbers entered with these prefixes; however, it
 will affect those without prefixes.

 The lines below have different meanings when setting watches.
 The left column is the command, while the right column is an example
 of the display produced in the watch window. Radix is assumed to be 10.

 The following is an example:

 1. ww 50               50    :  0067:0032  6942

 2. ww 050              050   :  0067:0028  6328

 3. ww 0n50             0n50  :  0067:0032  6942

 4. ww 0x50             0x50  :  0067:0050  6163

 The first command sets the watch at the address specified using the
 current radix. This address will change when you use the N command to
 change the radix; the 50 on the left of the watch remains the same;
 however, the offset in the address will change to watch 50 in the new
 base. This address will always be displayed in hexadecimal, but 50
 will be evaluated differently.

 Examples 2 through 4 show watches being set in octal, decimal, and
 hexadecimal modes, respectively. These addresses will never change
 with a change of radix.

 Notice that watches 1 and 3 match. This is because by default CodeView
 is in base 10, so 50 and 0n50 evaluate to the same thing. Using N 8 will
 cause watches 1 and 2 to match, and N 16 will match 1 and 4.


 48. Interrupt Conflict with Greenleaf Libraries

 Product Version(s): 2.20    | 2.20
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | CV CVP
 Last Modified: 23-NOV-1988    ArticleIdent: Q38314

 The Greenleaf Comm Library, a collection of asynchronous
 communications functions for use with the C compiler, causes severe
 complications with CodeView (e.g. crashes, lockups) due to interrupt
 conflicts. Greenleaf Software is aware of this difficulty and will
 advise customers of the incompatibility.

 No workarounds are available. Greenleaf Software is located in
 Carrollton, TX, and can be reached at (214) 248-2561.


 49. CodeView Gives "Illegal Instruction" on Clone 386

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | CV
 Last Modified: 23-NOV-1988    ArticleIdent: Q38317

 Some clones that are not entirely IBM-compatible under CodeView may
 give an "illegal instruction" message upon executing Go (F5), and then
 hang, requiring a warm boot. If the instruction being called illegal
 is FINIT or FNINIT, the particular ROM BIOS probably has a built-in
 387 emulator. Either turn off the emulator, or set the environment
 variable SET NO87=(some string).



 50. Thirty-Two-Bit Register Not Visible under OS/2

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 23-NOV-1988    ArticleIdent: Q38375

 Thirty-two-bit registers are not viewable (using F2) under CVP even if
 you have an 80386-based machine. This is not a problem with CodeView;
 it is a limitation.

 Real mode CodeView (CV) DOES support viewing 32-bit registers. This
 is because of the unprotected and generally more flexible nature of
 DOS. Using the full 32-bits of the 80386 under OS/2 is considered
 hazard-prone and is not supported by CVP.



 51. CodeView Instruction Pointer Miscounts Very Long Lines

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.20
 Last Modified:  1-DEC-1988    ArticleIdent: Q38382

 CodeView may display the "current instruction" highlight on the wrong
 line if the source file contains lines that are very long.

 The compiler counts the long lines as one line, but CodeView counts
 the very long lines as two lines. This makes the line number
 calculations incorrect and causes the "current line" highlight to
 appear on the wrong line. This problem does not occur if the source
 lines are less than 251 characters in length.

 Because the Microsoft Editor breaks lines that are longer than 250
 characters, this problem does not occur if you create and maintain
 your source files with the Microsoft Editor.

 Microsoft has confirmed this to be a problem in CodeView Version 2.20.
 We are researching this problem and will post new information as it
 becomes available.


 52. CodeView Requires PUBLIC to Trace MASM Program in Source Mode

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | H_MASM
 Last Modified:  3-MAY-1989    ArticleIdent: Q44006

 A MASM program that runs perfectly from a DOS prompt refuses to trace
 in source mode inside of CodeView. The program single-steps in
 assembly mode, but an attempt to trace into the code in source mode
 results in the program terminating upon reaching the first data
 declaration.

 In addition, the program does not come up in source mode when CodeView
 is started, but can be changed into source mode with "View" "Source".

 This problem happens when the code and data segments are not declared
 as "PUBLIC". The code is valid and executes perfectly inside of
 CodeView or from a DOS prompt. However, CodeView cannot follow the
 logic at a source level.

 A program constructed in the following manner exhibits the symptoms
 described above:

 TITLE    myprog

 StackSeg Segment STACK
 .
 .
 .
 DataSeg  Segment DATA
 .
 .
 .
 CodeSeg  Segment CODE
 .
 .
 .
 END      myprog

 However, if the following minor changes are made to the program, and
 the segments are declared as "PUBLIC", CodeView can trace through the
 program in source mode:

 TITLE    myprog

 StackSeg Segment STACK
 .
 .
 .
 DataSeg  Segment WORD PUBLIC 'DATA'
 .
 .
 .
 CodeSeg  Segment WORD PUBLIC 'CODE'
 .
 .
 .
 END      myprog


 53. Cannot Use /2 Switch on IBM PS/2 in CodeView

 Product Version(s): 2.10 2.20  2.30 | 2.20 2.30
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G881031-5515
 Last Modified:  9-AUG-1989    ArticleIdent: Q38865

 To use the /2 switch with CodeView, your computer must be equipped
 with a monochrome display (MDA) and a color display (CGA/EGA/VGA). The
 IBM PS/2 computers aren't currently configurable this way because they
 come with built-in VGAs or MDAs, but not both.

 If a hardware vendor starts selling MDAs that can be added to systems
 with built-in VGAs, this problem will be solved. An MDA card is
 needed that plugs into the PS/2 and works correctly in conjunction
 with the built-in VGA so that PS/2 owners can have a dual-monitor
 system.

 Currently, there is no solution to this debugging restriction other
 than using CodeView through the com port in sequential mode (/T) with
 a debugging terminal.


 54. CodeView Does Not Support Debugging Spawned Process

 Product Version(s): 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-FEB-1990    ArticleIdent: Q58653

 The following are several reasons why CodeView doesn't provide
 debugging support for spawned processes under DOS:

 1. DOS is not a multitasking operating system. CodeView cannot start
    another thread/process to watch the execution of the spawned
    process.

 2. DOS does not provide debugging support for the DOS BIOS calls (int
    21h). Since all spawn() and exec() functions under DOS have to go
    through the BIOS to run, CodeView cannot follow the spawned
    program.

 3. DOS only recognizes 640K of memory; therefore, there is
    insufficient memory to debug a large program, since both the parent
    and child processes have to reside in memory at the same time.


 55. Display Settings for Compaq Gas Plasma Screen

 Product Version(s): 1.00 2.10 2.20 | 2.20
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified:  6-DEC-1988    ArticleIdent: Q38866

 The default monitor settings for CodeView do not work properly with
 the Compaq gas plasma display adapter. Invoking CodeView with the /b
 switch corrects the problem.


 56. CodeView: Watchpoints and Tracepoints with Enumerated Types

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_c
 Last Modified: 28-MAR-1989    ArticleIdent: Q42601

 CodeView will not display the members of an enumerated type as they
 are declared in a C program. Only the integer representations of these
 types of variables can be shown. The following is an example:

 /*  Example enumerated type.
  */

 enum e_type
 {
     var1,
     var2,
     var3
 };

 enum e_type foo = var1;

 CodeView will not display "var1", "var2", or "var3" when watching a
 variable of type e_type, such as foo. CodeView will instead show the
 integer values of the variable: 0, 1, and 2, respectively. In order to
 watch the variable foo, you must explicitly display its value as an
 integer. The following command will add the proper watch:

     w? foo,d

 To set a watchpoint or a tracepoint on the same variable, further type
 casts must be made. These lines will produce watchpoints and
 tracepoints on foo, as follows:

     wp? *(int *)&foo == 1
     tp? *(int *)&foo

 Trying to set a watchpoint without the proper type cast will result in
 the following error:

     Operand types incorrect for this operation

 Setting a tracepoint on foo without this type cast will set the
 tracepoint but will only show "?CANNOT DISPLAY" in the watch window.
 Going through the right steps will display the current integer value
 of the variable, as it should.


 57. "?CANNOT DISPLAY" Error Not Documented in CodeView Documents

 Product Version(s): 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | TAR64267 docerr
 Last Modified: 21-AUG-1989    ArticleIdent: Q24877

 Problem:

 When trying to evaluate (?), a function that returns void, I get the
 error "?CANNOT DISPLAY". I cannot find this error message in the
 "Microsoft CodeView Utilities and Editor" manual.

 Response:

 This error message is not contained in the CodeView manual.

 The "?CANNOT DISPLAY" error message will be displayed in cases where
 the expression evaluator cannot return a value, such as a function
 returning void.


 58. Watch Bytes (wb) Command Can Be Used to Watch a Buffer in HEX

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50224

 Question:

 Is there a way to keep tabs on the contents of a buffer via a watch
 command? We want to observe the contents of a 20-character buffer in
 HEX. The buffer is not necessarily null terminated.

 Response:

 The way to watch a buffer in CodeView in hexadecimal with the Watch
 command is to use Watch Bytes (wb) as follows:

    >wb *buffer L 10  ; this will watch the first 10 bytes of
                        buffer in HEX

 For the given example, you should follow the previous command with the
 following:

    >wb *(buffer + 10) L 10  ; this will watch the next 10
                               bytes in HEX.

 Please note that both the length specifier as well as the number 10
 used to offset the pointer in the second command are taken in the
 current radix. The example above assumes a radix of 10. You can
 explicitly specify the base of the number in hex as follows:

    >wb *buffer L 0x0a
    >wb *(buffer + 0x0a) L 0x0a

 For more information on the wb command in CodeView, see the "Microsoft
 CodeView and Utilities, Microsoft Editor, Mixed-Language Programming
 Guide" manual.


 59. Specifying Both /T and /W Disables Mouse

 Product Version(s): 2.20    | 2.20
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified:  6-DEC-1988    ArticleIdent: Q38867

 If you invoke CodeView with the following, the use of your mouse is
 disabled:

    CV /T /W program

 Don't specify the /T switch. Using /T with /W produces mutually
 exclusive modes of operation.


 60. Illegal Instruction in CodeView

 Product Version(s): 1.x 2.00 2.10 2.20 | 2.20
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER | S_C h_fortran S_PASCAL
 Last Modified:  6-DEC-1988    ArticleIdent: Q38868

 Question:

 When I compile and link my C program and try to run it under CodeView,
 execution stops on the open curly brace of main. The view then goes to
 assembly, and the message "Illegal instruction" appears in the dialog
 window. Is there something wrong with the startup code?

 Response:

 This error can be produced when the main module of a program is
 compiled for one memory model and is then explicitly linked with a
 library for a different model. When the startup code is linked to the
 entry point of the program, different size instructions are used for
 the different memory models. If the program expects one size and the
 linker links in a different size, the startup instructions will be
 misinterpreted and result in this error.


 61. Entering Double Words at a Prompt Prevents Reloading Program

 Product Version(s): 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER| | S_C S_PASCAL H_FORTRAN H_MASM buglist2.30
 Last Modified: 30-NOV-1989    ArticleIdent: Q50410

 When using the Enter Double word (ED) command within the CodeView
 symbolic debugger and allowing the debugger to prompt, you will
 prevent the debugger from reloading your executable (using the L
 command). This problem occurs only when you allow the debugger to
 prompt you for the double word and you enter a double word.

 This problem can manifest itself in several ways, depending on the
 version and on other unpredictable circumstances. Symptoms of the
 problem include the following:

 1. Giving the message "No such file/directory"

 2. Giving the message "Arg list too long"

 3. Generating an internal debugger error 7

 Valid workarounds consist of entering words (not double words) at the
 prompt, or entering double words on the command line (without being
 prompted).

 Microsoft has confirmed this to be a problem with CodeView Version
 2.30. We are researching this problem and will post new information
 here as it becomes available.


 62. CodeView 2.20 Does Not Allow Routine.Variable Specification

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_PASCAL S_C H_FORTRAN H_MASM DOCERR
 Last Modified: 10-NOV-1989    ArticleIdent: Q50698

 On Pages 91-92 of the "CodeView and Utilities" manual that accompanied
 C 5.10 and Pascal 4.00 for CodeView Version 2.20, the period is
 documented as being useful as a specifier of local variables in parent
 functions. The syntax is stated to be as follows:

    routine_name.variable_name

 However, this feature was not implemented in Version 2.20 of CodeView.
 It was implemented in CodeView Version 2.30 (which accompanied FORTRAN
 5.00).

 This feature is useful in all languages, but particularly helpful in
 Pascal because of the "nested-scoping" (the ability of a function to
 access variables from the routine that called it) that occurs in
 Pascal.

 To use this feature in CodeView 2.30, you must be in either the
 routine where the variable is defined or in a routine that is a child
 (or grandchild, etc.) of that routine. After entering the proper
 routine, any variable name can be referenced with a routine and
 variable name (see example below).

 program first (input, output) ;
 var a: integer ;            { Available throughout the program }

     procedure second ;
     var b: integer ;        { Available in second and third }

         procedure third ;
         var c: integer ;    { Available in third }

         begin
             a := 3 ;
             b := 3 ;
             c := 3 ;
         end ;

     begin
         a := 2 ;
         b := 2 ;
         third ;
     end ;

 begin
     a := 1 ;                { Cannot watch second/third variables }
     second ;
 end.

 When in procedure third, you can place a watch on the variables in
 procedure second in the following manner:

 w? second.b

 This will display the variable in procedure second. This variable
 cannot be displayed from the main program, however.


 63. Using a Debugging Terminal with CodeView

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-JAN-1989    ArticleIdent: Q39179

 It is possible to use either a dumb terminal or another machine (PC or
 Macintosh, running a communications package at 9600 baud) as a
 debugging terminal for CodeView. To take advantage of this option, do
 the following:

 1. Connect the second terminal to the com port (COM1 or COM2).

 2. Initialize the communications package to set up the
    second machine as a dumb terminal. Set the baud rate at
    9600.

 3. Start CodeView in either window or sequential mode.

 4. Redirect either the output ( >COM1 ) or both input and output
    ( =COM1 ) to the second terminal.

    If you redirect just the output to the second terminal, you will
    see the debugging output on the second terminal, and program output
    on the primary terminal. If you redirect input and output, you will
    also be able input program information (responses to prompts,
    input from the keyboard, etc.) on the primary terminal, and input
    CodeView information on the secondary terminal.

 5. Set your options and run the program.


 64. Pascal Version of CodeView Version 2.20

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_PasCal
 Last Modified: 14-AUG-1989    ArticleIdent: Q39181

 CodeView Version 2.20 is different for Pascal then the rest of the
 languages. The Pascal version of CodeView 2.20 is the only version
 that has the Pascal Expression Evaluator. The way you can determine
 whether you are running the Pascal version is that Pascal will appear
 under the Languages menu.

 If you have multiple Microsoft Languages, you do not have to keep
 multiple versions of CodeView on your system. CodeView Version 2.20 is
 compatible with all of our languages. However, there is one exception
 -- if you are using Microsoft Pascal, make sure you use the version
 that came with Pascal. It is the only version that has the Pascal
 Expression Evaluator and all of the other language evaluators.

 To check if the version you have is the Pascal version, invoke
 CodeView and pull down the Languages menu. If it lists Pascal in the
 menu, you are using the Pascal version that is compatible with all of
 the Microsoft languages.


 65. "." on the LIBPATH Eases DLL Debugging, But Not for CVP 2.20

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 10-NOV-1989    ArticleIdent: Q50711

 When debugging OS/2 DLLs with protected mode CodeView (CVP), you must
 specify each DLL on the command line with an /L switch, and the DLL
 must be in the current directory as well as in a directory on the
 LIBPATH as set in CONFIG.SYS.

 For ease of debugging, if you put a period ("."), which means the
 current directory, as one of the directories on your LIBPATH, then a
 DLL in the current directory will also be on the LIBPATH and you won't
 need to have two copies of a DLL present on disk for debugging.

 This method only works for versions of CVP beginning with 2.30. CVP
 Version 2.20 will not recognize DLLs in a "." LIBPATH directory.

 If a copy of the DLL called by the program being debugged is not in
 the current working directory, you will not be able to trace into the
 DLL. If a copy of the DLL is not in a LIBPATH directory, CodeView will
 not be able to find the DLL. In this case, instead of coming up in the
 usual "debugging mode," CodeView immediately exits and returns to the
 command prompt after several seconds.

 Many DLL debugging problems arise from the fact that the copy of a DLL
 that is on the LIBPATH may be inadvertently out of date compared to
 the version in the current directory that is being used for debugging.
 By putting a period on the LIBPATH, the current directory becomes a
 LIBPATH directory and only one copy of the DLL needs to exist, thus
 eliminating any DLL update inconsistencies.


 66. CodeView Trace Skips Statement Following Switch Statement

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified:  7-MAR-1990    ArticleIdent: Q59315

 CodeView incorrectly maps assembly level instructions to source code
 in the first statement following a switch statement with seven or more
 cases.

 As shown in the code sample below, the statement following the switch
 is executed correctly, but CodeView steps over the statement while
 tracing in source mode. In mixed source and assembly mode, the
 statement following the switch may be traced into.

 Sample Code
 -----------

 # include<stdio.h>

 void main(void)
 {

    short tag, marker;

    marker = 0;
    tag = 5;

    switch(tag){
       case 1:
          break;
       case 2:
          break;
       case 3:
          break;
       case 4:
          break;
       case 5:
          break;
       case 6:
          break;
       case 7:
          break;
       default:
          break;
    }

       marker = 2;

 }


 67. Using CodeView to Create Disassembled Program Listings

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 12-APR-1990    ArticleIdent: Q51323

 The following steps can be used to create an assembly listing of a
 program with CodeView:

 1. Begin CodeView in sequential mode by using the /T command-line
    switch.

 2. Specify a listing file to redirect CodeView output to by typing the
    redirection operator ">" followed by a filename at the dialog
    prompt. You may redirect the output directly to a printer by
    specifying the printer after the ">" (e.g., >PRN).

    (Note: From this point on, commands will not be viewable.)

 3. Use the Unassemble command "U" to disassemble the code and send a
    listing of the program to the output file. If you do not specify
    the starting address and the range to unassemble, CodeView will
    unassemble the next eight lines of code. See the CodeView
    documentation for more information on the Unassemble command.

 You can use this method on any files, whether or not they contain
 CodeView information. In this regard, you can create assembly listings
 of programs that were not created with a Microsoft compiler. Please
 also note that you cannot create assembly listings of instructions
 other than 8086 instructions.


 68. Debugging DLLs with Codeview

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 18-DEC-1989    ArticleIdent: Q51764

 To debug most DLLs (Dynamic Link Libraries) in CodeView, CVP
 (protected mode CodeView) Version 2.20 or later is required. For DLLs
 loaded via DosLoadModule(), CVP Version 2.30 or later is required.

 Invoke CodeView with the /L switch as follows:

    cvp /L dll1name /L dll2name main.exe

 Make sure that each DLL you want to trace into is specified by the /L
 option.

 CodeView cannot debug DLLs that have either IOPL or EXECUTEONLY
 specified with the CODE directive in the associated definition (.DEF)
 file. For DLLs that require these controls, the Kernel Debugger
 supplied with the SDK is required.

 Note: With CVP 2.30, pathnames cannot be specified for DLLs;
 therefore, the DLL must reside in the current directory. For more
 information, query on the following:

     CODEVIEW DLL LIBPATH


 69. Debugging Bound Applications

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 | 1.11 2.02.02 2.20 2.30
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER | TAR63888
 Last Modified: 14-AUG-1989    ArticleIdent: Q25219

 CodeView does not support the debugging of bound applications in real
 mode. However, CVP in protected mode will allow you to debug such
 applications.


 70. No Symbolic Information Generated for Pascal Units

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_pascal
 Last Modified: 12-JAN-1989    ArticleIdent: Q39811

 The Microsoft Pascal Compiler Version 4.00 generates no symbolic
 debugging information for Pascal Units. As a result, when tracing
 through a Pascal program Unit, attempting to access any local
 variables by using trace/watchpoints, dumps, examines, etc. yields a
 "symbol unknown" error.

 The only workaround is to transform the program Units into Modules.


 71. "Internal Debugger Error: 0" When Watching Structure Members

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist2.30 cv
 Last Modified: 29-DEC-1989    ArticleIdent: Q51834

 When watching a member of a structure using the "w?" or "?" commands,
 it is possible to get the message "internal debugger error: 0". When
 this happens, the only way to view the contents of the member is to
 use the "D" or "??" commands.

 Code Example
 ------------

 typedef struct {
    char *(*instruction)[];
    } *structype;

 structype mac;

 void main (void)
 {
 }

 If you set a watch on an element of the structure variable in the
 above program such as "w? mac->instruction[0]" (without the quotation
 marks) you'll get the message "internal debugger error: 0." Use the
 dump command "D" or the special "??" structure viewing command to look
 at the contents of the member.

 Microsoft has confirmed this to be a problem in CodeView Version 2.30.
 We are researching this problem and will post new information here as
 it becomes available.


 72. Incorrect Error Generated for Very Small COM Files

 Product Version(s): 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR65183 buglist2.00
 Last Modified: 21-AUG-1989    ArticleIdent: Q25365

 Problem:

 If my COM file is less than 8 bytes long and I try to load it into
 CodeView, I get the error message "Invalid executable file format -
 please relink."

 Response:

 This problem occurs only on COM files less than 8 bytes in length.

 Microsoft has confirmed this to be a problem with CodeView Version
 2.00. We are researching this problem and will post new information as
 it becomes available.


 73. Dual-Monitor Setup Requires 8-Bit Data Paths for Both Monitors

 Product Version(s): 1.00 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER | s_c s_pascal h_fortran h_masm b_basiccom
 Last Modified: 21-MAR-1990    ArticleIdent: Q51870

 When writing to a system that has a dual-monitor setup, you must make
 sure that both the monochrome monitor and the color monitor are using
 an 8-bit data path. In any dual-monitor write scheme, both display
 cards must be configured to write to a common data path (either both
 8-bit or both 16-bit mode). Today's monochrome adapters use 8-bit
 paths exclusively.

 Most display cards that use a 16-bit mode can autosense whether they
 are being written to in a dual-monitor mode, but some cards, such as
 the ATI VGA Wonder card, do not sense for this situation; therefore,
 you must set the card to an 8-bit path manually.

 If you are using dual monitors and you experience strange behavior
 such as garbage or blinking characters on the monochrome screen, make
 sure that your 16-bit video card is running in 8-bit mode.

 The most common use for a dual-monitor setup is for debugging graphics
 applications in CodeView.


 74. Retrieving Previously Entered Commands

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER | TAR65921
 Last Modified: 14-AUG-1989    ArticleIdent: Q25539

 Question:

 Is there a method to retrieve commands after typing them in once? For
 instance, if I type "d some_data_area l 40", I would like to retrieve
 the command without having to retype it. A suggested method would be
 to allow the user to scroll on the command, then press a key to make
 the command active.

 Response:

 The only way to retrieve commands is to highlight them with the mouse
 and press the INS key. This method inserts the command into the
 command line. We are considering making an easier way to scroll
 through the commands and may implement it in a future version.


 75. system() Call May Cause CodeView to Terminate Process

 Product Version(s): 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified: 22-JAN-1990    ArticleIdent: Q57867

 Using real-mode CodeView to trace over the system() run-time function
 will cause the debugger to terminate the parent process upon return
 from the child process in certain situations where the child does a
 multiple directory-level traversal.

 Instead of tracing, use the "Go" Command (F5) to run past the system()
 call. This procedure allows the program to run to completion.

 The program below demonstrates this problem, but it requires that
 TREE.COM be somewhere in the path. Compile the code with the /Zi and
 /Od options and use CodeView to trace into the program, using F8.
 After TREE.COM executes, CodeView will display the "Program terminated
 normally" message, preventing the last printf() from being executed.

 Microsoft has confirmed this to be a problem with CodeView Versions
 2.20 and 2.30. We are researching this problem and will post new
 information here as it becomes available.

 Code Example
 ------------

 #include <process.h>
 #include <stdio.h>

 void main (void)
 {
         printf ("This is the beginning of the program\n");
         printf ("Calling TREE.COM\n");
         system ("tree");

         /* This line will never be executed */
         printf ("Back from spawn\n");
 }


 76. CodeView Versions 2.10 to 2.30 Use Four Extra File Handles

 Product Version(s): 2.30 2.20 2.10 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-JAN-1990    ArticleIdent: Q25950

 Problem:

 CodeView Versions 2.00 to 2.30 seem to be using four additional file
 handles. The following program attempts to open 20 files, reporting
 its success or failure after each attempt:

     #include <stdio.h>
     #include <string.h>
     #include <stdlib.h>

     main()
     {
             FILE *streams[20];
             int i;
             char buffer[12];
             char *p;

             for (i = 0; i < 20; i++) {
                     p = itoa(i, buffer, 10);
                     p = strcat(buffer, ".dat");
                     streams[i] = fopen(buffer, "w+");
                     printf("streams[%d] = %d\n", i, streams[i]);
             }
     }

 Running outside of CodeView, the call to fopen() fails after 15
 streams have been opened. Running in CodeView Versions 1.x, the call
 fails after 15 files have been opened. However, in CodeView Versions
 2.00 to 2.30, it fails after 11 file handles have been opened.

 Response:

 CodeView Versions 2.00 to 2.30 require four file handles for their own
 use. Remember that MS-DOS itself has five preopened file handles. If
 you want to open more than 15 files, follow the steps specified in the
 C Version 5.10 README.DOC to modify the C start-up code to allow
 opening more than 20 files.


 77. Copying Text from Display Window to Dialog Window

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-JAN-1989    ArticleIdent: Q40110

 Question:

 Is it possible to copy text from the display window down to the dialog
 window to use at the command line in Microsoft CodeView?

 Response:

 Yes, if you have a mouse. You can highlight with the mouse the section
 of text you would like to copy and press the INSERT key. The
 highlighted text will appear in the dialog box.

 This is very useful if you have very long variable names that you want
 to watch and don't want to retype the long variable name each time.
 Simply type a w? on the command line, then highlight the variable name
 with the mouse and press the INSERT key.

 Strange behavior can occur if you use the SHIFT key in combination
 with the INSERT key. For example, if you use the INSERT key on the
 extended keyboard along with the SHIFT key, it works the same as using
 INSERT alone. However, if you turn NUM LOCK off on the keypad so you
 can you the INSERT key with the SHIFT key, you will get a zero instead
 of the string of text. To get the string of text, you have to turn NUM
 LOCK on. This seems backwards because with NUM LOCK on you would
 expect to get a zero, but you get the text.

 The workaround is not to use the SHIFT key in conjunction with the
 INSERT key. INSERT alone works correctly.


 78. OS2PATCH for CVP Not Needed in OS/2 Version 1.10.

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q30976

    The OS2PATCH supplied with CodeView (protected) Versions 2.20 and
 2.30 allows you to use command 7 on machines with math coprocessors.
 This patch works only with OS/2 Version 1.00. The PTRACE feature was
 updated in Version 1.10, so this patch is not needed in OS/2 Version
 1.10.
    This patch only works on IBMs version of OS/2 1.00.  If they have
 a different version have them talk to the people who they received
 OS/2 from.  If it was from us then they need to systems languages
 support.
    Please refer to the file OS2PATCH.DOC for more information.



 79. I/O Redirection Under CV Not Supported Prior to Version 2.30

 Product Version(s): 1.x 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER |
 Last Modified: 23-JAN-1990    ArticleIdent: Q57870
 In versions of CodeView earlier than Version 2.30, it was not possible
 to redirect the input or output of the program being debugged. For
 example, a "filter" program that takes input from a file specified by
 the input redirection operator ("<") is hindered by this limitation
 under pre-2.30 CodeView because there is no way to specify that you
 want the redirection to apply to the application rather than to
 CodeView itself.

 In CodeView (CV) or protected-mode CodeView (CVP) Version 2.30,
 redirection on the command line following the program name is directed
 to the program being debugged. For example, invoking CodeView 2.30
 with the following command line

    CV test < test.dat

 causes all input to the program TEST.EXE to be read from the file
 TEST.DAT.

 Redirecting I/O to CodeView itself is useful for involved debugging
 sessions where many CodeView dialog commands can be put into a
 separate text file that is automatically read by CodeView during
 debugging. For instance, this method will allow a complicated
 debugging scenario to be accurately repeated any number of times.
 Prior to CV and CVP 2.30, this was the only type of redirection
 supported while debugging.

 Starting with CodeView 2.30, you can redirect I/O to both the
 application being debugged and to CodeView. The CodeView redirection
 is done with the /C command-line option, or from within CV itself with
 the redirection dialog commands ("<" and ">"). Since the /C switch
 allows you to specify CV dialog commands on the command line, you can
 specify the redirection at this point. For example, the following
 command line

    CV "/C<cv.dat" test < test.dat

 brings up CodeView with TEST.EXE as in the example above (with the
 TEST.EXE input coming from TEST.DAT), but this time CodeView also
 reads the debugging instructions to perform from the file CV.DAT.


 80. /2 and /O Switches Not Compatible

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  9-NOV-1988    ArticleIdent: Q30978

    The UTILITY.DOC states that the /O switch is not compatible with
 the /2 switch. However, the SDK Installation Notes file uses the
 following code as the example of how to debug child processes:

     cvp /2 /O <program> <program arguments>

    This file recommends that the /2 switch be used when debugging PM
 applications. The UTILITY.DOC file is correct. You cannot use the /2
 and /O switches at the same time.


 81. CVP Prompts "SYS0197 OS/2 Not Configured..." Error Message

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  9-NOV-1988    ArticleIdent: Q31658

    When loading CodeView protected mode (CVP), the "SYS0197 OS/2 not
 configured to run this application" error message may appear. A
 request for help on 0197 prompts the "requires input/output privilege"
 message. You need to set IOPL=YES in CONFIG.SYS to run CVP.

    The following information is from the section titled "Microsoft(R)
 CodeView(R) Debugger" of the Microsoft C Version 5.10 UTILITY.DOC
 file, the FORTRAN Version 4.10 CVREADME.DOC file, and the Microsoft
 Macro Assembler Version 5.10 README.DOC file.

 CONFIG.SYS Setting for CVP
    To run the protected-mode CodeView debugger (CVP.EXE), you must
 have the following line in your CONFIG.SYS file:

    IOPL=YES



 82. Methods for Debugging Large Programs within the 640K DOS Limit

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-FEB-1990    ArticleIdent: Q57941
 Because of the 640K limit under DOS, it is common to run out of memory
 when trying to debug large programs with CodeView. CodeView requires
 over 200K of RAM, not including the program being debugged. In
 addition, the symbolic information added by compiling with the /Zi
 switch greatly increases the executable size of the program you are
 trying to debug.

 The following is a list of the possible ways of getting around the
 limited memory problems for debugging:

 1. Include full symbolic information only in those modules that
    contain source code that you are currently trying to debug. In
    other words, compile only those modules with the /Zi switch. For
    the other modules, compile with the /Zd option, to put only line
    number information in the object files.

 2. Use overlays to swap parts of your code in and out, even if it is
    just during the development process. You can always link without
    overlays once your application is debugged.

 3. If you have expanded memory, use it by invoking CodeView with the
    /E switch. To work properly with CodeView, you should have LIM EMS
    3.2 or (preferably) 4.0. Expanded memory is used for storing the
    symbolic information, which can be a great percentage of your .EXE
    size.

 4. Use the CVPACK utility, which is documented in the Update Section
    of the C 5.1 "Microsoft CodeView and Utilities Software Development
    Tools for MS OS/2 and MS-DOS Operating Systems Update" manual.
    CVPACK will compress the debug information in the file by removing
    duplicate references. Use the /p option to achieve maximum
    compression.

 In trying to obtain a workable solution, you can use any combination
 of the above methods. If adequate debugging is still impossible, then
 you might look into the following possibilities:

 5. Switch to the OS/2 operating system. This may be limited as far as
    how much real mode program debugging you can do, depending on how
    compatible your application is with protected mode requirements.

 6. You might look into MagicCV from Nu-Mega Technologies of New
    Hampshire. MagicCV requires a 386-based computer because it uses
    virtual-86 mode of the processor to run CodeView in extended
    memory. This method reportedly allows CodeView to use only about 8K
    of conventional DOS memory. It should be noted that Microsoft does
    not endorse MagicCV or make any claims as to its usage. The
    information is offered only as a potential option. Nu-Mega can be
    reached at (603) 888-2386.


 83. Problems with CodeView and Logitech Mouse with Older Drivers

 Product Version(s): 2.00 2.10 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-JAN-1990    ArticleIdent: Q31918

 Incompatibility problems have been reported with Logitech's mouse and
 CodeView. Some of the problems encountered are as follows:

 1. The Logitech mouse fails to function correctly with CodeView
    Version 2.20 when in 43-line mode. The characters within
    highlighted cells are incorrect until they are unhighlighted.

 2. When in either 43-line or 25-line mode, garbage characters are
    occasionally found at the DOS prompt following an exit from
    CodeView.

 The problems seem to be with Versions 3.20 and earlier of the Logitech
 mouse driver. An update of the mouse driver is available that corrects
 these problems. Logitech can be reached at (415) 795-0427. Logitech
 also has a bulletin board service, which may contain the latest driver
 and can be reached at (415) 795-0408.

 A Microsoft Mouse or 100 percent Microsoft-compatible mouse is
 required for use with CodeView. In addition, you must use Microsoft's
 mouse driver Version 6.00 or later, or a driver that exactly emulates
 these Microsoft drivers.


 84. Using the T Command to Echo CodeView Output

 Product Version(s): 2.00 2.10 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-NOV-1988    ArticleIdent: Q31919

    To generate and record a history of the source lines stepped
 through in the course of a debugging session, do the following:

    1. Start CodeView in sequential mode using the /T option.
    2. While in sequential mode, enter the Redirect Output (>) command,
 followed by a filename. If no filename is specified, then stdout will
 be assumed.
    3. If you wish to view the output as it is redirected, precede the
 redirection operator with the echo command (T).
    4. If a second redirection operator is specified, the redirection
 file is appended to rather than truncated before output.

    For more information on output redirection, refer to the "System
 Commands" section of the "Microsoft CodeView and Utilities" manual.

    The following example demonstrates this process:

 CV> T > log.dat  or T >> log.dat
 CV> t
 CV> t
 CV> t
 CV> .
 CV> .
 CV> .
 CV> q

    The lines traced will be written both to the console and to the log
 file.


 85. CHAIN Statement in Compiled BASIC Not Supported by CodeView

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | B_QuickBas B_BasicCom
 Last Modified: 16-NOV-1988    ArticleIdent: Q32265

    In Microsoft CodeView, when debugging compiled BASIC programs that
 CHAIN, you can view only the first program executed (the one given in
 the CV command line). The modules that are CHAINed-to cannot be viewed
 or stepped through, and their variables cannot be looked at, even if
 these modules are successfully executed. In fact, you cannot gain any
 information about the CHAINed modules, other than whether or not they
 execute correctly, unless you execute them separately in CodeView.
    This information applies to QuickBASIC Versions 4.00 and 4.00b,
 and the Microsoft BASIC Compiler Version 6.00 for MS-DOS and OS/2.



 86. CodeView Cannot Debug Source Code in Include Files

 Product Version(s): 1.00 1.10 1.11 2.00 2.02.02 2.10 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  9-NOV-1988    ArticleIdent: Q34922

 CodeView cannot debug source code in include files. This information
 is documented on Page 7 of the "Microsoft CodeView and Utilities"
 manual. The explanation for the restriction on include files says "You
 will not be able to use the CodeView debugger to debug source code in
 include files."

 This information means programs with include files that contain
 executable statements cannot be debugged with CodeView.

 The usual symptom of this problem is that after tracing or otherwise
 trying to execute your program, you will be viewing one of your
 include files instead of your normal source code. Repeated attempts
 to view the main or other source files will result in viewing the
 include file again.

 This is program design for the product. Microsoft's compilers do not
 generate symbolic information for code in include files. As a result,
 CodeView is confused by the discrepancies, and the subsequent behavior
 is unpredictable. Include files only can contain prototypes,
 declarations, #defines or #includes, etc.

 (Note that these items are all "nonexecutable" statements )

 Although it is valid C code, include files must not contain
 initializations or function definitions or other executable statements
 for CodeView to be able to debug your programs properly.


 87. No Symbolic Information Generated for Pascal Units

 Product Version(s): 2.10 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_pascal
 Last Modified:  8-MAR-1990    ArticleIdent: Q57943

 The Microsoft Pascal Compiler Version 4.00 does not generate symbolic
 debugging information for Pascal units. As a result, when tracing
 through a Pascal program unit, any attempt to access local variables
 by using trace/watchpoints, dumps, examines, etc. yields a "symbol
 unknown" error.

 The only workaround is to transform the program units into modules.


 88. CVP Accessing I/O Ports

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified: 14-AUG-1989    ArticleIdent: Q36885

 In the "Microsoft CodeView and Utilities Software Development Tools
 for the MS-DOS Operating System," Sections 6.6 and 10.5 discuss the
 Port Input and Port Output commands respectively. These commands
 function correctly in CV under MS-DOS. However, CVP under OS/2
 generates a protection violation when trying to access a port. The
 port input and output commands do not function in CVP Version 2.20
 under OS/2.

 Microsoft has confirmed this to be a problem in Version 2.20. We are
 researching this problem and will post new information as it becomes
 available.


 89. Using CodeView to Examine FORTRAN Arrays

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 14-AUG-1989    ArticleIdent: Q37548

 Question:

 I have allocated memory for a three-dimensional array in FORTRAN. How
 can I examine the contents of a row using CodeView?

 Response:

 You can use CodeView to display a single element of the array using
 ?arrayname(x,x,x), where "arrayname" consists of the first six
 characters of the array name and "(x,x,x)" must be a valid cell in the
 array.

 There is no way to display more than one cell of the array using this
 command. To display many cells, you must do a memory dump of the
 addresses where the array is stored. Use the examine command (X) to
 get the starting address of the array, and dump (D) to dump the
 elements.

 FORTRAN stores array elements in column-major order. Use the following
 formula to determine the address where any cell (i,j,k) is stored,
 where Max_Row is the maximum i possible and Max_Col is the maximum j
 possible:

     MemAddr = start_addr+(size of elements)*
                      (Max_Row((k-1)(Max_Col)+(j-1))+(i-1))

 "Size of elements" is the number of bytes of each element in the
 array.


 90. CodeView Unexpectedly Exits to DOS

 Product Version(s): 2.10 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-APR-1990    ArticleIdent: Q37566

 When debugging a program with CodeView, certain operations cause it to
 exit to DOS without giving any warning or error message. Some of the
 things that cause this behavior are trying to access help, setting a
 watch variable, and returning from a DOS shell.

 This problem occurs because not enough file handles are being
 allocated at boot time with "files=XX" in CONFIG.SYS. An error message
 is printed, but then over written before most people can see it.

 The solution is to make sure files are set to 20 in CONFIG.SYS.


 91. How CodeView Handles DosExitList Routines

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 12-JAN-1989    ArticleIdent: Q40270

 Question:

 CodeView does not seem to be executing my DosExitList. What should I
 do to execute the exit list?

 Response:

 If you are in your program and issue the GO command, your program
 executes to the end of your application, giving the message "Thread
 terminated normally." At this point, you can use the GO command or
 trace into your exit routine. However, if you would like to quit your
 program and go to your exit handler in the middle of executing your
 program, you have two choices.

 When you quit CodeView ("q"), your code including your DosExitList
 will not be executed. The first method to execute your DosExitList is
 the safest, but you are not able to trace through your exit routine.
 When you want to exit, type the following:

    ? myexithandler()

 This command executes the function "myexithandler", which is your
 DosExitList routine. After this command has been performed, you can
 quit CodeView ("q") because all of your cleanup has been accomplished.

 The second method, which is less reliable, is to modify the instruction
 pointer (IP) so that you can effectively jump to the end of your
 program. Before you do this, make certain that you are not in a
 subfunction. If you are not in main(), jumping to the end of the
 program causes problems with the stack. While in your main() routine,
 enter the following at the CodeView command line, where XXXX is the
 value of the IP when you are at the last curly brace at the end of
 your program:

    R IP XXXX

 This command causes a jump to the last curly brace; you can step
 through your program from there. This method allows you to step
 through your exit routine, but it is a little more risky.


 92. You Cannot Display Past Column 71 in CodeView

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40428

 Can I view my code beyond column 71 in CodeView like I can in the
 Microsoft editor?

 In CodeView Version 2.20, you cannot scroll your code to the right.
 You should either rewrite the source code or, if you used tabs in the
 source code, reduce the tab size with the # dialog command, as
 described on Page 240 of the "Microsoft CodeView and Utilities"
 manual.



 93. Display Command Returns Incorrect Result for FORTRAN Function

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified: 14-AUG-1989    ArticleIdent: Q40586

 The display command does not return correct values for the
 user-defined FORTRAN real functions in Microsoft CodeView.

 The display command calls integer functions and returns correct
 results.

 Microsoft has confirmed this to be a problem in Version 2.20. We are
 researching this problem and will post new information as it becomes
 available.

 The display command is discussed in Chapter 6 of the "Microsoft
 CodeView and Utilities" manual. The valid FORTRAN expressions for
 CodeView are discussed in the Chapter 4 of the same manual.


 94. CodeView Does Not Work with Grouped Code Segments

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | H_MASM
 Last Modified:  9-FEB-1989    ArticleIdent: Q40784

 When using MASM it is possible to associate various segments into a
 group; DGROUP is an example of this technique. Grouped data or stack
 segments do not affect CodeView, but CodeView does not recognize
 grouped code segments. The program will execute correctly under
 CodeView, but none of the CodeView functions will be available on the
 second and subsequent segments in the code group.

 The following code segment illustrates this behavior:

 codegroup  GROUP ASEG,BSEG
         assume cs:codegroup

 ASEG    SEGMENT WORD PUBLIC 'CODE'
 A:
         mov ax,1
         mov ax,1
         JMP B
 ASEG    ends

 ;   Will not be able to single step through this section
 BSEG    SEGMENT WORD PUBLIC 'CODE'
 B:      mov ax,1
         mov ax,1
         mov ax,1
         int 21h
 BSEG    ends
         end A

 Once the program executes into the BSEG segment, all CodeView
 functionality will be lost. You cannot set any breakpoints or single
 step through the BSEG segment of code. It appears that CodeView does
 not store any symbolic information for the BSEG segment. Any attempt
 to single step through this section of code will result in CodeView
 executing the BSEG segment of code until the program is completed.

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


 95. CodeView and Video Pages

 Product Version(s): 2.00 2.10 2.20 | 2.20
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified:  2-MAR-1989    ArticleIdent: Q41101

 Question:

 Is there anyway to specify which video page CodeView uses? I have an
 application that uses video page one; I am not able to use CodeView
 with it because CodeView also uses video page one.

 Response:

 CodeView does not allow you to specify which video page it will use.
 As a result, any application that uses video page one conflicts with
 CodeView and the screen becomes corrupted.

 The recommend work around in this situation is to use the two monitor
 option for CodeView. This option allows CodeView to send the
 application's output to one screen while using the first screen for
 its own output.

 Another less desirable workaround would be to avoid the use of video
 page one in programs that will be used under CodeView.



 96. Removing CodeView Information from .LIBs and .EXEs

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | SR# G890207-11424
 Last Modified:  2-MAR-1989    ArticleIdent: Q41371

 Question:

 Is there a way to remove CodeView symbols from a .LIB or .EXE file?

 Response:

 Although there is no utility that removes CodeView information from
 libraries, EXEPACK will remove CodeView information from .EXE files in
 the course of packing them. You can also remove information from an
 .EXE file by relinking it without the /CODEVIEW option.

 The only way to remove CodeView information from a library is to
 recompile the source modules and use the LIB utility to rebuild the
 library.


 97. CodeView: Debugging Presentation Manager Printer Drivers

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 28-MAR-1989    ArticleIdent: Q42780

 To debug OS/2 Presentation Manager (PM) printer drivers, you must use
 the kernel debugger. Currently, PM printer drivers fall under the same
 category as lower-level device drivers. These device drivers cannot be
 debugged using the current version of CodeView.


 98. Dump Command on Arrays in FORTRAN Gives Syntax Error

 Product Version(s): 1.10 2.20 | 2.20
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | H_FORTRAN buglist2.20 buglist2.30
 Last Modified: 21-AUG-1989    ArticleIdent: Q42942

 Microsoft CodeView Versions 2.20 and 2.30 gives a "Syntax error" when
 attempting to use the Dump command on an array of dimension greater
 than 1.

 For example, issuing the DI i(1,3) command to dump the contents of an
 array element fails.

 To work around this problem use one of the following methods:

 1. Use the "?" command, as follows:

       ? i(1,3)

 2. Enclose each dimension index within parentheses and omit the comma,
    as follows:

       DI i((1)(3))

    DI i(1(3)) and DI i((1)3) are also acceptable.

    A three dimensional example would look like the following:

       DI j(1(2)3)

    Any permutation of the parenthesis around the index is sufficient.

 Microsoft has confirmed this to be a problem in Versions 2.20 and
 2.30. We are researching this problem and will post new information as
 it becomes available.


 99. CodeView Protect: /43 Switch Doesn't Work on VGA Adapters

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.20
 Last Modified: 18-APR-1989    ArticleIdent: Q43043

 The /43 switch for CodeView, used to debug in 43 line mode, is ignored
 when a VGA video adapter is being used under OS/2. This switch works
 properly as documented in DOS, or when an EGA adapter is being used.
 The /50 switch, used to debug in 50 line mode, also works properly as
 documented.

 If you wish to use CodeView Version 2.20 in 43 line mode under OS/2,
 the MODE command can be used first to set the entire screen group into
 43 line mode. Using MODE 80,43 at the OS/2 prompt will accomplish this
 result. Starting CodeView without any switches will then cause it to
 use the current video mode.

 Microsoft has confirmed this to be a problem in CodeView Protect
 Version 2.20. This feature is under review and will be considered for
 inclusion in a future release.


 100. CV: K Command in Secondary Module Sets Breakpoints in Main

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.20
 Last Modified:  6-APR-1989    ArticleIdent: Q43170

 In some cases the K (call stack) command will cause CodeView to become
 uncertain as to where to set breakpoints.

 If an attempt to set a breakpoint is made in a module of a
 multi-module program immediately after using the K command then the
 breakpoint will be set in the module containing main() instead of in
 the current module.

 If the corresponding line in the first module is not an executable
 line then CodeView will issue the expected beep to indicate that the
 breakpoint could not be set.

 If the corresponding line is an executable line then there will be no
 indication at all that the breakpoint has been set until that module
 is again in view. At that point the breakpoint will be highlighted as
 usual. This behavior will occur in any module accessed after the one
 containing main().

 Breakpoints will be set properly after using the K command if any
 stepping is performed, the view is changed, or the Calls menu is
 accessed.

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


 101. Vertical Scroll Inactive with MODE CO40 and Dual Monitors

 Product Version(s): 2.x
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C buglist2.20
 Last Modified: 18-APR-1989    ArticleIdent: Q43260

 While debugging a program using Microsoft CodeView and dual monitors,
 the vertical scroll bar is disabled when the video mode is set to
 40-line color text. This occurs if the mode is set either at the
 command line

    MODE CO40

 or from within a program as follows:

    _setvideomode(_TEXTC40);

 The scroll bar remains inactive until the mode is changed. This
 problem does not occur on a single monitor system or in any other
 video modes.

 Microsoft has confirmed this to be a problem in Version 2.20. We are
 researching the problem and will post new information as it becomes
 available.

 The following program demonstrates the problem:

 #include <graph.h>

 void main (void)
 {
   _setvideomode(_TEXTC40);
   _setvideomode(DEFAULTMODE);
 }



 102. Selecting Text for Use with Commands

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | docerr insert
 Last Modified:  9-APR-1990    ArticleIdent: Q59408

 In CodeView Versions 2.20 and 2.30, you supposedly can press the left
 mouse button to highlight the command to be copied, and then press the
 INS key to copy the command. However, this method works only with the
 mouse and not with the keyboard.

 On Page 64 of the "Microsoft FORTRAN CodeView and Utilities User's
 Guide" Version 5.0 manual, it incorrectly states that you can copy any
 text that appears in any window. This is incorrect because you can
 only copy text in the command window.


 103. CodeView: View Command Fails with Underscore in Filenames

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.20
 Last Modified:  3-MAY-1989    ArticleIdent: Q43508

 Assume that two source files, MAINPROG.C and FILE_NAM.C, have been
 compiled with CodeView information. The main function in MAINPROG.C
 calls a function in FILE_NAM.C.

 When the following command is executed in CodeView, CodeView responds
 with "syntax error":

    V.FILE_NAM.C

 When FILE_NAM.C is renamed and recompiled as FILENAM.C, the following
 command works properly, and the source code in FILENAM.C is displayed:

    V.FILENAM.C

 Attempts to open a file with an underscore character will work
 correctly through the "Open" menu in CodeView, but will fail with the
 View command.

 Microsoft has confirmed this to be a problem in Version 2.20. We are
 researching this problem and will post new information as it becomes
 available.


 104. Cannot Set Breakpoint on an Executable Line with CodeView 3.00

 Product Version(s): 3.00   | 3.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 19-APR-1990    ArticleIdent: Q60338

 If you cannot set a breakpoint on a particular line of code, make sure
 you have used the -Zi and -Od options to create executable code that
 has full CodeView debugging capabilities.

 Some code in the executable is concatenated if the -Od option is not
 used.

 Sample Code
 -----------

 #include <stdio.h>

 int foo();

 void main (void)
 {
    int a,b,c;

    a = foo();/* this line would be concatenated into the next */
    b = a + c;/* line to look like b=(a=foo())+c.              */
 }

 int foo()
 {
    return(10);
 }


 105. Commands Invoked with "?" Command Must Be Compiled with /Zi

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  3-MAY-1989    ArticleIdent: Q43556

 Invoking C functions in CodeView using the "?" command works as
 expected as long as the function is contained in a module that was
 compiled with /Zi for the CodeView information. However, if you invoke
 a run-time library function, CodeView returns the error message
 "syntax error."

 The reason for the error message is that the module containing the
 library function is not compiled with the CodeView option /Zi. The
 error message is not dependent on the fact that the function is in the
 library rather than being user-defined. If a user-defined function is
 contained in a module that is compiled without /Zi for the CodeView
 information and you try to invoke it with the "?" command, CodeView
 will return the same error message.

 The "?" command is formally referred to in the CodeView Utilities
 menu as the Display Expression command.


 106. CodeView May Single Step onto a Comment Line

 Product Version(s): 2.20   | 2.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist2.20
 Last Modified:  2-JUN-1989    ArticleIdent: Q43601

 When using CodeView to single step the following program, the current
 execution line will be put on the first comment line. CodeView should
 always skip over the comment line.

 The program is compiled as required for running in CodeView. The
 compiling command used could be the following:

    cl /Zi /Od test.c

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

 This problem has no effect on the application program's performance.

 The following is the program:

 /*   test.c   */
 #include <stdio.h>
 int i = 1 ;
 void main (void)
 {
 if ( i )
      i = 0 ;
      /* first comment line */
 else
      /* more comment */
      i = 1 ;
 }


 107. Returning Control to CodeView

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | CONTROL-C CONTROL+C CONTROL+BREAK CONTROL-BREAK ^C ^BREAK
 Last Modified:  3-MAY-1989    ArticleIdent: Q43648

 The following are two software methods of returning control to
 CodeView during program execution:

 1. Use the debug interrupt, interrupt 03, in your code. Interrupt 03
    is called a microprocessor (or logical) interrupt. It is the
    interrupt that CodeView uses to make breakpoints. Hard code
    interrupt 03 into your code in selected places where you want to
    return control to CodeView. The following sample program will
    demonstrate the technique. Note that a macro could easily be
    constructed to insert breakpoints where desired.

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

         void main()
         {
             union REGS    inregs;
             int           i = 1;

             for( ;; )
             {
                 printf( "Loop iteration: %d\n", i++ );
                 int86( 0x03, &inregs, &inregs );
             }

 2. Use CTRL+C and CTRL+BREAK to return control to CodeView. This is
    a useful method for breaking out of a program is currently running
    or that has locked up.  The position in the source code to which
    you are returned depends on when you hit the ^C and what caused
    the system to hang, e.g. an infinite loop, a bad pointer, etc.
    Execution may be continued from this point in the usual manner
    (F5, F8, F10, etc.).

    Under OS/2 CTRL+BREAK does not return control to CodeView. CTRL+C
    may be used to abort a normally executing program but you cannot
    continue to debug from that point as you can in DOS.

 There is no hardware interrupt that will return control to CodeView.


 108. Cannot Open Source File Under CVP

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30 buglist2.4.1
 Last Modified: 18-SEP-1989    ArticleIdent: Q45135

 Problem:

 When using CodeView Protect (CVP) Version 2.20, I trace my program
 through a number of source files and after some number of files CVP is
 no longer able to open source files. When CVP gets into this
 situation, it automatically goes into mixed mode -- displaying line
 numbers but no source text. In this state, trying to use the "v"
 command to look at another (not previously looked at) file results in
 a red message box telling me that CVP can't open the file.

 Response:

 This is a problem with CVP Version 2.20 and 2.30. CVP is running into a
 file limit. To work around this problem, before you step out of the first
 module, open the source file containing the code you wish to debug and
 set a breakpoint there. Now "go" to this location by pressing the F5
 key. This procedure allows you to start debugging at a location deep
 into the file without opening multiple source files.

 Microsoft has confirmed this to be a problem with CodeView versions
 2.20 and 2.30. We are researching this problem and will post new
 information as it becomes available.


 109. Incorrect Handling of SP Can Cause CodeView to Corrupt Stack

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified:  7-JUN-1989    ArticleIdent: Q45183

 CodeView will use your program's stack for temporary variables in
 between assembly instructions. Thus, when writing an assembly language
 program, if you forget to increase the stack pointer (SP) to point
 beyond the memory locations you are using on the stack, CodeView will
 overwrite that memory.

 This is expected behavior. Even if CodeView did not use the stack, you
 would still have to increment the stack pointer to keep your program
 from overwriting your variables when you make a call, or with any
 operation that pushes values on the stack.


 110. Switching Out of PM Application Hangs System under Codeview

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q44418

 Question:

 I am using CodeView to debug my Presentation Manager (PM) application.
 Why does my machine sometimes hang when I use CTRL+ESC to switch to
 the OS/2 program selector?

 Response:

 Presentation Manager applications require the use of the Presentation
 Manager shell. To debug PM applications, CodeView must put hooks into
 the Presentation Manager before the PM application is executed. This
 process works properly while inside CodeView, but if you try to switch
 back to the program selector, PM is in an unknown execution state.

 Therefore, to switch out of CodeView while debugging a PM application,
 you must first restart or end the program inside CodeView. This tells
 CodeView to restore the Presentation Manager to its original
 condition.


 111. SYS0317 Caused by Running CVP on a DOS Application

 Product Version(s): 2.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 31-MAY-1989    ArticleIdent: Q44707

 The following message results from running a DOS application under
 Microsoft CodeView Version 2.20 or 2.30 for protected mode:

    SYS0317: The system cannot find message 0491
    in message file OSO001.MSG

 The screen is then cleared and the OS/2 prompt returns.


 112. /43 Starts CodeView with Screen Swapping Enabled

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified:  7-JUN-1989    ArticleIdent: Q45185

 When CodeView is started with the /43 switch to bring it up in 43-line
 mode, screen swapping is automatically enabled. This behavior is by
 design, although it is not stated in the documentation for the
 product.


 113. Setting a Breakpoint Highlights More Than One Line

 Product Version(s): 2.20
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.20
 Last Modified:  7-JUN-1989    ArticleIdent: Q45241

 When setting a breakpoint, CodeView may highlight two or more lines of
 code when you do the following:

 1. Compile C program (e.g., "Hello, world") with /Zi /Od.

 2. Load CodeView with 50 line mode (in VGA mode) as follows:

       cv /50 hello.c).

 3. Display mixed source and assembly.

 4. Move the cursor to the edit window and scroll down two or three
    pages of start-up assembly code.

 5. Set and remove breakpoints at arbitrary locations. In some cases,
    multiple lines will be highlighted and the display altered. The
    code itself is not changed. To restore the altered display, page
    down and then page up to the altered location.

 CVP does display this problem.

 Microsoft has confirmed this to be a problem in CodeView Version 2.20.
 We are researching this problem and will post more new as it becomes
 available.

 After setting a breakpoint that highlights more than one line of code,
 using the BL command will list only the one breakpoint you set.


 114. "No Symbolic Information" May Be Caused by Using Wrong Linker

 Product Version(s): 1.00 1.10 2.00 2.10 2.20 2.30 2.35 | 2.20 2.30 2.35
 Operating System:   MS-DOS                             | OS/2
 Flags: ENDUSER | S_LINK
 Last Modified: 19-SEP-1990    ArticleIdent: Q59540

 To debug programs at the source level with CodeView, it is critical
 that a proper version of LINK be used. Particular versions of CodeView
 are matched to particular versions of LINK and using a version of LINK
 newer than the versions matched to a particular version of CodeView
 will prevent CodeView from recognizing the symbolic information in the
 .EXE file.

 This mismatch will cause CodeView to come up in assembly mode and
 produce the message "No Symbolic Information," even though the source
 files may have been compiled and linked with the correct options for
 CodeView symbolic debugging.

 The difference between the linkers is in the way they store symbolic
 information in .EXE files. A newer version of CodeView generally can
 always display symbolic information for programs produced with
 previous versions of LINK, but the opposite is NOT true. Using a more
 recent linker with an older version of CodeView is where potential
 problems arise.

 The following information applies to both real-mode CodeView (CV) and
 protected-mode CodeView (CVP).

 Versions of CodeView prior to Version 3.00 cannot display symbolic
 information for .EXE files produced with LINK 5.10. In other words,
 if LINK 5.10 (supplied with C 6.00) is used for linking, then
 CodeView 3.00 is the ONLY matched version of CodeView that can
 display the program's symbolic information.

 CodeView Version 2.35 is matched to LINK 5.05 (both were released with
 BASIC 7.00). Therefore, CodeView 2.35 is the ONLY version of CodeView
 that can display symbolic information for a program linked with LINK
 5.05.

 For CodeView Versions 2.00, 2.10, 2.20, and 2.30, any linker with a
 version number from 3.60 to 5.03 is acceptable.

 For CodeView Versions 1.00 and 1.10, LINK versions later than or equal
 to 3.51, but earlier than 3.60, must be used.


 115. Mouse Disabled When Single-Stepping over Video Mode Change

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.20 buglist2.30
 Last Modified: 21-JUN-1989    ArticleIdent: Q45617

 When CodeView is run in the OS/2 compatibility box with screen
 swapping enabled (started with either /s or /43), single-stepping (F8)
 over a _setvideomode() call or an INT 10 call to change the video mode
 to a graphics mode causes the mouse cursor to disappear. Exiting
 CodeView and running another mouse-driven program reveals that the
 mouse has been completely disabled in the compatibility box. The only
 way to regain the mouse is to reboot the computer. Attempting to
 reload the mouse by typing "mouse" at a prompt results in the
 following message:

    Session Title: DOS Command Prompt

 This error occurs because a DOS mode program changes an interrupt
 vector that is owned by the system causing the program to end.

 The behavior described above applies to tracing in SOURCE mode.
 Attempting to trace in assembly language or mixed mode through the
 code that changes the video mode produces erratic results, which range
 from hanging the DOS box to halting the entire system with an
 "internal processing error."

 Microsoft has confirmed this to be a problem in CodeView Versions 2.20
 and 2.30. We are researching this problem and will post new information
 as it becomes available.

 The following program illustrates the problem:

 #include <graph.h>

 void main(void)
 {
   _setvideomode(_ERESCOLOR);    /* when this line is executed, the  */
                                 /* mouse cursor will disappear.     */
   _setvideomode(_DEFAULTMODE);

 }


 116. CodeView "??" Command Can't Show All of Large Structures

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | SR# G890607-19918
 Last Modified:  8-AUG-1989    ArticleIdent: Q45624

 Question:

 How can I view structures with many members in CodeView with the "??"
 command? It shows only those members that fit on the screen. Is there
 some trick I haven't found?

 Response:

 Unfortunately, the "??" command is limited in this respect -- there is
 no way to view the last members of a large structure with this
 command. This feature is under review and will be considered for
 inclusion in a future release.

 Instead, however, you can view each element of the structure by itself
 by dereferencing the struct and element, i.e., "?structname.field".

 There are at least two ways to work around the problem in CodeView
 Versions 2.20 and 2.30. One way is to shrink or nest the structures.
 Another workaround is to use the "?" or Watch command to look at the
 individual member(s) you want to see.


 117. Problem Debugging StartSession from a Child Process

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER | buglist2.30
 Last Modified:  9-AUG-1989    ArticleIdent: Q45707

 When a program spawns another program that starts a new session,
 CodeView has difficulty stepping into that new session. This process
 is shown graphically in the following diagram:

        --------------        -------------------
    A --| DosExecPgm |--> B --| DosStartSession |--> C
        --------------        -------------------

 The following describes how to duplicate this process and re-create
 the problem:

 1. Invoke CodeView on Program A with offspring debugging enabled, as
    follows:

       CVP /O A

 2. Program A calls DosExecPgm to spawn Program B. Trace into Program B
    by pressing F8 on the DosExecPgm function. You will be informed
    that a new process has begun and you will be asked if you wish to
    debug it. Answer yes and switch to the newly created CodeView
    session.

 3. Program B calls DosStartSession to begin a new session. The program
    that will execute in that session is Program C. Attempt to trace
    into the new session by pressing F8 on the DosStartSession function.

 The problem is demonstrated in Step 3. CodeView does not give you the
 opportunity to debug Program C as it should. Further, when Program B
 has completed execution and CodeView returns back to Program A, the
 first single step will inform you that a new process has been started.
 This message should have been presented on the call to
 DosStartSession.

 CodeView has no difficulty stepping into a new session when the
 initial program being debugged is Program B. To work around this
 problem, invoke CodeView on Program B with the /O switch.

 Microsoft has confirmed this to be a problem with CodeView Version
 2.30. We are researching this problem and will post new information
 as it becomes available.

 The following three modules demonstrate this problem:

 //***********************************************************
 // A.C - spawn a child from here.

 #define INCL_BASE
 #include <os2.h>

 void main (void)
 {
   char        failbuf[80];
   RESULTCODES ExecCode;

   DosExecPgm (failbuf, 40, EXEC_ASYNC, NULL, NULL, &ExecCode, "B.EXE");
   VioWrtTTY ("End of A.\r\n", 11, 0);
 }

 //***********************************************************
 // B.C - start a new session from here.

 #define INCL_BASE
 #include <os2.h>
 #include <string.h>

 void main (void)
 {
   USHORT    Disk;
   ULONG     Drives;
   BYTE      SessionProg [80];
   USHORT    MaxLen = sizeof(SessionProg)-14;
   STARTDATA StartData;
   USHORT    Session;
   USHORT    Process;

   // Build program name to run in new session.
   DosQCurDisk (&Disk, &Drives);
   strcpy (SessionProg, "*:\\");
   SessionProg[0] = (char) ('A' + Disk - 1);
   DosQCurDir (0, SessionProg + strlen(SessionProg), &MaxLen);
   strcat (SessionProg, "\\C.EXE");

   StartData.Length      = sizeof(STARTDATA);
   StartData.Related     = 1;
   StartData.FgBg        = 0;
   StartData.TraceOpt    = 0;
   StartData.PgmTitle    = "Test Session";
   StartData.PgmName     = SessionProg;
   StartData.PgmInputs   = "sample param";
   StartData.TermQ       = NULL;
   StartData.Environment = NULL;
   StartData.InheritOpt  = 0;
   StartData.SessionType = 1;
   StartData.IconFile    = NULL;
   StartData.PgmHandle   = 0;

   DosStartSession (&StartData, &Session, &Process);
   VioWrtTTY ("End of B.\r\n", 11, 0);
 }

 //***********************************************************
 // C.C - the test session.

 #define INCL_VIO
 #include <os2.h>

 void main (void)
 {
   VioWrtTTY ("In test session", 15, 0);
 }


 118. CodeView Skips Over a Line of Source Code

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_QuickC
 Last Modified: 14-AUG-1989    ArticleIdent: Q46010

 After setting a breakpoint on the indicated line in the program below
 and executing the program, CodeView executes that line without
 stopping. Likewise, if you single step through the code, CodeView
 steps past that line. This problem also occurs in the QuickC
 integrated debugger.

 The workaround is to flip your source into mixed mode and set the
 breakpoint on the correct assembly line.

 This is due to the fact that CodeView is line-based and the C compiler
 is token-based. This will not be corrected; it is a restriction.

 Sample Program
 --------------

 int i, j, k, l;

 void main(void)
 {
     for(i = 0; i < 20; i++)
     {
         j = 0;
         for(k = 0; k < 20; k++)
             if(j == 0)
                 break;

         j = 1; /*** set breakpoint here ***/
     }

     l = 0;
 }


 119. Capabilities and Limits of the /R switch on 80386 Machines

 Product Version(s): 2.20 2.30 2.35 3.00 | 2.20 2.30 2.35 3.00
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | 386
 Last Modified: 12-APR-1990    ArticleIdent: Q46448

 The /R command line switch for CodeView beginning with Version 2.20 is
 used only on 80386 machines. The /R switch tells CodeView to use the
 four debug registers available on the 80386 chip, and also allows
 hardware breakpoints. This causes CodeView to run faster when
 performing debugger-intensive steps such as monitoring a tracepoint.

 The /R switch works under DOS and OS/2's DOS compatibility box. It is
 an unrecognized switch under OS/2. The /R switch speeds operation of
 Tracepoint but not Watchpoint or Breakpoint commands.

 Note: because there are only four debug registers, only four
 tracepoints (of up to 4 bytes each) may be specified when utilizing
 these registers. Specifying any combination of tracepoints greater
 than 16 bytes will require CodeView to use software tracepoints rather
 than the debug registers and all performance gains will be lost.


 120. Using CodeView /2 with Hercules Graphics Cards and Libraries

 Product Version(s): 2.20 2.30
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-OCT-1990    ArticleIdent: Q46949

 Using CodeView in the dual-monitor mode with a Hercules graphics card
 as the primary (application) monitor requires the Hercules card to be
 configured in the half mode. Using the Hercules graphics library, the
 monitor must be configured using the config(0) function call. This
 function call is a part of the Hercules graphics library and does not
 use Microsoft graphics library or the MSHERC.COM program. Therefore,
 this information applies only if you are using the Hercules graphics
 libraries. This is NOT the same as using the /h switch with CodeView.

 The first page of the Hercules graphics display card is mapped to
 memory location B0000 (same as MDA), and the second page is mapped to
 B8000. The CGA/EGA/VGA also use B8000 as the beginning of their video
 memory. CodeView uses these two different address to run in the
 dual-monitor mode, sending the application output to the primary
 address, usually located at B8000, and the CodeView information to the
 secondary monitor, usually located at B0000.

 This works well until a Hercules graphics card is used as the primary
 monitor (in graphics mode) and the CGA/EGA/VGA card is used as the
 secondary monitor. The Hercules graphics card uses both pages (one at
 B0000 and the other at B8000) in the full mode. Therefore, use
 config(0) and only the first page (B0000) will be used and CodeView
 will function properly in dual-monitor mode.


 121. DEF File Entry of EXECUTEONLY Causes Problems with CVP

 Product Version(s): 2.20 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1989    ArticleIdent: Q47103

 Question:

 When I step into my DLL, I can see and step through the source code
 correctly. I also can look at local variables. However, I cannot set
 breakpoints in the DLL. Also, when I try to look at the disassembled
 code I see the following:

    ??? No Code ???

 I am using the correct Compile and Link options. Why is CodeView
 acting strangely?

 Response:

 In the .DEF file for the DLL, you had the EXECUTEONLY attribute as
 opposed to the default EXECUTEREAD. When you choose EXECUTEONLY,
 CodeView cannot read the code segment as it must to work correctly.
 Removing the EXECUTEONLY attribute corrects the problem.


 122. OS/2 SDK Version of CVP 2.30 Won't Debug DosLoadModule DLLs

 Product Version(s): 2.30
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q59610

 The OS/2 version 1.10 Software Development Kit (SDK) includes a
 prerelease version of protected-mode CodeView (CVP) version 2.30. This
 version is identical to the regular retail release of CVP 2.30, except
 that it does not allow the debugging of DLLs loaded with
 DosLoadModule. The regular retail version of CVP 2.30 is included with
 FORTRAN 5.00 and the OS/2 Presentation Manager Toolkit for OS/2
 version 1.10. This release DOES support debugging DLLs loaded at run
 time with DosLoadModule.

 The prerelease version of CVP 2.30 released in the OS/2 SDK may be
 identified by a file date of 2-24-89. The regular release version is
 dated 3-21-89. The file date is the only discernible difference
 between these two versions since the files themselves are exactly the
 same size.


 123. Minimum Extended Memory (384K) Causes CV 3.00 to Use Extra RAM

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr HIMEM
 Last Modified: 27-SEP-1990    ArticleIdent: Q59890

 Real-mode CodeView (CV) Version 3.00 is documented as being able to
 run in extended memory as long as there is at least 384K of extended
 memory available. This 384K minimum is accurate as far as CV being
 able to utilize the extended memory, but it is not enough for CodeView
 to remove all of itself from conventional RAM. In fact, a system
 configuration with only 384K extended memory will result in LESS
 memory being available for the debuggee (the program being debugged)
 than if no extended memory is utilized at all.

 The CodeView 3.00 documentation states that "if HIMEM.SYS or another
 extended-memory driver is installed, all but 16K of CodeView, plus all
 of the symbolic information for the program you are debugging, are
 placed in extended memory." But, for CodeView to truly work with this
 16K "footprint" in conventional memory, a minimum of approximately
 600K extended memory must be available.

 When no extended memory is available, CodeView normally utilizes
 overlays to keep as much of itself out of memory as possible, so that
 the debuggee can have more space to load. (The new /Dnnn option
 actually allows you to specify the size of the overlays -- a bigger
 overlays means CV runs faster, but a smaller overlays mean a bigger
 program can be loaded for debugging.)

 Once CodeView detects extended memory, it assumes that overlays are no
 longer needed, since CV itself and the debuggee's symbolic information
 will both (supposedly) be loaded into extended memory. However, the
 result may be that CodeView seems to get bigger because what Codeview
 can't fit into extended memory is loaded into conventional memory.

 Since no overlays are used, this can result in a much larger
 footprint. For instance, if the minimum of 384K extended memory is all
 that is available, then the footprint will be well over 200K.
 Obviously, as the amount of extended memory is increased from 384K,
 the footprint will shrink accordingly.

 The /X command-line option instructs CodeView to use extended memory.
 However, CV will automatically detect extended memory and use it if it
 is available. Consequently, if the /X option is not specified, CodeView
 will still use extended memory.

 Thus, if you have a limited amount of extended memory and decide to
 run CodeView in conventional RAM only, you have two options. You can
 explicitly specify /D (for example, /D16) to tell CodeView to use
 overlays, or you can remove (or comment out) the line in your
 CONFIG.SYS file that loads the extended memory driver (HIMEM.SYS) and
 reboot.


 124. If COMSPEC Is Invalid, Invoking DOS Shell May Hang Machine

 Product Version(s): 2.x 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_pwb s_quickasm s_editor
 Last Modified: 19-APR-1990    ArticleIdent: Q60748

 If you set your COMSPEC environment variable to point to an invalid
 command interpreter, and then shell out of any DOS application, your
 machine will hang. This problem occurs because the file that COMSPEC
 points to is assumed to be a valid command interpreter and cannot be
 checked for validity.

 This is expected behavior. Because .COM files have no standard file
 header structure, they cannot be checked for validity. Therefore, DOS
 must assume that whatever the COMSPEC environment variable points to
 must be a valid command interpreter, and can do no further error
 checking.

 This behavior can easily be demonstrated in any program that allows
 you to access a DOS shell, including CodeView, Programmer's WorkBench
 (PWB), the Microsoft Editor (M), and the Quick environments. Type the
 following line at the DOS prompt:

    set comspec=a:\foo.c ; Invalid command.com file

 Then enter a DOS application and shell out. Your machine will hang,
 and you may receive strange error messages.

 If you are running under OS/2, you will be warned about an invalid
 command interpreter when you attempt to shell to the operating system.
 Under OS/2, the system expects an .EXE file to be the command
 interpreter, and .EXE files have a standard, recognizable structure
 that can be checked.


 125. /I Documented Incorrectly in "Advanced Programming Techniques"

 Product Version(s): 3.00   | 3.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 19-APR-1990    ArticleIdent: Q60829

 In Section 9.7, "Controlling CodeView with Command-Line Options," on
 Page 204 of the "Microsoft C Advanced Programming Techniques" manual,
 it incorrectly states that the /I switch (used to turn the nonmaskable
 interrupts and 8259 interrupts on or off) is followed by either a 1 or
 a 2 (either /I1 or /I2).

 The correct switch options are /I0 to trap these interrupts, or /I1 to
 ignore these interrupts. Both the online documentation and the
 "Microsoft C Reference" give this correct usage of the /I switch.


 126. OS/2 1.20 Requirements for Dual-Monitor Debugging

 Product Version(s): 2.x 3.00
 Operating System:   OS/2
 Flags: ENDUSER | PM
 Last Modified: 17-JUL-1990    ArticleIdent: Q60866

 To do dual-monitor debugging under OS/2 Version 1.20 with CodeView,
 make sure that you have the correct display DLLs specified in your
 CONFIG.SYS file.

 For example, the following three lines in your OS/2 CONFIG.SYS file
 specify the device drivers needed to use a VGA and a monochrome
 adapter:

    set video_devices=bvh_vga,bvh_mpa
    set bvh_vga=device(bvhvga)
    set bvh_mpa=device(bvhmpa)

 If you have a CGA or an EGA monitor and adapter for your primary
 (color) display, replace device(bvhvga) with device(bvhcga) or
 device(bvhega), depending on your adapter type.

 Next, make sure that both of the BVH*.DLL files (in the above case,
 BVHVGA.DLL and BVHMPA.DLL) specified in the device(name) section are
 in your LIBPATH. OS/2 setup places these files in your C:\OS2\DLL
 directory by default.

 Note: You can substitute any name for bvh_vga or bvh_mpa, as long as
 those two placeholders match up with the name tab in the set
 <name>=device... lines.

 Remember, the two monitors must be unique for OS/2 to determine which
 monitor is which. For instance, debugging with two VGA monitors will
 not work because OS/2 and, therefore, CodeView will be unable to
 determine which adapter/monitor is the primary adapter/monitor and
 which is the secondary adapter/monitor.

 This point is critical to remember when considering dual-monitor
 debugging on a microchannel machine (for example, an IBM PS/2 Model 50
 and above). Since there are currently no microchannel monochrome
 adapter cards on the market, the only alternative is to use a VGA and
 an 8514 as the two monitors. The following are the matching three
 lines for your OS/2 CONFIG.SYS file for that scenario:

    set video_devices=bvh_vga,bvh_8514
    set bvh_8514=device(bvh8514)
    set bvh_vga=device(bvhvga)

 Using this setup, the 8514 monitor displays the graphics output (or
 the Presentation Manager screen) and the VGA is the debug monitor and
 displays all text output.


 127. Debugging Large DOS Applications in CodeView 3.0 with /X /E /D

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q61473

 CodeView version 3.00 includes enhanced support for debugging
 applications under DOS. CodeView 3.00 may access extended memory or
 expanded memory, or the size of the overlay swap area that CodeView
 uses may be adjusted.

 CodeView 3.00 offers three command-line parameters (/X, /E, and /D)
 for specifying memory utilization. If you DO NOT specify the /X, /E,
 or /D options when you start a CodeView session, CodeView will
 automatically search for extended memory. If CodeView finds extended
 memory, it will place the symbolic information and most of itself into
 extended memory (as long as enough extended memory is available).

 If there is no extended memory on your system, Codeview will search
 for expanded memory. If there is expanded memory, Codeview will place
 the symbolic information for your program in expanded memory.

 If there is no extended or expanded memory on your machine, CodeView
 will load itself, your application, and symbolic information for your
 program in base memory.

 Since CodeView does this automatic scan for extended and expanded
 memory, the /X and /E switches are needed only if you explicitly want
 to specify the use of one form of memory or the other and you do not
 want to enter CodeView if this memory type is not available.

 CodeView's /X option tells the debugger to load into extended memory
 ONLY, and to return an error message if extended memory is not
 available on your system. This message has the following form:

    CV1302 Error: /X : HIMEM.SYS not loaded

 CodeView's /E option tells the debugger to access expanded memory
 ONLY, and to return an error message if there is no expanded memory on
 your machine. This message has the following form:

    CV1304 Error: /E : EMM driver not loaded

 CodeView's /D option specifies that CodeView should use disk overlays.
 When you use this option, you can also specify a decimal size in
 kilobytes between 16K and 128K to explicitly set the overlay swap area
 size. The default size of the swap area is 64K if /D is used but no
 size is explicitly specified. If extended and expanded memory are not
 available, /D will not need to be specified for the default 64K
 overlay swap area to be used.

 A larger overlay swap area allows CodeView to run faster because it
 doesn't have to swap to disk as frequently as with a smaller swap
 area, but it means more memory is used up by CodeView itself. A
 smaller swap area allows you to debug larger applications under DOS,
 but CodeView runs slower because of the more frequent need to swap
 code from disk to memory.


 128. P70 Display Creates Problems Under CodeView and PWB

 Product Version(s): 3.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist3.00 S_PWB S_Editor
 Last Modified: 15-AUG-1990    ArticleIdent: Q61557

 CodeView version 3.00 and Programmer's WorkBench (PWB) version 1.00
 have problems recognizing the built-in monitor of IBM P70 portables
 under OS/2. Symptoms of this problem include the following error
 messages:

    Product     Error Message
    -------     -------------

    CodeView    Internal Debugger Error 0 at load time
    PWB         Inability to change from 43-line mode

 Microsoft has confirmed this to be a problem with CodeView version
 3.00. We are researching this problem and will post new information
 here as it becomes available.

 This problem is directly related to the video configuration of the IBM
 P70. In its documentation, IBM mentions briefly that it might be
 necessary to type MODE CO80 to make some software recognize the
 built-in plasma display. An added condition for PWB and CodeView is
 the necessity of being in 43-line mode. PWB automatically places you
 in 43-line mode no matter what you previous mode was and thus gets
 around this limitation. If you attempts to change the height switch
 while editing, PWB doesn't complain but still stays in 43-line mode.

 CodeView cannot make the mode change in the same way that PWB can. If
 invoked without the above considerations, CodeView will crash with an
 Internal Debugger Error 0. The following are several ways to work
 around this problem if want to use CodeView with this type of
 configuration.

 1. Type MODE CO80 or BW80 and invoke CodeView with the /43 switch.

 2. Type MODE CO80,43 or BW80,43 before invoking CodeView.

 3. Use an external monitor with the built-in VGA port.

 4. Invoke CodeView from PWB, which makes the change automatically.


 129. CodeView Does Not Reset Initial Graphics Mode on Exit

 Product Version(s): 2.x 3.00    | 2.x 3.00
 Operating System:   MS-DOS      | OS/2
 Flags: ENDUSER |
 Last Modified: 29-MAY-1990    ArticleIdent: Q61611

 When CodeView exits, it leaves the screen in the current video mode
 and does not reset the mode to the mode that was active when CodeView
 was initially loaded.

 This behavior is by design. However, if you start CodeView with the /s
 option to enable screen swapping, the video mode that was active when
 CodeView was loaded will be reset because CodeView has separate
 swappable video memory pages to hold the output screen as well as the
 CodeView screen.


 130. CV 3.00 Gives R6000, Hangs When Accessing Help During Start-Up

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist3.00 fixlist3.10
 Last Modified:  5-FEB-1991    ArticleIdent: Q61919

 Accessing help in the "Enter directory for filename.c (cr for none)?"
 window results in the following error in CodeView version 3.00:

    run-time error R6000
    -stack overflow

 Then, the machine hangs requiring a cold reboot.

 To reproduce the error, do the following:

 1. Compile and link a program with symbolic information for CodeView.

 2. Delete or rename the source file and then go into CodeView. A
    window will appear asking you to "Enter directory for filename.c
    (cr for none)?".

 3. Choose the Help option at the bottom of the window. The run-time
    error message will be printed over the CodeView screen and the machine
    will be hung.

 The problem does not occur under OS/2.

 Microsoft has confirmed this to be a problem in CodeView version 3.00.
 This problem was corrected in CodeView version 3.10.


 131. CodeView 3.00 Fades with Monochrome VGA

 Product Version(s): 3.00   | 3.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 11-JUL-1990    ArticleIdent: Q61970

 If you invoke CodeView version 3.00 on certain machines with
 monochrome VGA monitors and then trace through several lines of code,
 the screen will fade and become unreadable. Exiting and re-entering
 CodeView refreshes the screen, but the screen immediately starts to
 fade again.

 This problem is caused by an error in the video ROM BIOS and has been
 verified to occur on the following machines:

 l. PS/2 Model P70 with monochrome VGA

 2. Siemens with Video 7 monochrome VGA

 3. Northgate 386 with Video 16 monochrome VGA

 The following are different methods of working around this problem:

 1. Switch into color mode using the mode CO80 command (may not have
    any effect).

 2. From the options menu inside Codeview, turn flip/swap off using
    the screen-swap option.

    If you don't want to give up flip/swap functionality, try option 3.

 3. If the video BIOS is replaceable, replace it with an updated video
    BIOS.

 4. If the video BIOS is not replaceable, replace the card.


 132. CodeView 3.00 Hangs on gets() with Screen Swap Off

 Product Version(s): 3.00   | 3.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_c s_quickc s_quickasm
 Last Modified: 25-JUL-1990    ArticleIdent: Q62663

 CodeView 3.00 will hang if you step or execute past a call to the
 gets() run-time routine if the Screen Swap option is turned off.

 Sample Code
 -----------

 #include <stdio.h>

 char string[256];

 void main (void)
 {
     printf ( "Enter a string: ") ;
     gets ( string ) ;
     printf ( "Echoing : %s\n", string) ;
 }

 Compile the above file with the following:

    cl /Od /Zi test.c

 Bring the file up in CodeView, then select the Options.Screen Swap
 option. Next, step past the gets() call. Under DOS, your machine will
 hang, and under OS/2, the current screen group will be hung.


 133. DosSetMaxFH Between 0-39 Fails Under CodeView 3.00

 Product Version(s): 3.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist3.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q62666

 OS/2's DosSetMaxFH routine can be called to reset the OS/2 default
 limit of a maximum of 20 open file handles to a larger number. By
 definition, DosSetMaxFH fails when trying to set the number smaller
 than the current maximum amount of handles. Under OS/2, the default
 maximum number of files is 20, so a DosSetMaxFH to a number between
 0-19 should fail.

 However, under CodeView 3.00, calling DosSetMaxFH with a number
 between 0-39 will return a fail value.

 Sample Code
 -----------

 /* compile with : cl /Od /Zi file.c */

 #define INCL_DOSFILEMGR

 #include <stdio.h>
 #include <os2.h>

 void main(void)
 {
    int i;
    for ( i = 0 ; i < 1000 ; i ++ )

    if ( DosSetMaxFH ( i ) )
    {
       printf ( " DosSetMaxFH to %d failed!\n ",i ) ;
    }
 }

 This program prints the error message on parameters from 0 to 39.

 You can call the DosSetMaxFH routine to set at least 40 file handles
 to work around this problem.


 134. CV Limits Input of Period Character (2Eh) into Memory Window

 Product Version(s): 3.00 3.10 | 3.00 3.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist3.00 buglist3.10 decimal point dot
 Last Modified: 31-AUG-1990    ArticleIdent: Q65241

 When viewing memory in byte format in a memory window in CodeView
 version 3.00 or 3.10, you cannot change the value of a byte in memory
 to the hexadecimal value 2E. The hex value 2E has an ASCII character
 equivalent of the period ("."). In CodeView, a period is used to
 display any nondisplayable character (for example, null, a carriage
 return, control characters, etc.), which means the period character
 can sometimes have special meaning to CodeView when it appears in a
 memory window.

 Because of the special usage of the period character in a memory
 window, CodeView does not allow periods to be typed directly into
 memory. In CodeView 3.00, attempts to change a byte value to 2E
 results in either the 2 or the E being entered and the other digit
 being ignored, depending on which value you enter first. In CodeView
 3.10, both the 2 and the E are returned to their original values once
 they have both been entered. If you move to the right side of the
 memory window where the ASCII equivalents are shown and you try to
 type in a period there, CodeView will also ignore that input.

 If you switch the memory window so that you are viewing memory in
 ASCII mode, actual periods can be typed in to any memory location.
 However, there is a problem with this because ALL other periods on the
 same line, which really represent various nondisplayable ASCII
 characters, are all converted to 2Es.

 If you use are viewing memory in a format other than bytes or ASCII,
 CodeView will allow a 2E to be entered. The workaround, then, if a
 period needs to be entered into memory, is to choose a different
 viewing mode other than ASCII or byte-mode, and then enter the period
 in the desired location as the value 2E. You can cycle through the
 available memory viewing modes by repeatedly pressing SHIFT+F3, or you
 can select the desired mode from the Memory Window option on the
 Options menu.

 Microsoft has confirmed this to be a problem in CodeView versions 3.00
 and 3.10. We are researching this problem and will post new
 information here as it becomes available.


 135. CV 3.00 Incorrectly Documents helpbuffer Switch as helpbuffers

 Product Version(s): 3.00   | 3.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-FEB-1991    ArticleIdent: Q63236

 In the "Configure CodeView" section of the online help for CodeView
 version 3.00, the "helpbuffer" switch is incorrectly listed as
 follows:

    helpbuffers:<size>

 This switch should be spelled as follows:

    helpbuffer:<size>

 CodeView will not recognize the first spelling. The correct spelling
 was incorporated into the online help beginning with CodeView version
 3.10.


 136. CodeView Crashes in DOS on "Drive Not Ready" Error

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist3.00
 Last Modified: 25-JUL-1990    ArticleIdent: Q64026

 CodeView version 3.00 may hang after encountering a "Drive Not Ready"
 error. This error may occur if a file is opened on Drive A and a disk
 is not in the drive.

 To reproduce this problem, compile the following program with CodeView
 options (cl /Zi /Od):

    main () {
      FILE *fp;
      fp = fopen("a:\readme.doc","r");
    }

 If you run the program in CodeView version 3.00 without a disk in
 Drive A and press F5 to run the program, the following error will
 appear:

    Not ready reading drive A
    Abort, Retry, Fail?

 Regardless of what is typed, the machine will hang and you must do a
 cold reboot to remedy the crash.

 Note: CodeView versions 2.20 and 2.30 do not hang the machine if the
 above steps are executed. The fopen() just returns a NULL. OS/2 also
 handles the error correctly in versions 2.20, 2.30, and 3.00 of
 CodeView.

 Microsoft has confirmed this to be a problem with CodeView version
 3.00. We are researching this problem and will post new information
 here as it becomes available.


 137. CV1319 Error May Be Caused by CodeView DOS Extender

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist3.00 fixlist3.10
 Last Modified: 31-AUG-1990    ArticleIdent: Q65242

 Real-mode CodeView (CV) version 3.00 (shipped with Microsoft C 6.00)
 may encounter problems on certain computers when extended memory is
 utilized for debugging programs. These problems involve the processing
 of interrupts while CodeView 3.00's internal DOS extender is being
 used to run CodeView in protected mode in conjunction with HIMEM.SYS,
 the extended memory (XMS) driver.

 The problems manifest themselves in various ways, due to both the
 varied interrupt handling speeds of different machines and the varied
 interactions of CodeView itself running in protected mode while the
 DOS program being debugged is still being run in real mode. The most
 common error is a protection violation, which shows up in CodeView as
 either a CV1319 error (internal error - unrecoverable fault) or as a
 system hang. The errors usually occur when you are paging through the
 code or manipulating the mouse.

 Registered Microsoft C 6.00 owners who are experiencing any of these
 problems with CodeView version 3.00 are encouraged to call Microsoft
 Technical Support at (206) 637-7096 to obtain information concerning a
 possible correction for these errors. However, there may be some cases
 where the only solution is to obtain a newer computer BIOS or to use
 CodeView without extended memory.
 Most reported problems have involved IBM PS/2 computers, but a number
 of these problems have also been reported on computers with an AMI
 BIOS. Note that CodeView version 3.10 includes modifications that are
 expected to eliminate most of these interrupt problems, but in some
 instances (especially with older AMI BIOS machines), an update of the
 BIOS may be the only solution.

 The easiest workaround to these protected-mode errors is to start
 CodeView without the use of extended memory. This can be done by
 removing the line in CONFIG.SYS that loads the HIMEM.SYS driver (and
 then rebooting the computer). Another option, if HIMEM is already
 loaded, is to start CodeView with the /D command-line option to
 specify explicitly that CodeView should use disk overlays, rather than
 extended or expanded memory. (Otherwise, if extended memory is
 available, CodeView will use the /X option by default.)

 Because these problems can occur only when CodeView is running in
 protected mode in extended memory, and because CodeView 3.00 requires
 HIMEM.SYS in order to run in protected mode, the problems are often
 mistakenly attributed to HIMEM.SYS. In reality, HIMEM.SYS is not
 responsible for the errors because it is just the memory manager that
 CodeView utilizes to get at extended memory. The errors are the result
 of an interrupt handling incompatibility between certain hardware
 configurations and the DOS extender built into CodeView.

 Microsoft has confirmed this to be a problem in CodeView version 3.00.
 This problem has been corrected in version 3.10.


 138. Label/Function Search Command Fails Under Codeview 3.00/3.10

 Product Version(s): 3.00 3.10 | 3.00 3.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist3.00 buglist3.10
 Last Modified: 31-AUG-1990    ArticleIdent: Q65312

 Under CodeView versions 3.00 and 3.10, the Label/Function search
 command is described in the online help as performing a search of the
 current source window for an assembly-language label or function name.
 If the label is found, the debugger should switch from source to
 assembly mode to display a label in a library routine or assembly
 language module.

 In reality, this command fails with a message "Error - Unknown
 Symbol". The debugger does not switch into assembly mode. This problem
 can be reproduced by selecting Search from the CodeView menu, then
 selecting Label/Function and typing in "__chkstk" (without the
 quotation marks).

 Microsoft has confirmed this to be a problem with CodeView Versions
 3.00 and 3.10. We are researching this problem and will post new
 information here as it becomes available.


 139. Cannot Enable A20! with Orchid 386s

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q65360

 Using HIMEM.SYS version 2.50 with Orchid 386/25 motherboards with the
 caching controllers can cause the following error message:

    Cannot enable A20!

 Orchid Technology has verified that this is a problem with the PAL
 chip on these motherboards. Customers who are experiencing this
 problem should call Orchid Technology at (415) 683-0300 for an update
 of their PAL chip. Please have the revision of the motherboard on hand
 when calling.


 140. Mouse Cursor on Wrong Monitor During Dual-Monitor Debugging

 Product Version(s): 3.00 3.10
 Operating System:   MS-DOS
 Flags: ENDUSER | H_MOUSE
 Last Modified: 17-SEP-1990    ArticleIdent: Q65528

 Under certain conditions, when invoking real-mode CodeView (CV) in
 dual-monitor mode with /2, the mouse cursor appears on the wrong
 monitor. When this occurs, a "sprite" mouse cursor appears on the
 monitor that the application is to run on, while the secondary monitor
 where CodeView is running does not have a mouse cursor. Several
 workarounds to this problem are given below.

 The sprite mouse cursor is a "graphic" arrow cursor similar to that in
 Windows 3.00 or OS/2 Presentation Manager (PM), as opposed to the
 traditional "text" block cursor that usually appears when running
 CodeView or the Programmer's WorkBench (PWB).

 The problem of the mouse appearing on the wrong monitor occurs only on
 computers that have "extended register" video boards, such as some of
 the Video 7 VGA cards. Certain mouse drivers enable the sprite cursor
 when they detect these extended video registers. Because a monochrome
 monitor cannot support this extended mode mouse cursor, the cursor
 fails to switch to the secondary monitor when focus is switched to
 that monitor after CodeView is invoked with the /2 switch.

 The following are three possible workarounds to this problem:

 1. Upgrade to mouse driver version 7.04 or later. This version
    provides a new switch, /Y, which can be used with either the
    MOUSE.COM program or the MOUSE.SYS device driver. The /Y switch
    tells the mouse driver to disable the sprite cursor. The mouse
    driver update can be obtained free of charge by contacting
    Microsoft Product Support Services at (206) 637-7096.

 2. If a mouse driver earlier than version 7.04 is used, the problem
    may be worked around by creating a batch file or adding the
    following commands to the AUTOEXEC.BAT file:

       mode mono
       mouse
       mode co80

    These commands will switch focus to the monochrome monitor while
    the mouse is being invoked and then will switch the focus back to
    the color monitor. This method will prevent the mouse driver from
    detecting the extended registers and using the sprite cursor.

 3. Disable the extended video registers. Check the video card
    documentation to see if this method is possible with your
    particular card.


 141. CV May Come Up Only in Monochrome with 8514/A Display Adapter

 Product Version(s): 3.00 3.10
 Operating System:   MS-DOS
 Flags: ENDUSER | appnote SV0337.ARC B_QuickBas
 Last Modified: 16-OCT-1990    ArticleIdent: Q65701

 Real-mode CodeView (CV) may display only in monochrome (black and
 white) mode on some systems with an 8514 or color VGA monitor attached
 to an 8514/A display adapter. On these systems, the installation of an
 8514/A video card causes the BIOS video functions to return an
 incorrect value indicating that a monochrome VGA monitor is attached,
 rather than a color monitor.

 This same BIOS information contributes to the way in which these
 versions of CodeView (and various other programs) detect the type of
 video adapter present; thus, CodeView may incorrectly determine that
 it is running on a monochrome system and may display the screen only
 in black and white.

 Workaround
 ----------

 As a workaround, an application note titled "8514/A Monochrome to
 Color Patch" is available from Microsoft Product Support Services by
 calling (206) 637-7096. This application note contains a program,
 which may be run before CodeView is invoked and which will configure
 the BIOS information correctly for CodeView to come up in color.
 The program is also available in the Software/Data Library by querying
 on SV0337, the Q number of the article, or S12719. SV0337 was archived
 using the PKware file-conversion utility.

 This monochrome video problem is specific to DOS, and therefore, does
 not occur with protected-mode CodeView (CVP) under OS/2. However, the
 problem may appear if real-mode CodeView is run in the DOS
 compatibility box under OS/2. In addition, the problem may occur with
 other software, such as Microsoft QuickBASIC.

 With CodeView, another symptom of this problem is that the program
 output screen (which can be accessed by pressing F4) will usually
 appear as dark blue characters on a black background. This screen is
 essentially unreadable and remains this way even after CodeView is
 terminated. Typing MODE CO80 at the DOS prompt after exiting CV should
 restore the system to the default colors.

 Microsoft intends to change the video detection routine in future
 software releases in order to circumvent this problem. Although the
 problem is not specifically caused by CodeView, a more sophisticated
 video detection routine will determine what video adapter and monitor
 are present without relying on the possibly inaccurate BIOS data.


 142. CV /E Avoids Windows 3.00 386 Enhanced Mode Protection Error

 Product Version(s): 2.35 3.00 3.10
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S900919-57 B_QuickBas B_BasicCom W_Win3
 Last Modified: 24-OCT-1990    ArticleIdent: Q65934

 When you start Microsoft CodeView under Windows 3.00 in a 386 enhanced
 mode DOS box, the following error message is displayed:

    You have attempted to run protected-mode application under 386
    enhanced mode. To run the application, exit and run Windows using
    either the WIN /s or the WIN /r command.

 However, using WIN /s or /r is unnecessary. To avoid the error
 message, start CodeView with the /E option to tell CodeView that
 expanded memory is available, as follows:

    CV /E

 This information applies to Microsoft CodeView versions 2.35, 3.00,
 and 3.10 for MS-DOS.
 Note that CodeView version 2.35 is shipped with Microsoft BASIC
 Professional Development System (PDS) version 7.00; CodeView version
 3.00 is shipped with Microsoft C Compiler PDS version 6.00; and
 CodeView 3.10 is shipped with Microsoft BASIC PDS version 7.10.

 You may find that after the error message is generated, if you return
 to the DOS box and wait a few seconds, CodeView will start up. To
 avoid the error message, start CodeView as follows with the expanded
 memory (/E) switch (where <filename.exe> is the name of the program
 you want to debug):

    CV /E <filename.exe>

 To increase the size of programs that can be loaded into CodeView in
 conjunction with the /E switch, you can create a PIF file for CodeView
 and specify -1 for the Expanded Memory KB Limit, which instructs
 Windows to give the program all the EMS that it needs.

 CodeView will run without the above error message in a Windows 3.00
 DOS box in standard mode, WIN /S.


 143. CV1319 Error May Be Caused by Generic Breakpoints

 Product Version(s): 3.00   | 3.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q66215

 In some situations a program will hang with the CodeView
 initialization error CV1319 even though the program runs correctly
 outside of CodeView. Deleting any generic breakpoints in the
 CURRENT.STS file may resolve this problem. The following is an
 example:

    [debug-]
          genericbp='E 0x47:0x0007

 The problem is that when you recompile your program, the code moves
 and the absolute breakpoint may now be set in the middle of a
 multibyte instruction rather than the beginning of the instruction.

 Additional Workaround
 ---------------------

 Invoke CodeView with the /TSF ("Toggle StateFileread") option. This
 option will either read or ignore the CURRENT.STS file based on what
 the statefileread switch is set to in the TOOLS.INI file.

 For example, if the statefileread switch is set to "yes" (the default)
 and CodeView is invoked with the /TSF option, the CURRENT.STS file
 will be ignored.


 144. Running Out of Memory in CodeView with /X

 Product Version(s): 3.00 3.10 3.11
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q66230

 Under some circumstances, CodeView may still run out of memory while
 debugging large applications with the /X switch invoked to take
 advantage of extended memory with HIMEM.SYS. The debug information
 gets expanded when CodeView loads the program, so the following
 suggestions may help the problem:

 1. Don't use the quick compile (/qc) option. The symbolic information
    created by the quick compiler may expand much more when loaded by
    CodeView than the symbolic information created by the standard
    compiler. In addition, the quick compiler may create some duplicate
    debug references in the executable file. These duplicate references
    can take up significant memory when CodeView loads the program.

 2. Use the CVPACK utility, which is documented in the online
    documentation and on Page 21 of the "Microsoft C Reference" manual.
    CVPACK will compress the debug information in the file by removing
    duplicate references. Use the /P option to achieve maximum
    compression.


 145. CodeView Fails to Return Value in ES

 Product Version(s): 3.00 3.10 3.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist3.00 buglist3.10 buglist3.11
 Last Modified:  9-NOV-1990    ArticleIdent: Q66507

 When CodeView is running in extended memory and a call is made to
 interrupt 15h function C0h, the value in the ES register is not
 changed. This interrupt call should return the segment of the system
 configuration table in the ES register. If CodeView is run with the /D
 or /E option, a value is returned in the ES register as it should be.

 Microsoft has confirmed this to be a problem in CodeView versions
 3.00, 3.10, and 3.11. We are researching this problem and will post
 new information here as it becomes available.

 Sample Code
 -----------

 main ()
   {
    _asm mov ah, 0xC0
   _asm int 0x15
   }


 146. Memory Requirements for Real-Mode CodeView (CV.EXE)

 Product Version(s): 3.00 3.10 3.11 | 3.00 3.10 3.11
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 11-NOV-1990    ArticleIdent: Q66513

 Real-mode versions of CodeView (CV) beginning with version 3.00 offer
 a number of ways to utilize available memory in order to make the
 greatest amount of conventional memory available to the program being
 debugged. The amount of memory actually used depends on the
 command-line options specified as well as the configuration of the
 system used for debugging.

 The following table shows the size of CodeView in standard DOS memory
 with each of the memory-specific command-line options (see the "More
 Information" section below for further details):

    Option  RAM Usage                   Option  RAM Usage
    ------  ---------                   ------  ---------

     /X       16K                       /D16     210K
     /E      192K                       /D32     225K
     /D      256K (same as /D64)        /D128    320K

 The following descriptions of the three memory-related CodeView
 options explain the ways in which each option affects memory
 utilization in addition to the respective amounts of conventional
 memory that CodeView requires with each. (This information pertains
 only to CodeView versions 3.00 and later -- versions of CodeView
 earlier than 3.00 require approximately 230K of RAM specifically for
 CodeView.)

 /X - Specifies that CodeView should utilize extended memory. Assuming
      that enough extended memory is available, this option moves both
      the symbolic information and most of CV itself into extended
      memory. Allowing CV to be loaded into high memory requires that
      approximately 16K to 19K of "control" code remain in conventional
      memory, thus all free conventional RAM over 19K is available to
      load the program to be debugged (the "debuggee").

 /E - Specifies that CodeView should utilize expanded memory. Assuming
      that enough expanded memory is available, this option moves both
      the symbolic information and CodeView's own overlays into
      expanded memory. The size of the CV "root" without the extra
      overlayed code is approximately 192K. Since the overlays do not
      cause any additional overhead with /E, all free conventional RAM
      over 192K is available to load the debuggee.

 /D - Specifies that CodeView should utilize disk overlays in
      conventional memory. By default, this option creates a 64K buffer
      area for loading disk overlays. With the 192K root, the 64K
      buffer means CV will take about 256K of conventional memory with
      /D. In addition, the symbolic information must also be loaded
      into conventional memory; therefore, since symbolic data varies
      with each program, it is not possible to specify the amount of
      memory available for the debuggee alone.

      The /D option can also be specified with a value that indicates
      the size of the overlay buffer area. This parameter can be any
      value from 16 to 128, which represents an overlay buffer size
      from 16K to 128K. Specifying /D16 will minimize CodeView's size
      with disk overlays to approximately 210K. This maximizes the
      amount of conventional memory that will be available to load the
      debuggee and the symbolic information. At the other extreme,
      /D128 causes CV to use approximately 320K of conventional RAM.
      This provides faster CodeView execution speed, but it will only
      work with smaller debuggees.

 Note: CodeView will default to the best memory usage possible. In
 other words, if NO memory usage option is specified, CV will try to
 use extended memory. If extended memory is unavailable, CV looks for
 expanded memory. CV will use disk overlays on its own only if expanded
 memory is not found.


 147. CV2206 Warning: Corrupt OMF Detected in <filename>

 Product Version(s): 2.x 3.00 3.10 | 2.x 3.00 3.10
 Operating System:   MS-DOS        | OS/2
 Flags: ENDUSER | S_MASM H_MASM
 Last Modified: 11-NOV-1990    ArticleIdent: Q66702

 When trying to debug a Macro Assembler program with CodeView, the
 following message may appear:

    CV2206 Warning: Corrupt debug OMF detected in <filename>,
       discarding source line information

 The error occurs when code segments are not of class "CODE". Page 104
 of the "Macro Assembler 5.10 Programmer's Guide" states the following:

    The CodeView debugger also expects code segments to have the class
    name 'CODE'. If you fail to assign a class type to a code segment,
    or if you give it a class type other than 'CODE', then labels may
    not be properly aligned for symbolic debugging.

 This is also mentioned in the "CodeView and Utilities" manual under
 section 1.3.8 titled "Preparing Assembly Programs."

 The following is an example of the problem:

 _text segment para public   ; 'CODE' should be added to this line

 begin    proc
       mov ah, 4ch
       int 21h
 begin    endp

 _text ends
       end begin


 148. How to Execute a Function From the Command or Watch Window

 Product Version(s): 2.x 3.00 3.10 3.11 | 2.x 3.00 3.10 3.11
 Operating System:   MS-DOS             | OS/2
 Flags: ENDUSER | docerr s_c 6.00 6.00a
 Last Modified:  4-DEC-1990    ArticleIdent: Q67007

 Page 201 of the "Advanced Programming Techniques" (APT) manual that
 accompanies Microsoft C versions 6.00 and 6.00a states that "any C
 function in your program (whether user-written or from the library)
 can be called from the Command window or the Watch window."

 This statement is not completely true. Actually, only functions
 compiled with full CodeView symbolic information can be called. This
 restriction eliminates all of the C run-time functions from being
 executed in this manner because they contain no symbolic information.
 A simple example of how to call a C run-time function is shown below.

 If an attempt is made to execute a function that has not been compiled
 with symbolic information via the Command window, the following error
 will be displayed in the Command window:

    CV1017 Error: Syntax error

 In CodeView versions 2.x, an "unknown symbol" error is displayed in
 the Command window.

 If an attempt is made to add the function to the Watch window via the
 Watch menu and the "Add Watch" command, CodeView will ignore the entry
 and beep. In versions 2.x, CodeView will give an "unknown symbol"
 error.

 The APT gives an example of calling a C function from the Command
 window via the following command:

    ?funcname (varlist)

 This command will only invoke the function and display its return
 value in the Command window. To add the function to the Watch window,
 a slightly different command must be used, as follows:

    w?funcname (varlist)

 The function name can also be added to the Watch window by choosing
 the Watch menu and the "Add Watch" command, and typing only the
 function name plus its variable list enclosed in parenthesis. Neither
 the "w" or the "?" are needed in this situation.

 It is important to note that you should be sure that the screen
 flip/swap option on the Options menu is turned on if the function you
 execute performs any screen input or output.

 For example, if you want to call a C run-time function or any other
 function that does not contain CodeView symbolic information, you must
 create a shell function that calls the desired function itself and
 gives the same return value.

 Therefore, if you wanted to call the C run-time function sqrt()
 directly from the CodeView Command window or Watch window, you would
 create a shell function that resembles the following:

 1. #include <math.h>
 2. double my_sqrt(double x)
 3. {
 4.    return(sqrt(x)) ;
 5. }

 You would then compile this function with CodeView information by
 compiling with the /Zi switch, and then link it into your program
 being sure to include /CO in your link command. Note that your program
 does not need to make a call to the function in order for it to be
 available for direct execution.

 To execute this function from the Command window, enter the following
 command:

    ?my_sqrt(4.0)

 The return value should be displayed on the next line in the Command
 window. In this example, 2.0000000000000 should be displayed as a
 result of the square root of 4.0.

 To add the function to the Watch window via the Command window, you
 would enter the following command:

    w?my_sqrt(4.0)

 The function could also be added to the watch window by choosing the
 "Add Watch" command from the Watch menu and entering the following at
 the Add Watch prompt:

    my_sqrt(4.0)

 When a function is added to the Watch window, that function is
 executed any time the Watch window is updated.

 Although these examples show a constant value as the parameter to the
 function, any variable that is in scope at the time could be entered
 as a parameter.


 149. Syntax Error When Watching Variables That Begin with "P"

 Product Version(s): 2.20 2.30 | 2.20 2.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist2.10 buglist2.20 fixlist3.00
 Last Modified: 18-NOV-1990    ArticleIdent: Q67008

 When the following command is entered in the Command window to watch a
 variable that begins with the letter "p", the result is a syntax
 error:

 > W pvariable

 The syntax for watching a memory location is W[type] range, where the
 type and range specify the format and length of memory to be
 displayed, respectively.

 When no type is declared, as in the above example, the default type is
 used. The default type will be the last type used by a Dump, Enter,
 Watch Memory, or Tracepoint Memory command. If none of these commands
 has been used during the session, the default type is byte.

 The workaround for this problem is to explicitly declare a type in the
 watch statement, for example:

 > WB pvariable.

 Microsoft has confirmed this to be a problem in Microsoft CodeView
 versions 2.x. This problem has been corrected in Microsoft CodeView
 version 3.00.

 Additional keywords: buglist2.30 buglist2.35


 150. CV1017: Syntax Error Can Be Caused by a Leading Zero

 Product Version(s): 3.00 3.10 3.11 | 3.00 3.10 3.11
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified:  4-JAN-1991    ArticleIdent: Q67160

 Since CodeView treats all values with a leading zero as octal numbers,
 the following error is reported when the value is not a valid octal
 number:

    CV1017: syntax error

 To enter a number in hexadecimal form, the value must be preceded with
 "0x" (without the quotation marks). If the value is a number in
 decimal form, any leading zeros should be dropped.

 You can also use the "0n" prefix to specify decimal numbers,
 independent of the current radix.


 151. CodeView Asks for Path to a Source File Without Extension

 Product Version(s): 2.x 3.00 3.10 3.11 3.50
 Operating System:   MS-DOS
 Flags: ENDUSER | s_lib s_utility
 Last Modified:  4-DEC-1990    ArticleIdent: Q67271

 If an old version of the LIB utility is used to store OBJ modules in a
 library, the extension may not be stored. This can cause a problem if
 a module is compiled with debug information and an .EXE is built for
 CodeView to debug. When CodeView attempts to open the source file for
 the module in the library, it will fail because there is no extension.
 It will then prompt you for the filename.

 This is a problem with the Microsoft LIB utilities earlier than version
 3.08 and some third-party library managers. Beginning with LIB version
 3.08, the full filename is stored in the library.


 152. CodeView Does Not Debug kbhit() Correctly

 Product Version(s): 3.00 3.10 3.11  | 3.00 3.10 3.11
 Operating System:   MS-DOS          | OS/2
 Flags: ENDUSER | buglist3.00 buglist3.10 buglist3.11
 Last Modified:  4-DEC-1990    ArticleIdent: Q67360

 When setting a breakpoint between the kbhit() function and a function
 to read a character from the input stream, CodeView will grab the
 character from the input stream when the breakpoint is executed.

 The following code example demonstrates the problem. If a breakpoint
 is placed on the line containing the getch() function, the character
 input from the keyboard will be placed in CodeView before the getch()
 function is actually stepped over. You will not be prompted for the
 character when you step over the getch() function. The character you
 typed to stop the kbhit() loop will be used for the getch() function
 call when that line is executed.

 Microsoft has confirmed this to be a problem in CodeView versions
 3.00, 3.10, and 3.11. We are researching this problem and will post
 new information as it becomes available.

 Sample Code
 -----------

 #include <stdio.h>
 #include <conio.h>

 void main(void)
 {
         int a;

         do {
                 printf(".");
         } while(!kbhit());

         a = getch();         // put breakpoint here

         printf("%c\n", a);
 }






 Microsoft Linker
 =============================================================================


 1. Corrupted Library Causes Error L1102

 Product Version(s): 3.61 3.64 3.65 | 5.01.20 5.01.21
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified:  6-DEC-1988    ArticleIdent: Q38201

 The link error "L1102: unexpected end-of-file" is generated when the
 linker attempts to resolve externals in a corrupted or null-length
 library.

 This error most commonly occurs with a combined library, mlibx.lib,
 that is corrupted during the library creation stage of SETUP. Make
 sure to check the \LIB subdirectory for odd or null size libraries.
 Library rebuilding is needed if insufficiently-sized libraries are
 found.

 The L1102 error can also be generated if you inadvertently type in the
 name of a used library at the "list file" prompt, as follows:

    Run File  [SPUD.EXE]:      main.exe
    List File [NUL.MAP]:       libname.lib    (generates faulty library)
    Libraries [.LIB]:          libname.lib
    Definition File [NUL.DEF]: main.def

 This process creates a map listing with the specified library name in
 the current working directory. Because this directory is searched
 before the directory specified in the LIB environment variable, the
 incorrect library containing the map listing is used during linkage,
 causing the error L1102.


 2. /I Linker Option Should Read /INF

 Product Version(s): 3.61 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 18-OCT-1988    ArticleIdent: Q30515

 Pages 266 and 267 of the "Microsoft C Optimizing Compiler CodeView and
 Utilities" manual for Versions 5.00 and 5.10 incorrectly list the
 shortened name of the /INFORMATION option as /I.

 If /I is given as an option, the result is an error stating that /I is
 an unrecognized option.

 The correct shortened name for /INFORMATION is /INF.


 3. Maximum Libraries LINK Can Handle

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-OCT-1988    ArticleIdent: Q31986

    LINK can handle no more than 32 libraries, i.e., on the LIBRARY
 prompt, you can specify up to 32 libraries.
    If you have more libraries, you have two choices: combine libraries
 or specify some of them at the object modules prompt. In the second
 case, LINK will treat the library as a collection of object modules,
 all of which should be included in your .EXE file.


 4. Maximum Number of Object Modules LINK Allows

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-OCT-1988    ArticleIdent: Q31987

    There is no limit to the number of object modules LINK allows;
 however, LINK can operate only in certain limits imposed by the amount
 of available resources.


 5. The Meaning of an Invalid Object Module

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-OCT-1988    ArticleIdent: Q31988

 An invalid object-module error message means that an object module
 does not conform to Microsoft object format. The description of object
 format can be found in "MS-DOS Encyclopedia Part E: Programming Tools
 Article 19: Object Module."


 6. Object Modules Handled by LINK

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q31989

    Successive versions of LINK always are backward compatible, but not
 necessarily upward compatible, i.e., the most recent versions should
 link any existing object module, but not necessarily any future object
 module.
    To solve this problem, update to the latest version of LINK.



 7. How LINK Orders and Combines Segments

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q31991

    Every segment belongs to a named class such as 'CODE', 'DATA', or
 'BSS'. LINK orders all segments with the same class name contiguously.
    Within each class, segments are placed in the same order as LINK
 encounters them. Segment classes are placed in the order they appear.
 If you do not give a class name when you define a segment in assembly,
 the segment gets the null class, which is treated like any other segment.
 If the /DOSSEG option is given, or one of the Microsoft language run-time
 libraries is used, LINK imposes the following additional order:

       code (class ending in 'CODE')
       far data (everything but DGROUP and 'CODE')
       DGROUP - the default data segment
           class 'BEGDATA' (special runtime segment)
           near initialized data (everything but 'BSS' and 'STACK')
           near BSS--uninitialized data  (class 'BSS')
           stack



 8. Link Error L1053 Symbol Table Overflow

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-OCT-1988    ArticleIdent: Q31992

 Question:

 I am receiving link error L1053: symbol table overflow. What is the
 limit of the symbol table?

 Response:

 Under MS-DOS, this limit using the DOS-only linker (Versions
 3.x) is dependent on the amount of available memory in your computer.
 LINK can use all conventional memory available under DOS (up to 640K).

 Under OS/2, the segmented-executable linker (Versions 5.x and above)
 has no limit on the size of the symbol table because it extends the
 symbol table in virtual memory.


 9. Temporary Files Created at Link Time

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-JUL-1988    ArticleIdent: Q31993

    The linker creates a temporary file when it runs out of memory to
 hold the symbol table or the load image and run-time relocations of
 the program being linked.



 10. How Overlays Are Set Up By the Linker

 Product Version(s): 3.x 4.06 4.07 5.01.20 5.01.21 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-JAN-1990    ArticleIdent: Q31994

 The overlay linker uses an interrupt to call in overlaid files. By
 default, the interrupt number used for passing control to overlays is
 63 (3f hex).

 The linker links the Microsoft overlay manager from the standard
 Microsoft language run-time libraries. The linker assigns segments to
 overlays based on the grouping you indicate. It replaces
 overlay-to-overlay far calls and root-to-overlay far calls with an
 interrupt sequence that calls the overlay manager. The overlay manager
 swaps overlays if necessary and returns control to the program.

 The linker replaces root-to-overlay and overlay-to-overlay far calls
 with the following sequence:

    INT     3Fh         ; can change # with /OVERLAYINTERRUPT:#
    DB      ?           ; target overlay segment number, where
                        ; every non-root code segment is numbered
                        ; starting at 1
    DW      ?           ; target offset within segment

 The interrupt handler is set to the overlay manager code that swaps
 out the resident overlay if necessary and swaps in the target overlay,
 then jumps to the target address. The overlay manager does nothing
 unusual in servicing the interrupts; it does not disable interrupts.
 However, it may issue INT 21h calls to swap overlays.

 The overlay manager assumes that once your initialization code has
 been executed, DS and SS will always be the same. Furthermore, it
 assumes you will initialize DS and SS to the value of DGROUP (the
 default data segment defined by Microsoft languages). Note that your
 program also must have a stack segment.

 A more detailed description of the overlay manager can be found on
 Page 715 of the "MS-DOS Encyclopedia," "Article 20: The Microsoft
 Object Linker."


 11. Why the First Module in the Code Segment Starts at Offset 16

 Product Version(s): 3.x 4.06 4.07 5.01.21 5.03 | 5.01.21 5.03
 Operating System:   MS-DOS                     | OS/2
 Flags: ENDUSER | s_c s_quickc s_quickasm h_masm h_fortran
 Last Modified: 14-FEB-1990    ArticleIdent: Q58688

 Question:

 Under some circumstances, I get 16 zero bytes at the beginning of my
 code segment. I'm linking with my own replacement C library with
 start-up code. The entry point to this start-up module is the first
 item in the module, and it always ends up at offset 16. Why is this?

 Response:

 The linker will insert 16 bytes at the beginning of the code segment
 if it determines that you are using standard segment naming
 conventions (/MS-DOSSEG) and the NULL segment is not explicitly
 removed (/NONULLSMS-DOSSEG). In your case, the linker assumes that you
 need support for signal() and allocates the first 16 bytes for it.

 Note: This will always be done for C programs by the compiler.


 12. Linker Outputs Information with Invalid Object Module

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q31999

    When an invalid object-module error message occurs, some
 information about the record and the position is printed.
    This information includes the object record type and the relative
 position of the record in the .OBJ file. There is little you can do
 with this information; it is mainly for compiler and assembler
 developers to point to the wrong object record.


 13. Incremental Linking

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q32000

    The following is a description of the incremental-linking process.
    Your file is built from a set of .OBJ files. Each .OBJ file is
 produced by the compiler or assembler from a source file. If a set of
 .OBJ files is large, then linking time can be long. If you change only
 one source file (i.e., in your set of .OBJ files you have one new .OBJ
 file), you can link all .OBJs one more time, or patch your .EXE file
 with the new .OBJ file. This patching is called incremental linking.
    Incremental linking only is supported for OS/2 and Windows
 programs.



 14. Explanation of a MAP File

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q32001

    A MAP file gives you a picture of how your code and data are
 arranged in memory when the program is loaded.
    First you get the list of segments in the order in which they will
 be loaded into memory. For each segment, you have its starting
 address, length, name, and class. Following the segments are groups,
 each specifying the starting address of the group.
    If you specify the /MAP switch and list filename, in the MAP you
 will get two lists of public symbols in your program. The first list
 will be sorted alphabetically, the second by addresses.
    If you specify the /LINENUMBERS switch, then in the MAP, you will
 get line numbers and the associated addresses of your source program.
 To produce line numbers in the MAP, give LINK an object file with
 line-number information. Use the /Zd option with any Microsoft
 compiler to include line numbers in the object file.
    Information from the MAP will help you debug your program and
 understand how the program is loaded into memory.


 15. L1087: "Unexpected End-of-File on Scratch File"

 Product Version(s): 3.x 5.x  | 5.10
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER |
 Last Modified: 13-OCT-1988    ArticleIdent: Q34669

 The Link Utility generates the error message L1087: "unexpected
 end-of-file on scratch file" when a disk with the temporary linker
 output file has been removed. This information is documented in the
 "Microsoft Macro Assembler CodeView and Utilities Guide."

 The error message L1087 also can be caused by insufficient memory
 available on the disk that contains the temporary linker output file.
 The disk can be a hard disk, floppy disk, or RAM disk.


 16. Assigning Addresses to Overlay Segments

 Product Version(s): 3.x 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-JUL-1988    ArticleIdent: Q32003

    The linker assigns only code segments (identified by class names
 ending in "CODE") to overlays. Data segments go in the root. The
 particular overlay the segment goes in is determined by the module
 that first defines the segment.

    Note that the linker assigns segments, not object modules, to
 overlays. Therefore, if you have the following command

     LINK A+(B+C)

 where

     A   defines public SEG1
     B   defines public SEG2
     C   defines public SEG1

 then C's contribution to SEG1 goes in the root, not in the first
 overlay, because SEG1 was first defined in a root module.
    The linker orders all segments as it normally would, ignoring the
 overlays and using the class and combine-type rules described
 elsewhere. The linker then assigns addresses for every segment in the
 root up to the first overlay segment. Before the first overlay
 segment, it defines a special empty segment called OVERLAY_AREA. Then
 for each overlay it assigns addresses for every segment in the overlay
 so that the first segment in the overlay starts at OVERLAY_AREA. One
 particular overlay will end at a higher address than all the others;
 at this address, the linker defines a special empty segment called
 OVERLAY_END. Finally, the linker assigns addresses for all remaining
 segments in the root so that the first one starts at OVERLAY_END. The
 load image looks like the following:

         ------------+-> 0000
         |           |
         |  root     |
         |           |
         +-----------+-> OVERLAY_AREA
         |  overlay  |
         |  area     |
         |           |
         +-----------+-> OVERLAY_END
         |  root     |
         +-----------+

    The resultant MAP file has some different contents than the
 pre-overlay file. All items listed are declared as "res", meaning
 resident. The items contained within the overlay modules are also
 declared as "res".
    At the top of the MAP file, the segments are listed in the exact
 order in which they will be in the load image, and each segment is
 identified as being in a particular overlay or the root.
    Every symbol marked "res" is in a root segment and every symbol
 marked "ovl" is in an overlay segment. If symbols are not where you
 think they ought to be, remember the linker assigns segments, not
 modules, to overlays.
    For more information on overlays, refer to the 1988 "MS-DOS
 Encyclopedia."


 17. Link Error L1089

 Product Version(s): 3.51 3.55 3.60 3.61 3.64 3.65 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-JUL-1988    ArticleIdent: Q32829

    If you are receiving the following error message, check to see if
 the TMP environment variable is set correctly:

    L1089   'filename' : cannot open response file

   If the TMP variable is not set, temporary files cannot be created
 and this error may occur.



 18. Cannot Overlay Small-Model Code

 Product Version(s): 3.60 3.61 3.64 3.65 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q34294

 Problem:

 I have specified overlays for my small-model code, but the link map
 shows that no overlays are produced.

 Response:

 You cannot overlay small-model code. You must change the memory model
 to medium, large, or huge. Page 285 of the "Microsoft CodeView
 Utilities" manual that comes with C Versions 5.00 and 5.10, MASM
 Versions 5.00 and 5.10, and Pascal Version 4.00, and Page 135 of the
 "Microsoft FORTRAN Optimizing Compiler User's Guide" states that you
 can overlay only modules to which control is transferred and returned
 by a standard 8086 long (32-bit) call/return instruction.


 19. Link Error 4051

 Product Version(s): 3.60 3.61 3.64 3.65 5.01.20 5.01.21
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-JUL-1988    ArticleIdent: Q32831

    If you receive link error 4051, check the following:

    1. Is the LIB environment variable set correctly? Check
       for spaces around the equal sign or any extra characters
       at the end of the line.
    2. Which version of the linker is being used? Old versions of
       the linker do not recognize the LIB environment variable.
          Make sure the linker being used is the one that came with
       the product.
    3. Are the library names being asked for component libraries or
       combined libraries? Libraries compiled under C Version 4.00 or
       earlier have component library names embedded in the .OBJ files.
       With later versions of the C compiler, combined libraries are used
       and the component libraries will not be found.
          This behavior also exist when upgrading from Pascal Versions 3.32
       or earlier to Pascal Versions 4.00 or greater.
          The work-around for this behavior is to recompile all .OBJ file
      (and libraries) with the new compiler or to use the /NOD switch
      when linking, and specify all the libraries (combined and otherwise)
      to be used. The following is an example:

             link /NOD  test,,,llibce.lib;

    4. Is the correct library available for the math option chosen?
    FORTRAN defaults to the co-processor library (e.g. LLIBFOR7.LIB).
    C and Pascal default to the emulator math library (e.g. SLIBCE.LIB
    and LIBPASE.LIB)



 20. LINK /CO /DO in OS/2 Gives Protection Violation

 Product Version(s): 5.01.21 | 5.01.21
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist5.01.21
 Last Modified: 13-OCT-1988    ArticleIdent: Q34374

 The Microsoft Segmented Link Utility Version 5.01.21 will
 incorrectly generate a protection violation under OS/2 when the
 command line uses the options /CO /DO, respectively.

 OS/2 gives the message SYS1943: "A program caused a protection
 violation." The SYS1811 violation follows, indicating the process has
 stopped.

 The work around for this problem is to order the switches differently.
 Instead of including /CO /DO in the command line, the command line can
 be reorder to /DO /CO.

 Microsoft has confirmed this to be a problem in Version 5.01.21. We are
 researching this problem and will post new information as it becomes
 available.


 21. /NOE Option for Redefinition Error L2044

 Product Version(s): 3.x 5.x | 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 13-OCT-1988    ArticleIdent: Q34502

 The /NOEXTDICTIONARY switch tells the linker NOT to take advantage of
 additional information recorded in Extended Dictionary in the library
 file. This additional information describes which module in the library
 calls any other module from the same library, saving linker number
 of passes through the library file to pick up all required modules.

 If you have a call in your code to the library function FOO and FOO
 calls another function BAR from the same library, then at processing
 time of FOO, the linker will pull out BAR. This process occurs because
 the extended dictionary has a link between FOO and BAR.

 Linking without /NOE causes the following error if you want to pull
 FOO in from the library but you want to provide its own BAR:

 L2044 BAR : symbol multiply defined, use /NOE

 This error resulted from the linker pulling FOO and BAR from the
 same library, then later it sees BAR coming from user .OBJ file.

 Using /NOE in this case prevents the linker from pulling out
 BAR from the library, so your BAR routine is used instead.

 If you have genuine symbol redefinition, then when linking with /NOE
 you will see the following error:

 L2025 BAR : symbol defined more than once


 22. L2001 Fixups without Data

 Product Version(s): 3.65 5.01.21 | 5.01.21
 Operating System:   MS-DOS       | OS/2
 Flags: ENDUSER |
 Last Modified: 12-OCT-1988    ArticleIdent: Q35155

 The Link Utility can generate the linker error message L2001:
 fixup(s) without data. In the manual, the linker error is described
 as follows:

 A FIXUPP record occurred without a data record immediately
 preceding it. This is probably a compiler error. (See
 the "Microsoft MS-DOS Programmer's Reference" for more information
 on FIXUPP.

 In most cases, the error message is generated from an
 assembly-language program that doesn't make sense from the linker's
 point of view, but is convenient for users. The following is an
 example:

     extrn   foo:word

     ABSEG   segment at 123          ; absolute segment

     dw      offset DGROUP:foo       ; offset portion of address of "foo"

     ABSEG   ends

 This tells the linker to fix up a location in ABSEG with the address
 of foo. But ABSEG is an absolute segment and has no data to be fixed
 up.

 Another example is when you include the same STRUC definitions in both
 absolute and non-absolute segments, so that the STRUC definitions
 contain relocatable addresses.



 23. Setting the Overlay Interrupt (/O) in LINK

 Product Version(s): 3.61 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 20-JAN-1989    ArticleIdent: Q40408

 Question:

 Page 272, Section 12.2.12, of the "Microsoft CodeView and Utilities
 Software Development Tools for the MS-DOS Operating System" manual
 states that you can change the default overlay interrupt. The default
 interrupt is 3F hexadecimal. Is the manual correct? Do you have to
 change the interrupt if you have a program that uses overlays and it
 spawns a program that also uses overlays?

 Doesn't the compiler save interrupts? Suppose both Programs A and B
 use overlays and A spawns B. If B is a Microsoft C Version 5.00 or
 5.10 program, shouldn't it restore the original INT 3F address when it
 exits? Thus, everything should work correctly without
 /OVERLAYINTERRUPT.

 Response:

 You are correct; the C Versions 5.00 and 5.10 compiler saves and
 restores the interrupt so there should be no conflict. The C Versions
 5.00 and C 5.10 manual is incorrect. This switch need only be used if
 you are linking a program with overlays, and INT 3F is being used by
 something else when you run the program. For example, INT 3F might be
 used to communicate with a hardware board or a TSR might use it;
 however, this is unlikely.

 This option is for advanced users who know their configurations well
 enough to know who is using which interrupt vectors and know there is
 a conflict.


 24. LINK Environment Variable Ignored When Linking Through CL

 Product Version(s): 5.00 5.10 | 5.10
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | S_C S_QuickC
 Last Modified: 15-AUG-1989    ArticleIdent: Q47503

 Problem:

 To increase the size of my stack, when I set an environment variable
 called LINK equal to /ST:4096, it doesn't work correctly when I link
 using CL.

 Response:

 Before CL spawns the linker, it clears the environment of all
 variables except LIB. Consequently, the LINK environment variable
 doesn't exist when the linker is invoked, and any options that were
 specified by it are not seen. When linking with CL, any desired linker
 options should be specified on the CL command line after the /link
 switch.

 The same behavior is seen with the command line compilers from QuickC
 Version 1.00 and 1.01, but not with QuickC 2.00 or QuickAssembler.


 25. Why Unitialized Global Variables Don't Appear in C 5.10

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G881021-5044
 Last Modified:  6-DEC-1988    ArticleIdent: Q38725

 Questions:

 Why don't uninitialized global variables show up in the library
 listing when the module containing them has been placed in the
 library? It appears that the librarian does not "see" uninitialized
 global variables.

 If my main program declares an extern, and an .OBJ with which its
 linked declares it globally (without extern), but doesn't initialize
 it, the symbol appears in the link map and space is allocated for it
 in the .EXE. This behavior seems different from previous versions of
 the compiler. If the .OBJ file is placed as a library rather than
 linked explicitly, the symbol does not appear in the .EXE. Why does it
 behave differently?

 Response:

 In Version 5.00 of the C Compiler, we introduced a new concept into
 our linking process called "communal data." Communal data can be
 declared in many modules, but only one copy of the data will exist
 in the linked .EXE file. (It is similar to the concept of COMMON
 blocks in FORTRAN.)

 In C, data declared outside of a function without a storage class is
 now considered to be communal data. (This is a change from previous
 versions.) Communal data declarations generate no definitions, just
 declarations; whereas initialized, or global, data declarations
 generate both definitions and declarations.

 Communal declarations may refer to a global definition. If they do,
 the linker simply adjusts the address as necessary. However, if
 there is no global definition of the variable, the linker combines
 the declarations into one definition and allocates the appropriate
 amount of space. For example, it is legal to declare

    int x;

 in several different modules without a corresponding

    int x = 0;

 Communal declarations are NOT copied into libraries. (This is
 documented on Page 84 of the "Microsoft C Language Reference Manual.")
 If you want the variable to appear in a library, it MUST be
 initialized so that it is global rather than communal. Communal
 variables are not included in libraries because they can cause
 strange conflicts. For example, let's suppose you
 unwittingly used a variable name that was also the name of a communal
 variable in your library. At link time, the linker would allocate
 only ONE copy of that variable without generating any warning.

 The symptom would be that your variable would mysteriously change
 every time you called the library function that used the communal
 variable. This problem would be a very difficult to trace.

 Now that we understand communal variables and how they interact with
 libraries, we can answer your questions.

 The first question was basically, "Why don't my communal variables
 show up in the library listing?" Because communal data is not placed
 into the library, it won't show up in the listing.

 The second question was, "How come the communal variable shows up in
 the .EXE file if I link it from an .OBJ file but not from a .LIB
 file?" It shows up from the .OBJ file because the communal variable
 is allocated space by the linker if it doesn't resolve to a global
 definition. It does NOT appear in the link produced by the .LIB file
 because it does not appear in the library dictionary.

 Note: this behavior is the result of doing something we ask you not to
 do; namely, putting communal data in a library. Data intended to be
 placed in a library must be initialized.


 26. Example of Using a Response File with LINK

 Product Version(s): 3.65   | 5.01.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40429

 The following is a small example of using a response file with LINK.

 A response file contains responses to the LINK prompts. The responses
 must be in the same order as the LINK prompts.

 LINK treats the input from the response file just as if you had
 entered it in response to prompts or in a command line. It treats any
 carriage-return-linefeed combination in the response file the same as
 if you had pressed the ENTER key in response to a prompt or included a
 comma in a command line.

 Note: You cannot put comments in response files.

 The following is an example of a file named RESPONSE.ONE:

 file1 file2 file3 file4
 /pause /map
 filelist
 graphics.lib

 Type the following at the command line:

    LINK @response.one


 27. Error L2025: Symbol Defined More than Once

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-JAN-1989    ArticleIdent: Q40485

 Problem:

 I cannot link a function name in my object file with a library
 containing that same function name and have the resulting EXE call my
 function and not the library's.

 I am using /NOE; however, I receive the following error:

 (...): error L2025: (my function name) : symbol defined more than once
  pos: (some number) Record type: 53E8

 Response:

 You can only perform this task if the function name is an individual
 module. The following procedure demonstrates the error:

 1. Create a file CALL.C that calls functions A() and B().

 2. Create functions A() and B() in fileA.c and fileB.c, and compile
    them to objects.

 3. Do the following to create TEST.LIB:

       LIB TEST +fileA +fileB, test.lst

 4. Change B() in fileB.c and compile the following:

       cl call.c fileB.c test.lib /link /NOE /INF

    You will have an EXE that calls A() from the library and B() from
    your modified fileB.c.

 5. Combine fileA.c and fileB.c into one file called TEST.C.

 6. Compile to object code.

 7. Delete the old TEST.LIB, and do the following:

       LIB TEST +test, test.lst

    (Normally you would change fileB.c, but this is not necessary here.)

       cl call.c fileB.c test.lib /link /NOE /INF

 You will receive the following error:

 TEST.LIB(test.c) : error L2025: _B : symbol defined more than once
  pos: 13E Record type: 53E8
 There was 1 error detected

 When you encounter this error, it is usually because the function you
 are trying to overwrite is part of a set appearing in one module.

 The library listing looks as follows in the first case:

 _A................fileA             _B................fileB

 fileA             Offset: 00000010H  Code and data size: 95H
   _A

 fileB             Offset: 000002a0H  Code and data size: 92H
   _B

 You will be able to replace A() or B(). The listing in the
 second example looks as follows:

 _A................test              _B................test

 test              Offset: 00000010H  Code and data size: deH
   _A                _B

 You will not be able to replace either A() or B() without removing the
 TEST module with the LIB utility. You may have to provide replacements
 for both functions and not just the one you want to change. For more
 information, query on the following words in this KnowledgeBase:

    L2029 unresolved externals


 28. Default for NODATA When Using the _export Keyword

 Product Version(s): 5.01.21 | 5.01.21
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist5.10.21 buglist5.02 fixlist5.03
 Last Modified: 21-AUG-1989    ArticleIdent: Q47826

 Question:

 What is the default for NODATA when using the _export keyword? The
 _export keyword is used to mark functions in DLLs for export. It
 appears that for real-mode windows, for normal applications, _export
 does not use NODATA. However, for DLLs (also for real-mode windows)
 _export marks the function NODATA. How does the keyword _export mark
 functions (NODATA or not).

 Response:

 The default as issued by the compiler is not NODATA, i.e., the
 exported routine is assumed to use the shared data segment.
 Unfortunately, the linker has a problem that causes it to mistakenly
 assume NODATA for all exports declared from the .OBJ file.

 Microsoft has confirmed this to be a problem with LINK Version 5.01.21
 and 5.02. The problem was corrected in LINK Version 5.03 and later.

 In OS/2 this should not make any difference. In Windows, the program
 loader looks for the -Gw sequence in the prolog of the exported entry
 and replaces it with a sequence to load DS. The _loadds keyword will
 generate the load-DS sequence in the first place.

 In any case, a workaround is to not use the _export keyword and
 declare the routine in EXPORTS in the .DEF file.


 29. No Default Extension for a Linker Response File

 Product Version(s): 3.55 3.60 3.61 3.64 3.65  | 5.01.21 5.01.21
 Operating System:   MS-DOS                    | OS/2
 Flags: ENDUSER |
 Last Modified:  2-MAR-1989    ArticleIdent: Q41611

 The Microsoft Overlay Linker does not have a default extension for a
 response file; unlike Phoenix's PLINK, which uses a default .LNK
 extension.

 This information also applies to the Microsoft Segmented-Executable
 Linker.


 30. Ambiguous Switch /PAC with QuickC 2.00 Linker

 Product Version(s): 4.06
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc b_quickbas docerr
 Last Modified: 22-JAN-1990    ArticleIdent: Q42027

 Using the /PAC switch with LINK Version 4.06 results in the
 following error:

    fatal error L1001: PAC : option name ambiguous

 This same option works correctly on Versions 3.65 and 5.01.21, and is
 documented as being a valid shorthand name for /PACKCODE on Page 131
 of the "QuickC Tool Kit."

 The problem is due to a conflict with an option that is not documented
 in the Tool Kit, but is displayed when LINK is invoked with /HELP. The
 option that causes the ambiguity is /PACKDATA, which causes data
 segments to be combined.

 The shortest version of /PACKCODE that can be used is /PACKC.
 Similarly, /PACKD is the shortest version of /PACKDATA that can be
 used.


 31. /CO before /DO Causes Problems in LINK

 Product Version(s): 3.65 4.06 5.01
 Operating System:   MS-DOS
 Flags: ENDUSER | h_masm s_pascal h_fortran buglist3.65 buglist5.01
 Last Modified: 28-MAR-1989    ArticleIdent: Q42212

 When compiling or assembling with the /Zi switch to include CodeView
 symbolic information and linking with /CO to preserve it, the
 placement of the /DO switch is crucial. If the /CO switch is specified
 before /DO, the following behavior may occur when running CodeView:

    Message                                Behavior

    Enter directory for  (cr for none)?    When CodeView is executed,
                                           no source code will appear.

    Unable to open file

    Internal debugger error: 13            When attempting to change
                                           from assembly view to source
                                           CodeView. Hanging of the
                                           machine when executing
                                           CodeView.

 If switching the order of the /CO and the /DO switches does not
 take care of the problem then you have to put the .DOSSEG into
 your MASM routines and not use the /DO switch.

 Microsoft has confirmed this to be a problem in Versions 3.65 and
 5.01. We are researching this problem and will post new information as
 it becomes available.

 While LINK Version 5.01 may be used in OS/2, the /DO switch has no
 meaning. Using it, however, causes the linker to GP fault if /CO
 precedes /DO.



 32. Unimplemented Switch /BI with QuickC 2.00 Linker

 Product Version(s): 4.06
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QUICKC
 Last Modified: 24-JAN-1990    ArticleIdent: Q42849

 The /BINARY switch for Link Version 4.06 is documented on Page 122 of
 the "Microsoft QuickC Tool Kit" as a switch used to create .COM files
 for assembly-language programs. Its shorthand version is /BI. This
 switch is an alternative to creating .EXE files and then running them
 through EXE2BIN.

 This switch is currently not implemented, a fact documented in the
 README.DOC on line 665, "Creating a .COM file." Using it will result
 in the following error:

     fatal error L1002: BINARY : unrecognized option name


 33. How /NOE (No Extended Dictionary) Is Used by the Linker

 Product Version(s): 3.65 4.06 5.01 | 5.01
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | S_C H_FORTRAN S_QUICKC
 Last Modified:  6-APR-1989    ArticleIdent: Q43009

 This article contains information about the LINK option /NOE and how
 it relates to the three following topics:

 1. The Extended Dictionary and how LINK uses it

 2. The definition of genuine redefinition

 3. Why redefinitions are not detected in some situations

 The LINK option /NOE stands for No Extended Dictionary.

 What is the extended dictionary and how does LINK use it? How does
 LINK use the extended dictionary?

 LINK uses the extended dictionary to speed up library searching. For
 example, if the library module A calls functions in module B and
 module C, the extended dictionary tells LINK that, if your program
 requires module A from library, it will also require modules B and C.
 According to this information, LINK pulls in the three modules A, B,
 and C all at once. This way, LINK doesn't have to search the library a
 second time to resolve references from module A to modules B and C.

 What is a genuine redefinition?

 The ERRMSG.DOC file states that when linker error L2044 occurs, the
 /NOE switch should be used. When linker error L2025 occurs, the
 program has a genuine redefinition problem.

 A genuine redefinition is any redefinition that has nothing to do with
 the extended dictionary. A redefinition error that occurs when you
 specify the /NOE switch indicates a genuine redefinition, as in the
 following example:

     FOO.OBJ:
         defines "_foo"
         calls "_libfunc"

     Module A: (in XYZ.LIB):
         defines "_libfunc"
         defines "_foo"

 If you run "LINK foo /NOE,,,xyz.lib", the L2025 error will be produced
 because module A is pulled in and redefines the symbol "_foo".

 When LINK encounters the redefinition while processing a library
 module, it assumes that the error might go away if you were to add the
 /NOE switch. This would be true if the symbols were defined like this
 as follows:

     FOO.OBJ:
         defines "_foo"
         calls "_libfunc"

     Module A (in XYZ.LIB):
         defines "_libfunc"
         calls "_foo"

     Module B ( in XYZ.LIB ):
         defines "_foo"

 The extended dictionary tells LINK to link modules A and B, even
 though module B should not be linked because "_foo" is already
 defined. In this case, the /NOE switch will eliminate the error.

 LINK cannot figure out when the error is due to the extended
 dictionary and when it is not; therefore, it assumes that the extended
 dictionary will cause a redefinition error when processing a library
 module.

 Please note that redefinitions not detected in some situations. For
 example, when the function 'printf' is redefined in a program module
 and the module is linked with SLIBCER.LIB without using the /NOE
 switch, LINK does not complain about the redefinition at all. LINK
 does not detect a redefinition because the module that defines printf
 in the library is not pulled in; thus, there is no redefinition.

 If your program module redefines a library function that is also
 called by other library functions used by your program, you will get a
 redefinition error. The extended dictionary specifies which library
 modules call routines in other library modules. Consider a
 "second-level" function to be any library function called by a library
 function in another module. For example, spawnve and _setargv are
 second-level functions because they are called by other library
 functions; printf is not. You can get a redefinition error only if you
 redefine a second-level library function called by some first-level
 routine being linked into your program.


 34. Producing an _TEXT Segment for Multiple Object Modules

 Product Version(s): 3.x 4.06 | 5.01.20 5.01.21
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER | S_C
 Last Modified:  6-APR-1989    ArticleIdent: Q43128

 In a map file, a <modulename>_TEXT will be produced for each logical
 code segment in your program. Since small and compact model programs
 have only one code segment, you only get one logical segment, _TEXT.
 Medium- and large-model programs, however, will have a separate
 logical segment for each object module in the program, and thus produce
 a <modulename>_TEXT for each logical segment.

 To generate a map file, use the /M option with LINK or the /Fm option
 with CL.

 The following is an example map file generated when compiling a
 program with two object modules in small-memory model:

  Start  Stop   Length Name                   Class
  00000H 016EAH 016EBH _TEXT                  CODE
  ...

 The following is an example map file generated when compiling the same
 program with two object modules in large-memory model:

  Start  Stop   Length Name                   Class
  00000H 0000DH 0000EH MAPL_TEXT              CODE
  0000EH 00023H 00016H MAP2_TEXT              CODE
  00024H 01B2CH 01B09H _TEXT                  CODE
  ...

 MAPL_TEXT and MAP2_TEXT come from the files MAPL.OBJ and MAP2.OBJ,
 respectively. The _TEXT is the Microsoft run-time library and any
 third-party libraries.



 35. LINK: Renaming Overlayed Executables Will Cause Problems

 Product Version(s): 5.01.21
 Operating System:   DOS
 Flags: ENDUSER | s_C s_Pascal h_FORTRAN
 Last Modified:  6-APR-1989    ArticleIdent: Q43139

 When the Microsoft linker creates an executable file with overlays,
 the name of that EXE is hard coded into the file for use by the overlay
 manager. The Microsoft linker only creates internal overlays, i.e.,
 rather than producing FOO.EXE, FOO1.OVL, and FOO2.OVL, the two
 overlays are contained in FOO.EXE.

 If the executable is renamed at any point after linking, the overlay
 manager will still use the hard-coded name found in the EXE to locate
 the overlays, and will fail with the following prompt:

    Cannot find <oldname>
    Please enter new program spec:

 In order to change the name of the executable without receiving this
 error, it must be relinked and given the new name at that time.


 36. LINK: Creating and Accessing _edata and _end

 Product Version(s): 3.X 4.06 | 5.01.20 5.01.21
 Operating System:   MS-DOS   | OS/2
 Flags: ENDUSER | s_c
 Last Modified:  6-APR-1989    ArticleIdent: Q43165

 LINK creates the two symbols _edata and _end when the LINK option
 /DOSSEG is used. If a program is compiled by a Microsoft high-level
 language compiler, or if an assembly program written in Microsoft MASM
 uses .DOSSEG directive, LINK uses this option automatically.

 LINK gives _edata the address of the beginning of BSS segment and
 gives _end the address of the end of BSS segment. Since the STACK
 segment is directly above the BSS segment, the address of _end also
 marks the lowest address of the STACK segment.

 To obtain the addresses for these two symbols, declare the following
 in your C program:

 unsigned char edata, end ;

 The addresses, &edata and &end, can now be used to locate _BSS and
 STACK. They can also be examined in CodeView. Modifying these two
 variables is not recommended.

 Note: The segment BSS referred to in this article actually includes
 the segment C_COMMON. However in a map file created by LINK, BSS and
 C_COMMON are listed as two separate segments.



 37. Linker Options /PADDATA and /PADCODE

 Product Version(s): 4.06
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC docerr
 Last Modified: 18-SEP-1989    ArticleIdent: Q44928

 Question:

 I ran the linker Version 4.06 that comes with the Microsoft QuickC
 Compiler Version 2.00 with the /help option as follows:

    LINK /HELP

 I noticed two switches for which I couldn't find documentation:
 /PADDATA and /PADCODE. What are these options for?

 Response:

 The /PADC[ODE]:padsize option causes LINK to add filler bytes to the
 end of each code module. The option is followed by a colon and the
 number of bytes to add. (Decimal radix is assumed, but you can specify
 special octal or hexadecimal numbers by using a C-language prefix.)
 Thus, the following adds an additional 256 bytes to each code module:

    /PADCODE:256

 The default size for code-module padding is 0 bytes.

 The /PADD[ATA]:padsize option performs a function similar to
 /PADCODE, except that it specifies padding for data segments (or data
 modules, if the program uses small or medium-memory models). Thus,
 the following adds an additional 32 bytes to each data module:

    /PADDATA:32

 The default size for data-segment padding is 16 bytes. Note that if
 you specify too large a value for padsize, you may exceed the 64K
 limitation on the size of the default data segment.

 These two options are quite useful when used in conjunction with
 QuickC Version 2.00's incremental linking option. Using them correctly
 increases the incremental linking speed of a program.

 These two options are documented on Page 64 in the update section of
 the Microsoft C Optimizing Compiler Version 5.10 "CodeView and
 Utilities, Microsoft Editor, Mixed-Language Programming Guide" manual.


 38. Linker Error L2013 May Be a Result of a Problem in MASM 5.10

 Product Version(s): 3.x 4.06 4.07 5.01.21 5.02 5.03 5.05
 Operating System:   MS-DOS
 Flags: ENDUSER | h_masm
 Last Modified: 27-DEC-1990    ArticleIdent: Q59894

 The error message for linker error L2013 is as follows:

    error L2013 LIDATA record too large
       pos: xxx Record type: 743C

 In the README.DOC file that comes with MASM version 5.10, Microsoft C
 version 5.10, and the "Microsoft FORTRAN CodeView and Utilities User's
 Guide" version 5.00 manual, the recommended course of action is to
 call Microsoft Product Support at (206) 637-7096.

 The error is a result of an invalid object module. This is a known
 problem in MASM 5.10. The most likely cause is a duplication of some
 large data item, such as a structure.

 The easiest workaround is to break up the duplication(s) into smaller
 parts.


 39. LINK 5.02 Should Not Be Used with ILINK 1.10

 Product Version(s): 5.02
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 30-AUG-1989    ArticleIdent: Q45536

 LINK Version 5.02, which comes as a secondary linker for QuickC 2.00,
 should not be used with ILINK Version 1.10, which also comes with
 QuickC 2.00.

 Inside the QuickC environment, this combination has caused problems
 with floating point-values being printed with printf. Outside of the
 environment, the same executable results in math error M6104.

 The source code below prints "FP = 0.00000" instead of "FP =
 5.020000". Running from the DOS prompt, in this case, produces the
 same results.

 Source Code
 -----------

     #include <stdio.h>

     void main( void )
     {
         float fp = 5.02F;

         printf( "FP = %f\n", fp );
     }

 LINK Version 4.06 should be used if ILINK is also to be used. If it is
 necessary to use Version 5.02 of the linker, incremental linking
 should be disabled from within the environment.

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


 40. Linker Errors L4013, L2048, and L4038: Overlaying in OS/2

 Product Version(s): 5.01.20 | 5.03
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | S_C H_Fortran
 Last Modified: 21-JUN-1989    ArticleIdent: Q45619

 The linker does not overlay files when linking with protected mode
 run-time libraries. If told to overlay a program that is being linked
 with a protected mode run-time library, the linker responds with one
 or more of the following errors:

    LINK : warning L4013: invalid option for new-format executable file
    ignored
    LINK : error L2048: Microsoft Overlay Manager module not found
    LINK : warning L4038: program has no starting address

 possibly followed by (in DOS):

    run-time error R6001
    - null pointer assignment

 or possibly followed by (in OS/2):

    A general protection (GP) fault. It may also go into an infinite
    loop after creating the temporary file (for large executables).

 The workaround is to create two versions of the executable, an
 overlayed DOS version and a non-overlayed OS/2 version.

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


 41. Link Error L1005: /PACKCODE: Packing Limit Exceeds 65,536

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 21-JUN-1989    ArticleIdent: Q45724

 The Microsoft Overlay Linker Version 3.65 presents the following error
 message when the /PACKCODE: switch is used with a value greater than
 65,536 (64K):

    Link Fatal Error L1005:

 No error message text is supplied, and the error cannot be referenced
 in the Microsoft C 5.10 "CodeView and Utilities, Microsoft Editor,
 Mixed-Language Programming Guide." The error message should read as
 follows:

    Link Fatal Error L1005: /PACKCODE: Packing Limit Exceeds 65,536

 The error is reported correctly by the Microsoft QuickC Linker Version
 4.06 and all 5.0x versions of the Microsoft Segmented-Executable
 Linker. It is correctly documented in the Version 2.00 "Microsoft
 QuickC Tool Kit," on Page 278, and on Page 373 of the Version 5.00
 "Microsoft FORTRAN, Microsoft CodeView and Utilities User's Guide"
 manual, as follows:

    The value supplied with the /PACKCODE option exceeds the limit of
    65,536 bytes.


 42. What the /HIGH and /DS Linker Options Do

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890607-19979
 Last Modified: 13-JUL-1989    ArticleIdent: Q46745

 Question:

 I would like information on the /HIGH and /DS options of the linker.
 Specifically, what changes are needed in the .EXE file to tell the
 loader to put it high?

 Response:

 Basically, these are hold-over features from DOS Version 1.00 and from
 the original Microsoft/IBM Pascal and FORTRAN Compilers -- they're of
 little or no use under DOS 2.00 and later. Specifically, programs
 linked with the /HIGH switch are allocated all of the memory in the
 machine and cannot release unneeded memory back to DOS; therefore, no
 other program can be loaded into memory.

 The /HIGH switch sets both the minalloc and maxalloc fields in the .EXE
 header to zero. This combination of values causes the loader to load
 the program in high memory.

 /DSALLOCATE (or /DS) causes DGROUP to be "shifted" upwards so that the
 high address in the group is always FFFFh. Offsets into DGROUP are
 adjusted appropriately.

 These switches are strictly incompatible with our current high-level
 languages -- the only possible use for them is in a MASM program.
 Microsoft doesn't recommend using them at all unless you know
 precisely what you're doing.

 There is good documentation on what the /HIGH and /DSALLOCATE switches
 do, as well as how the loader works, in the "MS-DOS Encyclopedia,"
 starting on Page 719. (This excellent reference manual is now less
 expensive and available in paperback).


 43. How Minimum Load Size Is Calculated

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# G890607-19979
 Last Modified: 13-JUL-1989    ArticleIdent: Q46774

 The MS-DOS program loader uses the following formula to calculate the
 number of 16-byte paragraphs to use when loading a program:

    TotPages * 20h - NumHeader + 10h + MaxAlloc

 The formula calculates the number of 16-byte paragraphs, unless
 there's not enough memory, in which case all the available memory is
 used. If there are not at least

    TotPages * 20h - NumHeader + 10h + MinAlloc

 paragraphs available, DOS cannot and will not load the program.

 The 20h is the size of a page in paragraphs, which is the size of a
 page (512 bytes) divided by the size of a paragraph (16 bytes).

 The 10h is the size in paragraphs of the 256-byte Program Segment
 Prefix that precedes all programs in memory.

 All of the values used in the formulae shown above are words (shown in
 the following) that are stored in standard Intel low-byte-first format
 in the .EXE file header:

    Value           Name used by EXEHDR             Offset in .EXE header
    -----           -------------------             ---------------------

    TotPages        Pages in file                   4 - 5
    NumHeader       Paragraphs in header            8 - 9
    MinAlloc        Extra paragraphs needed         0Ah - 0Bh
    MaxAlloc        Extra paragraphs wanted         0Ch - 0Dh

 For more information, refer to a good MS-DOS reference such as the
 "MS-DOS Encyclopedia."


 44. L1074 Name: Group Larger Than 64K Bytes

 Product Version(s): 4.06
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickC
 Last Modified: 24-JUL-1989    ArticleIdent: Q46996

 The Microsoft QuickC Compiler Version 2.00 returns the following
 linker error message when the size of DGROUP (the default data
 segment) exceeds 64K:

    L1074 name: group larger than 64K bytes

 This error is documented on Page 282 of the "Microsoft QuickC Tool
 Kit" manual as follows:

    The given group exceeds the limit of 65,536 bytes.

    Reduce the size of the group, or remove any unneeded segments from
    the group (refer to the map file for a listing of segments).

 There are four ways to resolve this data segment overflow when using
 QuickC:

 1. Reduce the stack size in order to reduce the size of DGROUP. In the
    environment this can be done in the Options.Make.Linker Flags menu.
    Outside the environment this can be done at compile time with the
    "/F hexnum" switch, where hexnum is the size of the requested stack
    in hexadecimal format. Outside the environment, at link time, this
    can be done with the "/ST:decnum" switch, where decnum is the size
    of the requested stack in decimal format.

 2. Declare data with the FAR keyword to move it out of DGROUP.

    Note: In the small and medium memory models the Microsoft run-time
    library functions can no longer be used with this data. You must
    copy this far to a near heap location, before you use the run-time
    routines on this data.

 3. Outside the environment, compile in the compact, large, or huge
    memory models with the "/GtX" switch, where X is a data threshold.
    All data items larger than X bytes are moved out of DGROUP into a
    far data segment.

 4. Reduce the amount of data declared in the program. In the compact,
    large, and huge memory models, try dynamically allocating space for
    the data. Memory can also be dynamically allocated outside DGROUP
    in the small and medium memory models by using _fmalloc() but, as
    stated in Number 2, the run-time library functions do not work with
    this data.

    Reduce the amount of string literals in this default data segment by
    reading from a data file at run time, or in C 5.00, by using the
    /Gt patch to allow string literals to be moved from the _CONST
    segment in DGROUP into a far segment.


 45. /CP:X Is Not Valid When Linking Protected-Mode Programs

 Product Version(s): 5.01.21 | 5.01.21
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 26-JUL-1989    ArticleIdent: Q47036

 Question:

 I cannot seem to get the /CPARMAXALLOC linker option to work when I
 link for OS/2 protected mode. When linking a real-mode application, it
 works correctly. Also, when I type "link /help" in protected mode, the
 output indicates that this is a valid option. However, when I try to
 use this option for a protected-mode application, the linker produces
 the following warning:

    LINK : warning L4013: invalid option for new-format executable file
                          ignored

 What am I doing wrong and what does this error message mean?

 Response:

 As documented on Page 27 in the update section of the Microsoft C
 Optimizing Compiler Version 5.10 "CodeView and Utilities, Microsoft
 Editor, Mixed-Language Programming Guide" manual, the /CPARMAXALLOC
 option is for real-mode applications only. The "link /help" indicates
 that this is a valid option because this option IS valid whenever
 you're linking real-mode applications, regardless of whether the
 linker is running under OS/2 or DOS. (By the same token, it is invalid
 when you're linking a protected-mode application, regardless of which
 operating system you're using.)

 This error message was omitted from the documentation. It indicates
 that one of the options that the linker was passed is invalid.

 This option is not supported in a protected-mode application because
 the functionality of it is done automatically by the linker.
 Protected-mode applications are not given a 64K default data segment;
 they are only allocated the space that they need. This is documented
 on Page 33 of the same section and manual listed above.


 46. Cannot Use Overlays in a Bound Application

 Product Version(s): 5.01.21 5.03 | 5.01.21 5.03
 Operating System:   MS-DOS       | OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1989    ArticleIdent: Q47104

 Question:

 How can I incorporate overlays into my bound application?

 Response:

 You cannot use overlays in a bound application. To bind an
 application, you must first have a runnable OS/2 executable; then, you
 use the BIND utility to make it run in both OS/2 and DOS. OS/2
 executables do not understand overlays so you cannot incorporate them
 into an OS/2 executable. Hence, you cannot use overlays in a bound
 program.


 47. Linker Error L1063 and Linking Over 1000 Object Modules

 Product Version(s): 5.01.21 5.03
 Operating System:   OS/2
 Flags: ENDUSER | S_C S_CodeView
 Last Modified: 16-AUG-1989    ArticleIdent: Q47931

 Question:

 When attempting to link a large OS/2 application consisting of over
 1500 object modules with C 5.10's Link 5.01.21 or FORTRAN 5.00's Link
 5.03 by using the options /co /map:2078 /noe /se:2078 /packcode, I get
 the link error "L1063 out of memory for CodeView information." Only
 one of the .C source files was compiled with /Zi. All were compiled
 with /AL. Linking without /co (CodeView information) successfully
 produces a 700K executable file (.EXE), but I need to do some
 debugging with CVP.

 What is the L1063 error, and how can I work around it?

 Response:

 Information on L1063 is not in the C 5.10 text files or documentation,
 but it is in Pascal 4.00's README.DOC and in FORTRAN 4.10's
 CVREADME.DOC as noted in another article in this knowledge base. The
 following reiterates the error message and its description:

    L1063 out of memory for CodeView information

    The linker was given too many object files with debug information,
    and the linker ran out of space to store it. Reduce the number of
    object files that have debug information.

 In this case, it is not the number of modules with CodeView
 information that is causing the problems exactly; it is the great
 number of modules and trying to link in any CodeView information.

 The following are ways to workaround this linker limitation:

 1. The most effective method is to demodularize your application. That
    is, put more functions into fewer .C source files.
 2. Reduce the linker option /se: value to as low as possible for the
    number of logical segments in the application.
 3. Link the object files from the current working directory. If you
    must use different directories for your .OBJs, make the pathnames
    as short as possible.


 48. Description of a Linker .MAP File

 Product Version(s): 3.60 3.61 3.64 3.65 5.01.20 5.01.21 5.03  | 5.01.20 5.01.
 Operating System:   MS-DOS                                    | OS/2
 Flags: ENDUSER | S_C S_PasCal H_FORTRAN
 Last Modified: 19-SEP-1989    ArticleIdent: Q47960

 A .MAP file generated by the linker is a listing of the addresses and
 names of a program, as follows:

    Logical Segments
    Groups (defined collections of logical segments)
    Public Symbols listed by name
    Public Symbols listed again by their relative address
    Entry Point address (first executable instruction)

 A linker .MAP file (with a .MAP file extension) contains the address,
 size, name, and class of logical code and data segments. (One or more
 logical segments of either code or data can be combined into a
 physical segment of either code or data, respectively, by the linker.)

 In DOS or real-mode OS/2, the addresses are 20-bit hex addresses that
 are RELATIVE to the beginning of the program's load image. In
 protected-mode OS/2, the hex addresses are in 32-bit segment
 selector:offset notation (16 bits for the segment selector and 16 bits
 for the offset) starting with segment selector 1.

 The _TEXT segment names of class CODE are the code in your object
 files. The various forms of near logical data segments are described
 in the DGROUP diagram, which you probably already have. (Briefly,
 _DATA is initialized near global data, _BSS is uninitialized near
 "static" data, C_COMMON is uninitialized near data, and CONST is for
 floating point constants. FAR_DATA and HUGE_DATA are global
 initialized far and huge data, respectively, and FAR_BSS is global
 unitialized far or huge data.)

 Next in the .MAP is the ORIGIN (address) and name of the defined
 groups of logical segments, notably DGROUP, which is used in our
 high-level languages for grouping many logical data segments into the
 "default" physical data segment. The name "default" data segment
 refers to the fact the the DS register will point to this segment by
 default so that offset (near) addressing can be used without loading
 the DS register. Groups allow multiple logical segments to be
 associated with the same starting address, so near (non-far) data in
 Microsoft high-level languages is addressed relative to DGROUP.

 Following the segment descriptions, under the heading of "Publics by
 Name", the names of Public symbols (i.e., global or extern functions,
 including numerous internal C library functions, and variables) are
 listed in ASCII order (capital letters first, then lowercase letters,
 and finally underscores) along with their hex relative segment:offset
 addresses (or segment selector:offset in protected-mode OS/2). Public
 symbols are then listed again, in order of their relative
 segment:offset addresses under the heading "Publics by Value".

 Only Public (e.g. global) symbols such as function and variable names
 appear in the .MAP. No "static" functions or data, "auto" storage
 class data (e.g. local function data), or data types are listed in the
 .MAP.

 A high-level language such as C creates many logical segments in
 DGROUP for "internal" (e.g. undocumented) purposes, calls numerous
 internal library functions, and refers to variables for the main
 program initialization and start-up code. C refers to additional
 initialization functions and variables for the library functions that
 your program explicitly calls, still more for floating point
 functions, as well as termination functions.

 To get an idea of the functions automatically linked in from the C
 library, generate and compare .MAP files for simple source modules
 such as foo(){} or main(){}, main(){puts("hi");}, and a small program
 that performs floating point arithmetic or calls a C library floating
 point math function that calls "fp..." routines.

 The "Program entry point" is the last item in the .MAP file. It refers
 to the segment:offset address of the first instruction of the program
 to be executed, relative to the lowest memory address in the .EXE load
 image.

 For more information on the entry point, please use the following
 query:

    .map file's program entry point


 49. Linker Can Indiscriminately Bind Different Types

 Product Version(s): 1.x 2.x 3.x 4.x 5.01 5.02 5.03 | 5.01
 Operating System:   MS-DOS                         | OS/2
 Flags: ENDUSER | S_C S_QuickC S_QuickASM S_Pascal S_QuickPas
 Last Modified:  2-AUG-1990    ArticleIdent: Q48204

 The object module format used by the Microsoft languages contains a
 record type that is used to bind symbol definitions to symbol
 references in other modules. This record is known as a "fixup." As
 defined by Intel, the fixup record type contains no information as to
 the type of data that is to be fixed up. Under certain circumstances,
 this can cause unexpected and undesired binding at link time. The code
 below demonstrates such an instance:

     /*----- FILE1.C -----*/

     void bar( void );

     void main( void )
     {
         bar();
     }

     /*----- FILE2.C -----*/

     int bar;

 These files both compile without error. When compiled for a model with
 a single code segment, linker error L2003 is produced saying that an
 intersegment self-relative fixup was attempted. If a multiple code
 segment model is used, no link errors are produced. Although a clean
 link can be obtained, the resultant EXE does not perform as expected
 due to the fact that the function reference of bar in FILE1.C has been
 bound to the integer definition of bar in FILE2.C.

 The linker has no way of determining the types of the reference to,
 and definition of, bar. This is a limitation of the object file
 format. If an include file was used to prototype bar and was then
 included in both files, the compiler could have detected the
 redefinition of bar.

 This information applies to all 1.x, 2.x, and 3.x versions of LINK
 including 3.60, 3.61, 3.64, and 3.65, as well as LINK Versions 4.06,
 4.07, 5.01, 5.02, and 5.03.


 50. Novell Network Software May Cause L1084 Error

 Product Version(s): 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER | h_fortran h_masm s_c s_pascal
 Last Modified: 23-JAN-1990    ArticleIdent: Q57304

 The resident software used to access a Novell network may cause the
 following error when linking large programs:

    L1084:  Cannot create temporary file

 This problem was observed with Netware versions 2.10 SFT and 2.15 of
 the Novell network software.


 51. Relationship between Map File Addresses and Location in Memory

 Product Version(s): 3.61 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1989    ArticleIdent: Q48241

 In situations where memory is very short or where CodeView interacts
 with your program, it is sometimes necessary to use the DEBUG.COM
 program supplied with DOS.

 Using DEBUG is more difficult than using SYMDEB or CodeView because
 DEBUG has no symbolic features. You must use the map produced by the
 /M option when you link with a standard DOS overlay linker (i.e., not
 a segmented executable linker) to locate specific parts of your
 program.

 However, since DOS relocates programs when it loads them, the
 addresses given in the map need conversion before you can use them.

 This conversion is simple: DOS adds the address of the start segment
 (defined below) to each segment address in the load map. The offsets
 never change from the values shown in the link map -- only the
 segments change.

 The start segment is the base address of the Program Segment Prefix
 (PSP) plus the size of the PSP in paragraphs. Since the PSP is always
 100h (256) bytes long, the size of the PSP is 10h paragraphs.

 Note: DOS puts the base segment address of the PSP in DS and in ES
 when a program begins execution.

 For example, assume that the link map says that the function _funct is
 at 0004:05A0 (all values in hex) and that the global variable _errno
 is at 0192:00E3. Suppose further that when the program is loaded into
 DEBUG, the DS and ES registers contain 2BA5 -- the segment address of
 the PSP. (Use the R command to display the values of the registers.)

 The start segment for loading the program will be 2BB5 -- the value of
 the PSP base address (2BA5) + 10h to allow for the 10h paragraph
 length of the PSP (100h bytes).

 Thus, the function _funct will be located as follows:

    0004:05A0   -- address of _funct in the link map
    2BB5        -- start segment address (PSP + 10h)
    ---------
    2BB9:05A0

 And _errno will be located as follows:

    0192:00E3   -- address of _funct in the link map
    2BB5        -- start segment address (PSP + 10h)
    ---------
    2D47:00E3

 Use this calculation on any address in the link map to find where the
 symbol is located in memory when actually loaded.

 The H (Hex Arithmetic) command in DEBUG can be helpful when performing
 these calculations, as can a hex calculator with constant feature.


 52. Warning L4014: /PACKDATA: Option Ignored for Real Mode

 Product Version(s): 4.06 4.07 5.02 5.03 | 5.02 5.03
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 21-SEP-1989    ArticleIdent: Q48839

 /PACKDATA is incorrectly listed as an available switch for LINK
 Versions 4.06 and 4.07. LINK Version 4.06 comes with the QuickC
 compiler, and LINK Version 4.07 comes with the QuickAssembler.

 The /PACKDATA option is valid ONLY for segmented-executable files --
 OS/2 or Windows; it has no meaning for DOS. Real mode executable means
 a DOS-only program. To use the /PACKDATA switch, create a .DEF file
 with at least the following statement:

    NAME    MyProtectModeProgram

 This switch is implemented in segmented-executable LINK Versions 5.02
 and later.


 53. /NOI Switch May Cause L2022 and L2029 in PM Programs

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 27-OCT-1989    ArticleIdent: Q49008

 I am compiling and linking a Presentation Manager (PM) program from
 Charles Petzold's "Programming the OS/2 Presentation Manager" and I
 get the following link errors:

    LINK : error L2022: ClientWndProc (alias ClientWndProc) : export
           undefined

         : error L2029 : 'ClientWndProc' : unresolved external

 I get the same errors when compiling WELCOME1.C from the companion
 disk to "Programming the OS/2 Presentation Manager."

 The /NOI switch instructs the linker to preserve case. If you are
 using the /NOI switch, the linker will generate these errors because
 EXPENTRY (the export entry point) is defined in OS2DEF.H as follows:

    #define EXPENTRY far pascal

 The "pascal" keyword instructs the compiler to use the left-to-right
 calling sequence for the functions that it modifies. The keyword also
 causes the conversion of the function's name to uppercase letters.

 All window procedures are defined as EXPENTRY. Thus, the name of your
 window procedure is converted to uppercase letters. In your .DEF, you
 export your window procedures as follows:

    EXPORTS         ClientWndProc

 Because of the /NOI switch, the linker does not view ClientWndProc and
 CLIENTWNDPROC as being equal. Consequently, you get the first error
 message "export undefined."

 The second error message is generated because ClientWndProc (mixed
 uppercase and lowercase letters) is not recognized as being defined,
 so the linker considers it an "unresolved external."

 Removing the /NOI switch from your link line corrects both errors.


 54. LINK 5.03 and Later Require EXETYPE WINDOWS in .DEF File

 Product Version(s): 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q49445

 Microsoft LINK (LINK.EXE) versions 5.03 and later require that the
 WINDOWS descriptor be placed in the EXETYPE section of your project's
 .DEF (definitions) file if you are developing a Windows' application.

 This marks a change from previous linkers' behavior, which would allow
 the programmer to fail in specifying the type of executable to be
 created, but still produce a Windows-compatible .EXE file. This
 failure is no longer acceptable to LINK Versions 5.03 and later.

 If you fail to inform the linker (via the .DEF file) that you are
 creating a Windows executable, the linker reaches completion but the
 resulting .EXE does not execute.

 To specify the executable type, you must create a .DEF file and submit
 this to the linker at link time. For example, if you had a project
 called WINTEST.C, you must modify WINTEST.DEF so that it contains the
 following line:

    EXETYPE   WINDOWS

 The default EXETYPE is OS/2, as stated in the "Microsoft FORTRAN,
 CodeView and Utilities User's Guide" packaged with FORTRAN Version
 5.00.

 For further information regarding the definitions file and other
 descriptors, consult Section 7, "Using Module-Definition Files," in
 the "CodeView and Utilities, Microsoft Editor, Mixed Language
 Programming Guide" (Update Section) for C 5.10.

 LINK Version 5.03 is shipped with the FORTRAN version 5.00 package.


 55. Long TMP Environment Variable Causes L1089

 Product Version(s): 5.03   | 5.03
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_fortran
 Last Modified:  6-DEC-1989    ArticleIdent: Q48869

 L1089 occurs when the LINK Utility Version 5.03 is called from FORTRAN
 Version 5.00 and the TMP environment variable is set to a long
 pathname.

 Normal troubleshooting indicates that the TMP variable is corrupt, but
 this is not the case. It seems that the temporary filename is being
 truncated.

 The following sequence produces the error if the subdirectory
 D:\COMPILER\FORTRAN5\TMP\ already exists:

 SET TMP=d:\compiler\fortran5\tmp
 fl sieve.for

 LINK : fatal error L1089: D:\COMPILER\FORTRAN5\TMP\000054l
 : cannot open response file

 This problem occurs in FORTRAN 5.00 and Link 5.03.


 56. L2041: Stack Plus Data Exceeds 64K -- Documentation Supplement

 Product Version(s): 3.65 4.06 | 5.01.21
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER  | s_pascal h_fortran h_masm s_c s_quickc s_quickasm s_error d
 Last Modified: 30-NOV-1989    ArticleIdent: Q50130

 The following indicates that there is more than 64K of stack and data
 to be put into the 64K DGROUP (default data segment):

    L2041    stack plus data exceeds 64K

             The combined size of the program stack segment plus DGROUP
             was greater than 64K; as a result, the program will not
             load up correctly.

 To correct this problem, do the following:

 1. If the file(s) was compiled with C 5.00, a large amount of string
    literal data in the program may cause this error. Unlike C 5.10,
    5.00 cannot move string literals out of DGROUP with the /Gt option.
    This problem can be corrected with the "C 5.00 /Gt Fix" application
    note, which is available from Microsoft Product Support Services by
    calling (206) 454-2030.

 2. Reduce the stack size.

 3. Use a large data model (compact, large, or huge). Try applying the
    /Gt compilation option to lower the threshold.

 4. Use the FAR keyword to move data out of DGROUP.

 This error is documented in "Linker Error Messages" in the "Microsoft
 QuickC Compiler for IBM Personal Computers and Compatibles
 Programmer's Guide," Section D.4, Page 374. It is also in the file
 ERRMSG.DOC on Compiler Disk 1 for Microsoft C Version 5.10, on the
 Setup disk for Microsoft C Version 5.00, in the file README.DOC on
 Disk 1 for Microsoft Macro Assembler Version 5.10, and in the file
 CVREADME.DOC on the CodeView for MS-DOS disk for Microsoft FORTRAN
 Version 4.10. It is not found in the "CodeView and Utilities,
 Microsoft Editor, Mixed-Language Programming Guide" manual.

 Nonfatal errors indicate problems in the executable file. LINK
 produces the executable file. Nonfatal error messages have the
 following format:

    location : error L2xxx: messagetext

 In these messages, location is the input file associated with the
 error, or LINK if there is no input file. If the input file is an .OBJ
 or .LIB file and has a module name, the module name is enclosed in
 parentheses.

 Additional reference words: appnote


 57. Link Error L2028 Caused by HEAPSIZE, STACKSIZE and DGROUP Size

 Product Version(s): 5.01.21 | 5.01.21
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-JUL-1990    ArticleIdent: Q49935

 The error L2028 "Automatic data segment plus heap exceeds 64K" was
 omitted from the linker error messages in the "CodeView and Utilities,
 Microsoft Editor, Mixed-Language Programming Guide" manual that
 accompanies Microsoft C 5.10. This error occurs when the stack and
 data plus the near heap exceeds 64K. The near heap size is set with
 the HEAPSIZE option in the .DEF file.

 The error can be corrected by using one of the following methods:

 1. Reducing the amount of data in the default data segment.

 2. Decreasing the stack size that was set by /ST:xxxx at the link line
    or by the STACKSIZE option in the .DEF file.

 3. Decreasing the amount of near heap that is being requested with the
    HEAPSIZE option in .DEF file.


 58. Specifying Link Options with "-" Causes L4046, L1083, or U1013

 Product Version(s): 5.01.21
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 10-NOV-1989    ArticleIdent: Q50333

 LINK command line switches must begin with the linker's option
 character, the forward slash (/). While it is valid to begin
 compilation switches with a dash (-), the same is not true for the
 linker.

 Code Example
 ------------

 #--------------------
 # test make file
 #--------------------

 test.obj : test.c test.h
      cl -c -Zi -G2sw -W3 test.c

 test.exe : test.obj test.def
      link test, -CO -align:16, NUL, os2, test

 You type:
         make test

 Microsoft (R) Program Maintenance Utility  Version 4.07
 Copyright (C) Microsoft Corp 1984-1988. All rights reserved.

   link test, -CO -align:16, NUL, os2, test

 Microsoft (R) Segmented-Executable Linker  Version 5.01.21
 Copyright (C) Microsoft Corp 1984-1988.  All rights reserved.

 TEST.DEF(12) : warning L4046: module name different from output file name
 LINK : fatal error L1083: cannot open run file
 test(16) : fatal error U1013: 'link test, -CO -align:16, NUL, os2, test'
          : error 2


 59. /PACKCODE Incompatible with IOPL Segments with LINK 5.01.21

 Product Version(s): 5.01.21
 Operating System:   OS/2
 Flags: ENDUSER | S_C
 Last Modified: 10-NOV-1989    ArticleIdent: Q50702

 LINK Version 5.01.21 does not support the combination of using the
 /PACKCODE switch and having code segments declared as IOPL (i.e., as
 having I/O privilege).

 When combining segments as directed by the /PACKCODE option, LINK
 5.01.21 will combine the IOPL segment(s) with other segments that do
 not have I/O privilege. The result is an invalid executable that
 returns the system error SYS1059 when it is invoked.

 The lack of ability to combine these options is a limitation of this
 particular linker version. LINK Version 5.03 allows the combination of
 /PACKCODE and IOPL segments without a problem.


 60. LINK : Warning L4011 Caused By Invalid /PACKCODE Group Size

 Product Version(s): 3.65 4.06 4.07 5.01.21 5.03 | 5.01.21 5.03
 Operating System:   MS-DOS                      | OS/2
 Flags: ENDUSER | S_C S_QUICKC S_QUICKASM S_PASCAL DOCERR
 Last Modified: 10-NOV-1989    ArticleIdent: Q50705

 The LINK code packing option, /PAC[:n], groups together neighboring
 code segments into the same segment of maximum size "n" bytes. The
 results of using /PAC will only be reliable when "n" is in the range
 of 0 to 65500. Page 278 of the "Microsoft C 5.1 CodeView and
 Utilities" reference manual states the default value for "n" is 65530.
 This is incorrect.

 The linkers from the following products were tested with the /PAC
 option to determine their behavior with various values of "n":

    C 5.10
    Pascal 4.00
    FORTRAN 5.00
    QuickC 1.01
    QuickC 2.00
    QuickASM 2.01

 Note: Linkers were checked in both real and protected mode where
 appropriate.

 The following table shows the acceptable values that can be used with
 the /PAC[:n] option and what error message will occur when the value
 of "n" is out of range:

 ----------------------------------------------------------------------
 Value of "n"      LINK Vers.   Error Message
 ----------------------------------------------------------------------
 0 to 65500        3.65         No Errors/Warnings
                   4.06         No Errors/Warnings
                   4.07         No Errors/Warnings
                   5.01.21      No Errors/Warnings
                   5.03         No Errors/Warnings

 65501 to 65536    3.65         LINK : warning L4011:
                   4.06         LINK : warning L4011: PACKCODE value
                                exceeding 65500 unreliable
                   4.07         (same as above)
                   5.01.21      (same as above)
                   5.03         (same as above)

 65537 and over    3.65         LINK : fatal error L1005:
                   4.06         LINK : fatal error L1005: packing limit
                                exceeds 65536 bytes
                   4.07         (same as above)
                   5.01.21      (same as above)
                   5.03         (same as above)
 ----------------------------------------------------------------------

 Note : With LINK Version 5.03 and later, the /PAC option has been
 changed to /PACKC to differentiate /PACKC[ODE] from the new
 /PACKD[ATA] option.


 61. How and When to Specify Stack Size (Clarification)

 Product Version(s): 3.65 4.06 4.07 | 5.01.21
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50950

 Question:

 When I want to specify a certain stack size for a program, should I
 use the /F compiler option, the /ST linker option, or both?

 Response:

 This depends on how you are compiling and linking. If you using the CL
 command to compile and link, the /F compiler option is all that is
 necessary. This option will pass the correct size of the stack to the
 linker.

 On the other hand, if you are invoking the compiler and the linker
 separately (as in a make file), the /ST link option can be used to get
 the desired stack size. The /ST link option is documented on Page 123
 of the "Microsoft C Optimizing Compiler User's Guide."

 No stack information is stored in the object module. Therefore, using
 the /F and /c (compile only) options together and then invoking link
 separately will not generate the desired stack size. The /F compile
 option is documented on Page 102 of the "Microsoft C Optimizing
 Compiler User's Guide."


 62. Linking Method May Result in Unexpected Increase in .EXE Size

 Product Version(s): 3.x 4.06 4.07 5.01.21 5.03 | 5.01.21 5.03
 Operating System:   MS-DOS                     | OS/2
 Flags: ENDUSER |
 Last Modified: 21-FEB-1990    ArticleIdent: Q58689

 Question:

 When my program is linked in the following manner

    link  file1.obj file2.obj library.lib;

 the resulting executable file is much larger than if the program is
 linked this way:

    link  file1.obj file2.obj,,,library.lib;

 What causes the difference in size?

 Response:

 This is expected behavior, the difference in size is due to the
 difference in linking method.

 The first method has the library name in the same field as the object
 files. Libraries entered in this field are called "load libraries" as
 opposed to "regular libraries." Link automatically links in every
 object module in a load library; it does not search for unresolved
 external references first.

 The effect of using a load library is exactly the same as if you had
 entered all the names of the library's object modules as separate
 object files on the link command line. This feature is useful if you
 are developing software using many modules and want to avoid having to
 retype each module on the LINK command line.

 With the second method, LINK links in only the objects from the
 library that are required for program execution.

 Please see documentation on LINK, such as Section 12.1.2 of the
 Microsoft C 5.1 "CodeView and Utilities Software Development Tools for
 the MS-DOS Operating System" manual (Page 257) for more information.


 63. Linker Uses Library Sequence to Resolve External References

 Product Version(s):
 Operating System:   1.x 2.x 3.x 4.06 4.07 5.01.21 5.02 5.03 | 5.01.21 5.02 5.
 Flags: MS-DOS                                  | OS/2
 Last Modified: 26-FEB-1990    ArticleIdent: Q57706
 ENDUSER |

 "The MS-DOS Encyclopedia," Pages 407 and 408, states the following:

    When a public symbol required to resolve an external reference is
    declared more than once among the object modules in the input
    libraries, LINK uses the first object module that contains the
    public symbol. This means that the actual executable code or data
    associated with a particular external reference can be varied by
    changing the order in which LINK processes its input libraries...

    Each individual library is searched repeatedly (from first library
    to last, in the sequence in which they are input to LINK) until no
    further external references can be resolved.

 The following simple case demonstrates the concept:

    Module MAIN   Library A     Library B1    Library C     Library B2
    +---------+   +----------+  +----------+  +----------+  +----------+
    | calls A |   | contains |  | contains |  | contains |  | contains |
    +---------+   |    A,    |  |    B     |  |    C,    |  |    B     |
                  | calls  C |  +----------+  | calls  B |  +----------+
                  +----------+                +----------+

 The linker determines which copy of Module B to use depending on the
 library sequence. For example, when you link with the following, the
 Module B from Library B2 is selected:

    LINK MAIN,,,A B1 C B2;

 The linker looks first in Library C and, unable to resolve the
 reference, proceeds to the next library, B2. If the linker is still
 unable to resolve the reference, it continues searching at Library A.

 A slightly more complex case, when Library A contains both Module A
 and Module B, produces different results, as shown below:

    Module MAIN   Library A     (remove B1)   Library C     Library B2
    +---------+   +----------+                +----------+  +----------+
    | calls A |   | contains |                | contains |  | contains |
    +---------+   |    A,    |                |    C,    |  |    B     |
                  | calls  C |                | calls  B |  +----------+
                  +----------+                +----------+
                  | contains |
                  |    B     |
                  +----------+

 Link with "LINK MAIN,,,A C B2;". In this case, Module B from Library A
 is selected.

 Although the linker always follows the same rules for resolution, it
 gets more difficult to determine which version of a module will be
 selected in more complex cases. When feasible, you can avoid this
 problem by putting your selected versions in an .OBJ instead of an
 .LIB. The linker uses any .OBJs to resolve references before it
 uses libraries.

 For more information, refer to "The MS-DOS Encyclopedia," Article 20:
 "The Microsoft Object Linker," in the "Object Module Order" section,
 Pages 703-706.


 64. Calling Overlaid Functions Through Pointers Not Supported

 Product Version(s): 1.x 2.x 3.x 4.06 4.07 5.01.21 5.02 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_QuickC
 Last Modified: 30-JAN-1990    ArticleIdent: Q58098

 LINK does not support using function pointers for calling functions in
 overlays unless the function is being called from within the same
 overlay. If an overlaid function is being called from the root or from
 a different overlay, then the call must not be made through a pointer.

 LINK cannot support calling overlaid functions indirectly through
 pointers because the address of the indirect function is determined at
 load time.

 In a program with overlays, a normal function call (that is, not a
 call through a pointer) is recognized by the linker and an interrupt
 call is placed into the .EXE in place of the function call. When the
 function is called at run time, the interrupt directs control to the
 overlay manager. The overlay manager checks whether the right overlay
 is loaded into memory, loads it if necessary, and calls the function.
 Because there is a fixup record in the .OBJ for the function call, the
 linker can set everything up correctly.

 On the other hand, with a function pointer, the compiler creates a
 fixup record for the address that the pointer references. However,
 there is no indication in the fixup record that this address is for a
 function. Therefore, if you link the function in as an overlay, the
 linker does not insert a call to the overlay manager and instead does
 a standard fixup.

 As a result, if you indirectly call a function located in a not-as-yet
 loaded overlay, the overlay does not get loaded. Nevertheless, control
 is still transferred to the address at which the function is thought
 to reside, which can only mean disaster for the executing program.


 65. /PAU Linker Option Doesn't Function in Some Versions of LINK

 Product Version(s): 3.61 3.65 3.69 5.01.20 5.05 | 5.01.20 5.05
 Operating System:   MS-DOS                      | OS/2
 Flags: ENDUSER |
 Last Modified: 21-FEB-1990    ArticleIdent: Q58781

 The /PAU (PAUSE) linker option tells LINK to pause in the link session
 and display a message before it writes the executable file to disk,
 allowing you to insert a new disk on which to store the executable
 file.

 In Microsoft LINK.EXE Versions 3.61, 3.65, 3.69, 5.01.20, and 5.05,
 the /PAU linker option does not pause the link session.

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

 In versions where the /PAU linker option functions correctly, LINK
 displays the following message before it creates the executable file:

    About to generate .EXE file
    Change diskette in drive ___ and press <ENTER>

 LINK resumes processing after the ENTER key is pressed.


 66. /INC and Overlays Are Not Supported at the Same Time

 Product Version(s): 5.01.20 5.01.21 5.02 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER | docsup
 Last Modified: 15-MAY-1990    ArticleIdent: Q59279

 LINK.EXE does not support the use of /INCREMENTAL (or /INC) switch and
 overlays at the same time. This is because ILINK.EXE, which is invoked
 by the /INC option, does not support overlays. One of the two
 operations is ignored.

 The linker produces a working executable file, but one of the
 following WARNING messages may be produced:

    L4013: Overlays: option ignored for segmented-executable file
    L4014: /INCREMENTAL : Option ignored for realmode executable file

 If no warning message is produced, the linker takes an unpredictable
 path. If this is the case, the executable file that is produced could
 be corrupted and should NOT be relied upon.


 67. Incomplete EXPORTS List May Cause L2022 and L2029

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-MAR-1990    ArticleIdent: Q59385

 Compiling and linking a Windows program and receiving the following
 two link errors can be caused by an incomplete EXPORTS list:

    LINK : error L2022: ProcedureName : export undefined
    LINK : error L2029: 'ProcedureName' : unresolved external

 Windows programming involves the creation of a .DEF (definitions)
 file. All Windows procedures to be exported must be listed in this
 file. The following is an example:

    EXPORTS     ProcedureName

 When this list is incomplete, the L2022 error is generated. The L2029
 error can be generated if the case of the EXPORT line doesn't match
 the case of the actual function.

 Listing all procedures to be exported in the .DEF file prevents both
 of these errors.

 Note: These errors can also occur with Presentation Manager programs
 or programs that use DLLs under OS/2.


 68. Why the /HIGH Switch Is Not Used with High-Level Languages

 Product Version(s): 3.65
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 15-MAR-1990    ArticleIdent: Q59535

 The linker option /HIGH is used with assembly language programs to
 load an .EXE file as high as possible in memory. Without the /HIGH
 option, LINK places the .EXE file as low as possible.

 /HIGH is not used with high-level languages because it prohibits the
 use of dynamic memory allocation by the program. Furthermore, C
 run-time start-up code specifies /DOSSEG, which forces low load and
 Microsoft run-time segment layout.

 When a program is linked with /HIGH, MS-DOS loads the program at the
 highest possible memory location available, usually 0xFFF0. All memory
 between the program's segments (which are high) and the program's PSP
 (which is low) is now considered program RAM, owned by the program.
 You can no longer allocate or free that memory.

 Therefore, calls to routines such as malloc() and free() fail. This
 causes problems for the following reasons:

 1. Some memory is dynamically allocated during function calls from
    high-level languages.

 2. The memory structure required by Microsoft high-level languages for
    tracking used/freed memory is not available.

 You can use /HIGH if you write your own start-up code, but your
 programs cannot call most of the routines from the C run-time library.

 The only reason /HIGH is still available to the linker is that early
 versions of Microsoft FORTRAN and Microsoft Pascal generated code that
 had to be linked with /DSALLOCATE, which relocates all addresses
 within DGROUP in such a way that the last byte in the group has the
 offset 0xFFFF. The /HIGH switch is used in conjunction with the
 /DS(ALLOCATE) switch.

 For more information, search the knowledge base with the following
 query:

    S_LINK and /HIGH and /DS

 You can also read the section "Using the /HIGH and /DSALLOCATE
 Switches" on Page 719 ff in the "MS-DOS Encyclopedia."


 69. OS/2 Module Definition File Syntax

 Product Version(s): 5.01.21 5.02 5.03 5.05
 Operating System:   OS/2
 Flags: ENDUSER | S_C
 Last Modified: 16-MAR-1990    ArticleIdent: Q59536

 The following is extracted from Ray Duncan's "Advanced OS/2
 Programming," Page 737:

    Module definition (DEF) files are simple ASCII text files that are
    interpreted by the linker during the construction of an application
    program, dynlink library, or device driver. The directives in DEF
    files cause information to be built into the executable file's
    header, which is later interpreted by the system when the program,
    library, or driver is loaded.

    Enter all DEF file directives and keywords in uppercase letters.
    File, segment, group, and procedure names can be lowercase or
    uppercase. Lines beginning with a semicolon (;) are treated as
    comments.

    Figure E-1. DEF file directives documented in Appendix E
    --------------------------------------------------------

    CODE        Assigns characteristics to code segments
    DATA        Assigns characteristics to data segments
    DESCRIPTION Embeds text in executable file
    EXETYPE     Specifies host operating system
    EXPORTS     Names functions exported for dynamic linking by other
                programs
    HEAPSIZE    Specifies initial size of local heap (C programs only)
    IMPORTS     Names functions that will be dynamically linked at load
                time
    LIBRARY     Builds dynlink library or device driver
    NAME        Builds application program
    OLD         Specifies ordinal compatibility with previous version of
                dynlink library
    PROTMODE    Flags file as executable in protected mode only
    REALMODE    Allows file to be executed in real mode
    SEGMENTS    Assigns characteristics to selected segments
    STACKSIZE   Specifies size of stack used by primary thread
    STUB        Embeds MS-DOS-compatible program in new executable file

 For further information, refer to Appendix E, Module Definition File
 Syntax, in "Advanced OS/2 Programming" or Chapter 19, Using Module-
 Definition Files, in the "Microsoft FORTRAN CodeView and Utilities
 User's Guide," packaged with FORTRAN Version 5.00.


 70. Linker Error L4047 May Be Benign

 Product Version(s): 5.10    | 5.10
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q59936

 The following linker error may be a benign error if it occurs with an
 application that links with the C Version 6.00 start-up code:

    L4047 - Multiple code segments in module of overlayed program
            incompatible with /CO

 This is a new error for LINK Version 5.10 and is to be expected.

 If an application is built with the C Version 6.00 run-time library,
 there is a second segment to hold floating-point math routines. This
 segment (EMULATOR_TEXT) does not have any CodeView information in it.
 However, from the linker's perspective, the extra segment MAY be an
 error and it is warning the user of such. In this case, it is a benign
 warning message.


 71. NODATA and pwords Parameters Reversed in EXPORT Statement Docs

 Product Version(s): 5.01.21 5.02 5.03 5.05 5.10 | 5.01.21 5.02 5.03 5.05 5.10
 Operating System:   MS-DOS                      | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-MAY-1990    ArticleIdent: Q61605

 The EXPORT statement used in module definition (.DEF) files is
 incorrectly documented in several places with the last two parameters
 reversed. The "pwords" parameter should be the last parameter, but it
 is listed second from the end. The "NODATA" parameter is listed last,
 but should be second from the end. The correct EXPORT statement syntax
 is as follows:

    entryname [=internalname] [@ord[RESIDENTNAME]] [NODATA] [pwords]

 Note that the "pwords" parameter is listed as "iopl-parmwords" in some
 of the documentation.

 The documentation with the incorrect EXPORT statement syntax with
 reversed parameters is as follows:

 - The C version 6.00 online help for LINK under the EXPORT statement
   syntax

 - On Page 334 of "The Microsoft CodeView and Utilities User's
   Guide" for version 2.30 in Section 19.9, "The EXPORTS
   Statement" (shipped with FORTRAN 5.00 and BASIC PDS 7.00)

 - On Page Update-52 of "The Microsoft CodeView and Utilities
   Update" for version 2.20 in Section 7.8, "The EXPORTS
   Statement" (shipped with C 5.10, MASM 5.10, and Pascal 4.00)


 72. Fatal /nologo and /e Switch Interaction

 Product Version(s): 1.20   | 1.20
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.20
 Last Modified: 22-JUN-1990    ArticleIdent: Q62375

 Using the /nologo switch in conjunction with /e switch can cause ILINK
 version 1.20 to fail. The problem will occur when an incremental link
 cannot be performed and the command specified by the /e switch is
 performed instead. If the /e switch is preceded anywhere on the
 command line by /nologo, then the link will fail.

 For example, the following command line

     ILINK /nologo /e "link hello;" hello.exe

 where hello.obj exists but hello.exe doesn't, will produce the
 following messages:

    Microsoft (R) Segmented-Executable Linker  Version 5.10
    Copyright (C) Microsoft Corp 1984-1990.  All rights reserved.

    LINK : fatal error L1089:  : cannot open response file
    ILINK : warning L4252: file '/e.exe' does not exist
    ILINK : performing full link
    ILINK : fatal error L1233: 'link' returned 2

 Placing the /nologo switch after the /e switch on the command line
 will alleviate the problem.

 Microsoft has confirmed this to be a problem with LINK version 1.20.
 We are researching this problem and will post new information here as
 it becomes available.


 73. L4050 Incorrectly Documented in Online Help

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr buglist5.10 S_PWB
 Last Modified: 24-JUL-1990    ArticleIdent: Q63235

 When linking a very small program with /EXEPACK, Microsoft LINKer
 version 5.10 sometimes gives the following error message:

    LINK: warning L4050: file not suitable for /EXEPACK; relink without

 The online Help documentation returns the following incorrect
 information:

    LINK warning L4050

    too many public symbols for sorting

    The linker uses the stack and all available memory in the near
    heap to sort public symbols for the /MAP option. If the number of
    public symbols exceeds the space available for them, this warning
    is issued and the symbols are not sorted in the map file but are
    listed in an arbitrary order.

    Reduce the number of symbols.

 The correct documentation for this error (except the number) is as
 follows and can be found in the online Help under L1114:

    Fatal LINK error L1114

    file not suitable for /EXEPACK; relink without

    For the linked program, the size of the packed load image plus
    packing overhead was larger than that of the unpacked load image.

    Relink without the /EXEPACK option.

 Because of its noncritical nature, this LINKer error was changed from
 its previous status of a fatal error to a simple warning in LINK
 version 5.10. The warning associated with L4050 in earlier versions of
 the LINKer will rarely appear in LINK 5.10, but if it does, it will
 have the number L4070.



 74. Parenthesis in Filename May Cause L1027: Unmatched Parenthesis

 Product Version(s): 3.x 4.06 4.07 5.01.21 5.03 5.05 5.10 | 5.01.21 5.03 5.05
 Operating System:   MS-DOS                               | OS/2
 Flags: ENDUSER |
 Last Modified: 10-JUL-1990    ArticleIdent: Q63624

 When linking object files into executable programs, the error L1027:
 "Unmatched left/right parenthesis" may be incorrectly generated for
 files that contain a parenthesis in the filename. This will only occur
 when the object module is in the current directory and either of the
 following conditions is true:

 1. If the object module being linked has a left parenthesis as the
    first character in its name, but NOT a right parenthesis as the last
    character.

 2. If an object filename has a right parenthesis as the last
    character in the name, but NOT a left parenthesis as the first.

 If the object module is NOT in the current directory, then the L1027
 error will occur only if the second condition above is true.

 This information applies to all versions of LINK.EXE that support
 overlays.

 Normally, parentheses are put around the names of one or more object
 modules when linking to inform LINK that the enclosed modules are to
 be in an overlay. Therefore, if a left (or right) parenthesis comes
 immediately before (or after) the name of an object module, LINK will
 expect a right (or left) parenthesis immediately after (or before) the
 name. If the parentheses do not match, a fatal L1027 error will be
 generated.

 For example, the following LINK command line causes an "Unmatched left
 parenthesis" error when the object module ABC.OBJ is in the current
 directory:

    link (abc;

 However, if ABC.OBJ is in a subdirectory, then the parenthesis is
 embedded in the middle of the path/filename string and no error is
 generated, as shown below:

    link temp\(abc;

 For the same reason, a file ABC).OBJ will NOT give an error if linked
 with the following line:

    link abc).obj;

 On the other hand, leaving off the .OBJ extension will result in the
 L1027 error:

    link abc);

 By the same reasoning, the placement of a left or right parenthesis in
 the middle of an object filename does not cause an error. The
 following three LINK lines all work correctly:

    link a(bc;
    link a()bc;
    link a)bc;


 75. ILINK 1.20 and 1.21 Are Not Backwards Compatible

 Product Version(s): 1.20 1.21 | 1.20 1.21
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 24-OCT-1990    ArticleIdent: Q65817

 Using ILINK version 1.20 or 1.21, after doing a full link using a
 bound linker earlier than version 5.10 or a DOS linker earlier than
 version 4.10, causes the following message:

    ILINK : warning L4267: invalid .ILK file
    ILINK : performing full link

 If you use the ILINK version that came with the linker you are using,
 the .ILK file will be recognized correctly. ILINK versions 1.20 and
 1.21 are not "backwards compatible" and will not work correctly with
 earlier .ILK files.


 76. Unexpected DOS Error: 14 Generated by Using /INC

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | s_quickc s_c
 Last Modified: 24-OCT-1990    ArticleIdent: Q66055

 Programs linked with the /INC (Prepare for Incremental Link) switch
 cause the following error if the program is executed using the
 Microsoft Windows version 3.00 Run command:

    Unexpected DOS error: 14.

 The Run command is located on the File menu in both the Windows
 Program Manager and the File Manager. If the program is run from a
 prompt in real DOS or in a DOS session of Windows 3.00, it executes
 properly.

 While this seems like a problem with the Microsoft Linker, Windows 3.0
 is actually at fault here. The use of the /INC switch causes the
 linker to create a segmented executable. When Windows attempts to run
 this .exe, it fails to recognize that it is a full screen application
 (ie: not a windows app) and subsequently tries to execute it as a
 Windows application. This bug has been entered into the Windows bug
 database and should be fixed in a future release.

 Note: This may appear to be a problem with QuickC and/or C version
 6.00 if the incremental link option is turned on. In fact, it is a
 linking issue, not a compiler issue.

 To workaround this problem, turn off the /INC switch.


 77. Response Filename Cannot Exceed 32 Characters

 Product Version(s): 5.01.21 5.03 5.05 | 5.01.21 5.03 5.05
 Operating System:   MS-DOS            | OS/2
 Flags: ENDUSER | buglist5.01.21 buglist5.03 buglist5.05 fixlist5.10
 Last Modified: 12-NOV-1990    ArticleIdent: Q66698

 When using a complete path specification for a response file with
 LINK.EXE versions 5.01.21, 5.03, and 5.05, there is a limit of 32
 characters that cannot be exceeded. The following example illustrates
 this:

    LINK @d:\c600\files\project\test\myfile.lnk

 This will fail with the following error:

    LINK : Fatal error L1089 : D:\C600\FILES\PROJECT\TEST\MYFIL :
         cannot open response file

 In LINK version 5.10, this limit has been increased to 255 characters.


 78. Linker Does Not Search Specified Drive for Libraries

 Product Version(s): 5.01.21 5.03 5.05 5.10 5.11  | 5.01.21 5.03 5.05 5.10 5.1
 Operating System:   MS-DOS                       | OS/2
 Flags: ENDUSER | buglist5.01.21 buglist5.03 buglist5.05 buglist5.10 buglist5.
 Last Modified: 12-NOV-1990    ArticleIdent: Q66699

 A library name can be embedded into an .OBJ module for the linker to
 search to resolve external references. This library name can either be
 the library name itself or the full path to the library. In the case
 of the full path to the library, the linker cannot handle a drive
 specifier.

 For example, with Microsoft C, the #pragma comment command is used to
 specify the library. If the following line is used

    #pragma comment (lib, "c:\C600\LIB\graphics.lib")

 the compiler will add a COMENT record to the .OBJ instructing the
 linker to search the C600\LIB subdirectory on drive C for the
 GRAPHICS.LIB library.

 The problem is that the linker will not search drive C but will
 instead search the default drive. When the library and/or path is not
 found, it will prompt for the path to the library. This is an error.

 Microsoft has confirmed this to be a problem in the Segmented Linker
 versions 5.01.21, 5.03, 5.05, 5.10, and 5.11. We are researching this
 problem and will post new information here as it becomes available.


 79. L2002 When Creating a Dynamic Link Library

 Product Version(s): 5.10 5.11
 Operating System:   OS/2
 Flags: ENDUSER | buglist5.10 buglist5.11
 Last Modified:  4-DEC-1990    ArticleIdent: Q67004

 The code sample below produces the following error when compiled and
 linked with the following switches:

 cl /c /Gs /Alfu /ML foo.c

 link foo.obj, foo.dll,,, foo.def;

 Error
 -----

    L2002: fix-up overflow at 2 in segment FOO_TEXT
     frm seg _DATA, tgt seg _DATA, tgt offset 0

 This error is produced when creating a dynamic link library and
 specifying _loadds on function entry (either with the /Au switch or
 the _loadds keyword). If each segment that comprises the default data
 segment is of zero length, the linker will return this error. In
 earlier linkers, the error wasn't generated.

 The following are three possible workarounds:

 1. If the function does not contain any static data, compile with the
    option /Aw (DS not reloaded on function entry) and/or remove the
    _loadds keyword from the function declaration.

 2. Turn on stack checking (compile without /Gs option).

 3. Declare data so at least one of the segments in DGROUP is not zero
    length.

    a. For _DATA, declare initialized global or static data.

    b. For _CONST, declare a constant in the program.

    c. For _BSS, declare uninitialized static data.

 Microsoft has confirmed this to be a problem in versions 5.10 and
 5.11. We are researching this problem and will post new information
 here as it becomes available.

 Sample Code
 -----------

 void foo(int i)
 {
    char c;

    c=i;
 }


 80. NOF Is Default for LINK, Not /F as C "Reference" States

 Product Version(s): 5.10   | 5.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr S_C
 Last Modified:  4-JAN-1991    ArticleIdent: Q67085

 On pages 30 and 31 of the "Microsoft C Reference" manual shipped with
 C versions 6.00 and 6.00a, there are contradictory references to the
 far-call translation options available for LINK. On page 30 under the
 /F[ARCALLTRANSLATION] option, far-call translations are listed as
 being "turned on by default." On the other hand, on page 31 under the
 /NOF[ARCALLTRANSLATION] option, far-calls are listed as being "off by
 default."

 The statement on page 30 is the one that is incorrect because the
 correct default for far-call translations is "off." Far calls are done
 only when /F is explicitly specified to LINK.

 Note that when the CL command is used to invoke LINK, CL itself is
 responsible for passing the /F option to the linker.


 81. EXE Checksum Incorrect If linked with /CO or /E

 Product Version(s): 3.xx 4.0x 4.10 5.0x 5.10 5.13 | 5.0x 5.10 5.13
 Operating System:   MS-DOS                        | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q67795

 According to "The MS-DOS Encyclopedia," a DOS .EXE file contains a
 checksum value in the .EXE file header. This checksum value should
 allow the summation of all words in the .EXE file to equal FFFFh.
 However, if you use the /Exepack or the /COdeview options when linking
 a program, the checksum value will not be calculated correctly.
 Current versions of MS-DOS ignore this checksum so this will not cause
 any noticeable problems.

 Sample Code:
 ------------

 #include <stdio.h>
 #include <stdlib.h>

 main (int argc, char * argv[])
 {
    FILE * fp;
    unsigned int nxt= 0, sum= 0;
    unsigned char bl, bh;

    if (argc != 2)
       exit (-1);
    if ((fp= fopen (argv[1], "rb"))== NULL)
       exit (-1);
    while (! feof(fp))
    {
       bl= fgetc (fp);
       if (! feof(fp))
          bh= fgetc (fp);
       else
          {
          bl= 0;
          bh= 0;
          }
       sum= sum+ nxt;
       nxt= (unsigned int) bh* 256U+ (unsigned int) bl;
    }
    nxt&= 0xFF;
    sum+= nxt;
    printf ("sum = %X\n", sum);
 }


 82. L1008: "Segment Limit Too High" May Be Caused by Missing Colon

 Product Version(s): 3.x 4.06 4.07 5.01.21 5.03 5.05 5.10 | 5.01.21 5.03 5.05
 Operating System:   MS-DOS                               | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q46733

 When linking, the following error may be caused by incorrectly
 specifying the parameters for the /SE switch on the link command line
 with the colon:

    LINK : fatal error L1008: SE: segment limit set too high

 To generate the error, link using the /SE switch, then insert a space
 and the number of segments for the linker to use, such as the
 following:

    LINK /SE 1024

 The correct syntax for the /SE option is with a colon separating the
 switch from the numeric argument as follows:

    LINK /SE:1024


 83. The Purpose of Module Definition Files

 Product Version(s): 5.01.21 5.02 5.03 5.05 5.10 5.13 | 5.01.21 5.02 5.03 5.05
 Operating System:   MS-DOS                           | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q27134

 Module-definition files (.DEF) are used by LINK when building Windows
 and OS/2 programs and dynamic-link libraries (DLLs). A .DEF file
 describes the name, size, format, functions, and segments of an
 application or DLL.

 A module-definition file contains one or more module statements. Each
 module statement defines an attribute of the executable file. The
 module statements and the attributes they define are listed below:

 Statement         Attribute
 ---------         ---------

 NAME              Name and type of application
 LIBRARY           Name of dynamic-link library
 DESCRIPTION       One-line description of the module
 CODE              Default attributes for code segments
 DATA              Default attributes for data segments
 SEGMENTS          Attributes for specific segments
 STACKSIZE         Local-stack size, in bytes
 EXPORTS           Exported functions
 IMPORTS           Imported functions
 STUB              Adds a DOS Version 3.x executable file to the beginning
                   of the module, usually to terminate the program when
                   run in real mode
 HEAPSIZE          Local-heap size, in bytes
 PROTMODE          Specifies that the module runs only in OS/2 protected
                   mode
 REALMODE          Specifies that the module is for real-mode Windows.
 OLD               Preserves export ordinal information from a previous
                   version of the library

 The following rules govern the use of these statements in a module-
 definitions file:

 1. If you use either a NAME or a LIBRARY statement, it must precede
    all other statements in the module-definition file.

 2. You can include source-level comments in the module-definition
    file, by beginning a line with a semicolon (;). The OS/2 utilities
    ignore each such comment line.

 3. Module-definition keywords (such as NAME, LIBRARY, and SEGMENTS)
    must be entered in uppercase letters.

 For more information, refer to the utility reference or online help
 that accompanied your particular compiler or assembler.


 84. Working Around Link Error "L1064: Out of Memory"

 Product Version(s): 5.03 5.05 5.10 5.13 | 5.03 5.05 5.10 5.13
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 17-DEC-1990    ArticleIdent: Q45718

 The linker error "L1064: Out Of Memory" is new with LINK version 5.03,
 which was first shipped to individuals using IMSL libraries with
 FORTRAN 4.10, and was then shipped with FORTRAN 5.00. The description
 of the error is as follows (from the "Microsoft FORTRAN, Microsoft
 CodeView and Utilities User's Guide"):

    The linker was not able to allocate enough memory from the
    operating system to link the program. On OS/2 try increasing the
    swap space. Otherwise, reduce the size of the program in terms of
    code, data, and symbols. On OS/2, consider splitting the program
    into dynalink libraries.

 In DOS, the only ways to work around the error are the following:

 1. Remove any memory-resident software or device drivers that may be
    limiting the available memory of the machine.

 2. Reduce the program size, as described above.

 In OS/2, the easiest way to work around the error is to increase the
 swap space, as follows:

 1. Close other screen groups and remove other processes from
    memory to free up both RAM and swap space on the swap drive.

 2. Create more free disk space on the drive that is pointed to by
    the SWAPPATH setting in the CONFIG.SYS file. (Delete or move files,
    or change the setting to a drive with more free space.)

 3. Possibly DECREASE the swap value set by the SWAPPATH variable (do
    this with caution -- read below).

 Explanation of the SWAPPATH Setting in CONFIG.SYS
 -------------------------------------------------

 Swapping must be enabled via the MEMMAN setting in CONFIG.SYS for the
 SWAPPATH setting to be acknowledged at all (usually "MEMMAN=SWAP" or
 "MEMMAN=SWAP,MOVE").

 The default setting for SWAPPATH after setting up OS/2 is usually as
 follows:

    SWAPPATH=C:\OS2\SYSTEM 512

 The drive setting indicates the drive and directory where the space
 for the swapper file will be allocated. If no SWAPPATH variable is
 set, the swapper file is allocated in the root directory on the boot
 drive. The number that follows indicates the amount of free space
 which must be left on this drive when the swapper file has grown to
 its maximum size. (This number, by itself, says nothing about the
 maximum size of the swapper file.) Given the settings above, the
 maximum size of the swapper file can be easily calculated by the
 following:

    (free space on Drive C) - (SWAPPATH value) = max. swap file size

 Therefore, increasing the SWAPPATH value DECREASES the amount of space
 available for the swapper file.

 The swapper value can be decreased, and the system will allow values
 down to 0 (zero). However, because OS/2 does time-slicing between
 processes and may need to write to the disk in question, decreasing
 the swapper value below 512K (the system default) is not recommended.
 This workaround should be used only if you have the value set to
 greater than 512K (the range of valid values is from 0 to 32,767). If
 this is the case, set the SWAPPATH value to 512 and reboot the
 machine. If this method does not solve the problem, you must clear
 space on the hard disk by deleting or moving files.


 85. Patches Available for Running Utilities Under Novell NetWare

 Product Version(s): 5.10
 Operating System:   MS-DOS
 Flags: ENDUSER | appnote SC0381.ARC s_codeview s_pwb s_c
 Last Modified:  6-FEB-1991    ArticleIdent: Q68659

 When LINK version 5.10 is run under a Novell network, LINK may fail
 with the following error:

    L1085: cannot open temporary file

 In addition, the C version 6.00 Setup program (SETUP.EXE), the
 Programmer's WorkBench (PWB) for DOS versions 1.00 and 1.10, and
 real-mode CodeView (CV.EXE) versions 3.00, 3.10, and 3.11 may all hang
 when run under some Novell NetWare software.

 These problems are directly related to the network software, but may
 be corrected with a set of patch files available from Microsoft as an
 application note titled "Network Patches for Utilities" (SC0381).
 Application notes can be obtained by calling Microsoft Product Support
 Services at (206) 637-7096.

 The "Network Patches for Utilities" application note can also be found
 in the Software/Data Library by searching on the keyword SC0381, the Q
 number of this article, or S12898. SC0381 was archived using the
 PKware file-compression utility.

 The following is the complete text of the application note, which
 includes the details of the problems mentioned above:

 ======================================================================
                     Network Patches for Utilities
 ======================================================================

 The enclosed Network Patches for Microsoft Utilities disk contains the
 following five files:

    README.DOC
    CVPATCH.EXE
    PWBPATCH.EXE
    SETUPFIX.EXE
    LINK.EXE

 These files solve conflicts with certain network setups. Please be
 sure to make backup copies of the original files.

 Network Patch Files
 -------------------

 When run under certain network software, some Microsoft utilities may
 hang. The enclosed patch files are designed to correct these problems
 for CodeView versions 3.00, 3.10, and 3.11; the Programmer's WorkBench
 (PWB) versions 1.00 and 1.10; and the C 6.00 Setup program.

 To install the patches, first copy the patch files (PWBPATCH.EXE,
 CVPATCH.EXE, and SETUPFIX.EXE) to the directories where you have
 installed PWB, CodeView, and Setup, respectively. Each patch assumes
 that the utility file it is to patch is in the same directory.

 Run SETUPFIX.EXE to patch SETUP.EXE. The original file will be saved
 as SETUP.BAK. Run CVPATCH.EXE to patch CV.EXE. The original file will
 be saved as CV.BAK. Run PWBPATCH.EXE to patch PWBED.EXE. The original
 file will be saved as PWBED.BAK. The patched utilities should run free
 of network interference.

 Microsoft LINK Version 5.13
 ---------------------------

 LINK version 5.13 includes code to work around another problem that
 sometimes occurs when running on a network. On large projects, the
 linker needs to open some temporary files to work around DOS memory
 limitations. LINK version 5.10 (supplied with C 6.00) will sometimes
 fail in its attempts to open a temporary file when run under certain
 network software.

 The problem actually lies in the network software, not the linker.
 When the network is loaded, the return value from an open call
 sometimes gets corrupted. When the call fails, it is because an "Out
 of handles" error (EMFILE) is returned as a "No such file or
 directory" error (ENOENT). If this occurs, LINK 5.10 halts with an
 "L1085: cannot open temporary file" error.

 LINK 5.13 includes a change to correct for the above situation (even
 though the problem is in the network software). When LINK version 5.13
 receives an ENOENT error on a failed open call, it will still try to
 free some file handles and reopen the temporary file, regardless of
 the error returned.

 To make the correction, locate LINK version 5.10 and replace it with
 LINK version 5.13 from the enclosed disk. Again, be sure to save a
 backup copy of the original file (LINK 5.10).


 86. L2025 LINK Error May Be Caused by Conflicting Library Routines

 Product Version(s): 3.x 4.06 4.07 5.0x 5.10 5.13 | 5.01.21 5.02 5.03 5.10 5.1
 Operating System:   MS-DOS                       | OS/2
 Flags: ENDUSER | s_lib
 Last Modified: 24-JAN-1991    ArticleIdent: Q44465

 All variables and routines in a module within a library will be linked
 into a program when any single variable or routine residing in that
 module is referenced. This can cause the following linker error if two
 or more modules contain definitions for the same symbol:

    L2025  symbol defined more than once

 For example, in the diagram below, module1 contains routines "a", "b",
 and "c". The module2 contains routines "c", "d", and "e". When main()
 references "a" and "e", the linker links module1 and module2 from the
 library. This results in "c" being defined twice. Removing "c" from
 one of the modules, recompiling the module, and replacing the module
 in the library with the LIB utility operator "-+" will prevent "c"
 from being multiply defined.

                         +-----------+
                         |           |
                         | calls "a" |
                         | calls "e" |
                       / |           | \
                      /  +-----------+  \
                     /       main()      \
                    v                     v
                +-------+             +-------+
                |   a   |             |   c   |
                |   b   |             |   d   |
                |   c   |             |   e   |
                |       |             |       |
                +-------+             +-------+
                 module1               module2

 For each routine you want to be linked separately, compile a separate
 object file and add it to the library.






 Microsoft `M' Editor
 =============================================================================


 1. How to Put Microsoft Editor (M or MEP) into 43-Line Mode

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q28580

 To use the Microsoft Editor (M.EXE or MEP.EXE) in EGA 43-line mode,
 the TOOLS.INI file must be modified to include the following
 statement:

 HEIGHT:41

 (The number 41 is used because the last two lines are used by the
 editor as status/error lines. See Page 59 of the "Microsoft Editor for
 MS OS/2 and MS-DOS: User's Guide".)

 Once the TOOLS.INI is modified, the editor must be re-initialized.
 This process is done with the Initialize command. The default key
 stroke for this command is SHIFT+F8. Appendix A lists the values for
 the other .INI files provided with the editor. The following example
 demonstrates this process:

 1. Load TOOLS.INI.
 2. Modify TOOLS.INI.
 3. Save the file (ARG ARG SETFILE or leave and re-enter).
 4. Use the Initialize command (SHIFT+F8).

 After the initialization, the changes in the TOOLS.INI become active
 and the 43-line mode is in use.

 M.EXE runs in MS-DOS real mode, and MEP.EXE runs in OS/2 protected
 mode.


 2. Creating Macros for the Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q23051

 Macros for the Microsoft Editor are sequences of editor functions. For
 example, a macro to delete the word to the right of the cursor is
 defined as follows:

 worddelete:=arg meta pword sdelete

 The above macro is named "worddelete". To associate "worddelete" with
 a particular keystroke, the following command is needed:

 worddelete:ALT+W

 The macro "worddelete" is now bound to the keystroke "ALT+W". Note
 that the macro definition (i.e., ":=") resembles a Pascal assignment
 statement, but the keybinding uses a colon to delimit the macro name
 from the key to which it is assigned. The following is another
 example:

 filestamp:=curfilenam curfileext " - " curdate " " curtime
 filestamp:ALT+S

 This macro creates a file-time stamp that contains the filename, the
 current date, and the current time; it is assigned to the keystroke
 "ALT+S".


 3. File Size Limitations for the Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | TAR62237
 Last Modified: 29-AUG-1988    ArticleIdent: Q23609

 Question:

 What is the largest file the Microsoft Editor can load?

 Response:

 The size of the file is controlled by the operating system, not by
 the editor. The editor will read in a file of any number of bytes;
 however, you are limited by the temporary file space.

 The size of the drive pointed to by the TMP variable is the limiting
 factor. Because TMP often points to a (relatively small) RAM drive,
 such as VDISK or MS-RAMDRIVE, this is the most common file size
 limitation.

 A safe rule-of-thumb is that your TMP drive may need to be up to
 two times the size of the file being edited.

 The maximum number of lines a file can contain is 0x7FFFFFFF, but you
 will run out of disk space before you have too many lines.

 Both MS-DOS and OS/2 currently limit disk size (hence, file size)
 to 64K sectors, which normally is 32 megabytes.


 4. Unassigning Predefined Keys

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | TAR62300
 Last Modified:  1-SEP-1988    ArticleIdent: Q23754

 The following are two ways to unassign a predefined key:

 1. Assign the key to a different function.
 2. Assign the key to the "unassigned" function.

 If ALT+A currently is assigned to the ARG function, you can assign
 it to another function by putting the following line in your
 TOOLS.INI file:

 NewFunct:ALT+A

 If you don't want ALT+A to be assigned to any function, place the following
 line in your TOOLS.INI file:

 Unassigned:ALT+A.


 5. Error C1015 "Can't Open Include File" with MEP

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | S_C buglist1.00
 Last Modified:  2-NOV-1988    ArticleIdent: Q35140

 The example program below generates the following error:

 Error C1015 "Can't open include file"

 The program must be compiled with one of the output-file switches
 (such as /Fc) or through a make file to generate this error.

 The include file os2.h opens two other include files: os2def.h and
 bse.h. The bse.h include file, in turn, opens three other include
 files: bsedos.h, bsesub.h, and bseerr.h.

 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.

 The compiler attempts to open the last include file and generates the
 C1015 error. The total file count at this point is 15, as follows:

  1. stdin
  2. stdout
  3. stdprn
  4. stderror
  5. stdaux
  6. MEP
  7. source
  8. listing file
  9. os2.h
 10. os2 def.h
 11. bse.h
 12. bsedos.h
 13. bsesub.h
 14. bseerr.h
 15. tmp file

 The following sample code demonstrates the problem:

 #define INCL_BASE
 #include <os2.h>

 void main (void)
 void main (void)
 {
 }



 6. Maximum Number of Defined Macros Allowed in TOOLS.INI File

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | TAR63148
 Last Modified: 17-MAY-1988    ArticleIdent: Q24696

 Question:
    Is there a maximum number of macros, predefined and user-defined,
 allowed in the TOOLS.INI file?

 Response:
    The maximum number of defined macros allowed is 1024.


 7. BRIEF TOOLS.INI File Assigns Two Commands to F5 in M.EXE

 Product Version(s): 1.00    | 1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q30474

 Problem:

 After I configure the Microsoft M.EXE Editor in the BRIEF mode and
 invoke Psearch (F5 key), I receive the following error message:

 "Invalid argument."

 However, Msearch (ALT+F5) functions correctly.

 Response:

 The BRIEF TOOLS.INI file assigns two commands to F5. The first
 occurrence in the file is for Psearch and the second is for
 DeleteWindow.

 To correct the problem, one of the commands should be mapped to a
 different key. Make sure the new key is not already in use.

 The following is an example of the incorrect portion of the
 BRIEF.INI file:

    ; TOOLS.INI file for BRIEF(tm) configuration
    [M]
           .
           .
           .
    Psearch:F5
           .
           .
           .
    ; WINDOWS
    ;
    ; Delete Current Window is F5
    DeleteWindow:=meta window
    DeleteWindow:F5
    ;
    ;
    ;
    ; BRIEF is a trademark of UnderWare, INC.


 8. Assigning Key Sequence to ENTER and BACKSPACE Keys

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q25407

 Functions can be assigned to the ENTER and BKSP (BACKSPACE) keys in
 the TOOLS.INI file, as in the following example:

 emacsnewl:enter
 emacscdel:bksp

 Consult Chapter 6 of the "Microsoft Editor User's Guide," titled
 "Function Assignments and Macros."


 9. CALLTREE Ignores Conditional Compilation Statements in Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C H_MASM
 Last Modified: 17-MAY-1989    ArticleIdent: Q44417

 The CALLTREE utility provided with the Microsoft Editor can be used to
 produce a graphical call-tree listing of a project. The following
 command line is an example of this utility. This command line creates
 a file called CALLS.TXT showing the relationship of the functions
 found in the four C source files shown below:

    calltree /c calls.txt main.c sub1.c sub2.c sub3.c

 If any of the files use conditional compilation directives, these are
 disregarded by CALLTREE and any functions that would not have been
 called appear in the call listing. An example of code that produces a
 misleading call listing is shown below. Although only one set of calls
 is compiled, both sets show up in the file produced by CALLTREE.

     void main( void )
     {
     #ifdef DEBUG
         dshow();
         ddone();
     #else
         fshow();
         fdone();
     #endif
     }

 To avoid this situation, a preprocessor listing should be produced
 using the /P switch with CL, and CALLTREE should then be run on the
 resultant file.

 This is a limitation of the utility. CALLTREE is meant to be a
 general-purpose tool for C and assembly programs, and is not designed
 to do any parsing or syntax checking.


 10. Microsoft Editor Fails to Find TOOLS.INI Using DOS Version 2.x

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q28590

 Problem:

 When running the M.EXE editor under DOS Versions 2.x, the editor does
 not find the TOOLS.INI file. The error reported is "Unable to Read
 TOOLS.INI[]".

 The following demonstrates the problem:

 1. Rename QUICK.INI to TOOLS.INI.
 2. Set the environment variable INIT to the directory c:\mytools
    as follows:

    SET INIT=c:\mytools

 3. Load the M.EXE editor. It will come up with default settings,
    instead of reading TOOLS.INI.

 When running DOS Version 3.20 on an IBM PC AT, M.EXE correctly finds
 the TOOLS.INI file.

 Response:

 M.EXE and MEP.EXE use their startup name to find the right section in
 TOOLS.INI. For example, if you rename the editor to Z, it will look
 for [z] instead of [m] in the editor's section in TOOLS.INI.

 This process occurs in all cases except under DOS Versions 2.x. Under
 any 2.x version of DOS, the name of your program is not available, and
 instead, the compiler provides the arbitrary name "C".

 To work around this limitation in DOS Versions 2.x, change the
 editor's tagged section in TOOLS.INI file to use the tag [c] instead
 of [m]. If it is necessary to share files with DOS Versions 3.x
 systems, the editor's section in TOOLS.INI can be tagged [m c].

 The editor uses the same method to name the following, where * is
 replaced by the editor name or by "C" under DOS Versions 2.x:

 1. The virtual memory file, *-XXXX.VM
 2. The history-and-state file, *.TMP
 3. The compiler message file, *.MSG


 11. Using Full Pathnames to Compile Programs with M or MEP

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | TAR75085
 Last Modified: 20-OCT-1988    ArticleIdent: Q29150

 The full pathname of a file is not transferred to the compiler when an
 ARG COMPILE is executed in the Microsoft Editor for MS-DOS and OS/2.
 The following is an example:

 1. Invoke M.EXE as follows:

 M \c5\source\test.c

 2. Compile the program with ARG COMPILE. (The default value is
    ALT+A SHIFT+F3). The following line is displayed:

    CL /c /Zep /D LINT_ARGS test.c

    The full pathname is not given.

 If you plan on compiling from other directories, you should define
 the compile command using the %|F option. The default option %s uses
 only the filename. For example, the TOOLS.INI file could be modified
 as follows to get the default compile with the full pathname:

 extmake:c cl /c /Zep /D LINT_ARGS %|F

 You also can select portions of the full pathname, and use the name
 more than once, as in the following example:

 %d|F - obtains the drive (and colon)
 %p|F - obtains the path
 %f|F - obtains the filename (no extension)
 %e|F - obtains the extension

 You can combine the "dpfe" any way you wish, as in the following:

 %dpf|F.xyz

 This combination produces the drive, path, and filename, with the
 extension .XYZ added to the filename.


 12. Editor "User's Guide" C-Extension Sample Generates Warnings

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-JUL-1988    ArticleIdent: Q29730

 Problem:
     When I compile the sample program on Page 85 of the "Microsoft
 Editor for MS OS/2 and MS-DOS: User's Guide," I get two warning
 messages.
    These warning messages are generated on the following two sections
 of the sample program:

    1. struct swiDesc swiTable [] = {
             { NULL, NULL, NULL }
        };

    2. struct cmdDesc cmdTable [] = {
             { "Upper", Upper, 0, BOXSTR | TEXTARG },
             { NULL, NULL, NULL, NULL }
        };

 Response:
   These warnings will not cause a problem. You can, however, make the
 following two changes:

    1. struct swiDesc swiTable [] = {
             { NULL, NULL, 0 }
        };

    2. struct cmdDesc cmdTable [] = {
             { "Upper", Upper, 0, BOXSTR | TEXTARG },
             { NULL, NULL, 0, 0 }
        };


 13. Missing Semicolon on Line 17 of Example on Page 85 in Manual

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 29-AUG-1988    ArticleIdent: Q29731

    On Page 85 of the "Microsoft Editor for MS OS/2 and MS-DOS: User's
 Guide," there is a missing semicolon on line 17.
    The following line is incorrect:

    cfile = FileNameToHandle("", NULL)

    It should read as follows:

    cfile = FileNameToHandle("", NULL);


 14. M.EXE Editor Macro to Join Current Line with Next Line

 Product Version(s): 1.00    | 1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q30030

    The following macro will join the current line with the following
 line, leaving one space between the last character on the current line
 and the first character of the next line.
    Place the following three lines in the [M] and/or [MEP] section(s)
 of your TOOLS.INI file, or enter them from the keyboard using the
 ASSIGN function (ALT+= in the default keyboard setup):

    ;Macro to join current line with next line.
        join:=endline right arg down begline sdelete
        join:alt+j

    The following is a description of how the join macro works:

    1. Endline moves one place beyond the last character on the current
       line.
    2. Right moves one character further, to insert a space.
    3. arg introduces the argument to the next command (in this case,
       sdelete).
    4. down begline moves to the first character on the next line.

    This process defines a Streamarg for the command sdelete (S stands
 for Stream).
    Note that sdelete should be used, not ldelete, because the down
 begline sequence would have defined either a Linearg or a Boxarg,
 neither of which would join the lines.
    Use sdelete because it closes the stream of characters and/or white
 space between the starting cursor position and the ending cursor
 position.


 15. Microsoft Editor Macro Moves Text with TAB Key

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-JAN-1989    ArticleIdent: Q30033

 The TAB key only moves the cursor. It does not move both the cursor
 and the text under the cursor (as it does in QuickC, Word, and many
 other editors).

 To move text and the cursor, put the following macro in your TOOLS.INI
 file in the [M] and/or [MEP] section(s):

    ;Macro to tab with insertion, as in QuickC and Word
        emacstab:=arg tab sinsert tab
        emacstab:ctrl+tab

 The "emacstab" macro (there is no significance to the name other than
 its similarity to M.EXE's EMACSNEWL and EMACSDEL functions) is invoked
 by pressing CTRL+TAB.

 Note: assigning this macro to CTRL+TAB will only function on
 enhanced-style keyboards. Older-style keyboards must use another set
 of keys for this macro assignment. On the older keyboards, assigning
 this macro to CTRL+TAB causes the macro to be ignored.

 The emacstab macro functions as follows:

 1. The Arg command introduces the argument (in this case, a
    "stream" arg).

 2. The Tab command moves you one tab stop to the right.

 3. The Sinsert command moves the highlighted text over to the tab
    stop.

 This macro leaves your cursor back where it started, so one more TAB
 moves your cursor to the right (on top of the shifted text).


 16. C Extension to Make Psearch Prompt for an Input in M.EXE

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 23-MAY-1988    ArticleIdent: Q30285

 Question:
    I wish to emulate the Brief Psearch (Plus Search) with the M.EXE
 editor. I want Psearch to prompt me to enter a search string. Can this
 be done with a macro or do I have to use a Microsoft C extension?

 Response:
     This emulation cannot be done with macros. However, it can be done
 with Microsoft C extensions.
     The following is an example of how to do so in a Microsoft C
 extension:

     1. Use DoMessage() to output a string saying something similar to
 the following:

     "Please enter the search string:"

     2. Use KbUnHook() to disable M.EXE's "logical keyboard." This
 gives you the "focus" of the keyboard so that keyboard input is no
 longer read by the editor, thus freeing you to input a string from the
 user.
     3. Parse the keyboard input and then process it appropriately by
 invoking the Psearch function.
     4. Use KbHook() to reenable the logical keyboard in M.

     The following is an alternate method:

     Use "ReadChar()" instead of "KbUnHook()" and "KbHook()."
 (Mentioned in steps two and four above.)

     For more information on the functions available for writing C
 extensions, please read the files EXT.DOC and EXT.H that are included
 with the Microsoft Editor Version 1.00.
     For general information on programming C extensions, please
 consult Chapter 8 of the "Microsoft Editor User's Guide."
     Appendix A of the "Microsoft Editor User's Guide" provides a
 comprehensive list of editing functions such as Psearch.
     Psearch searches forward for the previously defined string or
 pattern. Msearch (Minus Search) searches backward for the previously
 defined string or pattern.


 17. Debug Shown on M.EXE Help Screen Is Not a Supported Switch

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-JUN-1988    ArticleIdent: Q30365

    The Debug numeric switch that appears in the information file of
 the help screen in the Microsoft Editor Version 1.00 has not been
 implemented.
    There is no function associated with Debug.


 18. M.EXE C Extensions Documented in UTILITY.DOC, Not README.DOC

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 26-MAY-1988    ArticleIdent: Q30534

    Page 70 of the "Microsoft Editor User's Guide" incorrectly states
 the following:

    "To create a successful C extension, you need to follow these
 guidelines:
        1. Check the README.DOC file to see what functions you can call
 from the standard C run-time library."

    Contrary to the above manual statement, C extensions are documented
 in UTILITY.DOC on the release disk, not in the README.DOC.



 19. Making Assignments to PLUS, MINUS and PRINT SCREEN Keys

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | tar66615
 Last Modified:  1-SEP-1988    ArticleIdent: Q31485

 It is possible to make key assignments to the PLUS, MINUS, and
 PRINT SCREEN keys on the numeric keypad.

 For more information on function assignments, macros, and keystrokes,
 consult section 6.2.1 of "The Microsoft Editor User's Guide."


 20. How to Load a C Extension that Is Not in Current Directory

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | TAR75933 docerr
 Last Modified:  8-JUN-1988    ArticleIdent: Q30826

    Page 84 of the "Microsoft Editor for OS/2 and MS-DOS User's Guide"
 incorrectly infers that the M.EXE editor will search for a C-extension
 module along the DOS PATH under MS-DOS or OS/2 real mode when you
 place the following statement in the TOOLS.INI file:

    load:myext.exe

    To search for a C-extension module along the DOS PATH, you must
 instead use the following load switch syntax in the TOOLS.INI file:

    load:{$ENVAR: | dos path}filename.ext

 where you have the option of using $ENVAR: (a DOS environment
 variable) or an explicit directory path specification.
    You can prefix your filename with $PATH: or $INIT:. For example,
 "$PATH:filename.ext" means the "filename.ext" is to be found in the
 directories in the DOS PATH. This format is valid in any filename
 context. The following example will go to the STDIO.H file that
 actually is being used by the compiler:

    <arg> "$INCLUDE:stdio.h" <setfile>

    Also, when operating under OS/2, $ENVAR:, the explicit DOS path,
 and the extension on the filename are ignored. Instead, filename.DLL
 is searched for in your LIBPATH. Please note that LIBPATH under OS/2
 is not an environment variable. LIBPATH is a directive in the
 CONFIG.OS2 file.
    The following are examples of using the load switch in TOOLS.INI:

    ; load 'my.ext' from the current directory.
    ; Under OS/2, load my.dll from LIBPATH.
    load:my.ext

    ; load 'your.ext' from either the current directory or one
    ; of the directories on path
    ; Under OS/2, load 'your.dll' from LIBPATH
    load:$PATH:your.ext

    ; load 'c:\init\ourext'.
    ; Under OS/2, load 'ourext.dll' from LIBPATH
    load:c:\init\ourext



 21. An Example Where a Protect Mode C Extension Will Not Load

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | TAR76121 TAR76251
 Last Modified:  8-JUN-1988    ArticleIdent: Q30827

 Problem:
    I am trying to create an extension to the MEP.EXE editor. I am
 unable to get the editor to load my C extension. To simplify things I
 tried to get the editor to load the sample SKEL; however, I was
 unsuccessful. I receive the following error messages when loading:

    "cannot load skel - invalid argument"
    "skel is an illegal setting"

    My LIBPATH is c:\os2\dll and skel.dll is placed there. If skel.dll
 is not in my libpath I would get the error "no such file or
 directory". My MAKE and DEF files for SKEL are as follows:

 SKEL MAKE FILE
 #
 # Makefile for the MEP Editor Extensions
 #
 SYS=\os2\dll

 .c.obj:
  cl -c -Gs -Asfu -G2 -Lp $*.c

 .obj.dll:
  link  /NOI /NOD exthdrp.obj $*.obj,$*.dll,nul.map,,$*.def;

 skel.obj:    skel.c skel

 skel.dll:    skel.obj skel.def

 $(SYS)\skel.dll:  skel.dll
        copy skel.dll $(SYS)

 SKEL DEF FILE

 LIBRARY  SKEL

 EXPORTS
  _ModInfo
  SKEL

 Response:
    The extension is not loaded because the DEF file is incorrect. The
 file should be as follows:

 SKEL.DEF:
    LIBRARY

    EXPORTS
            _ModInfo
            EntryPoint

    This file should be used with all the extensions that are written.
 It need not be modified.



 22. Tags Let You Use the Same TOOLS.INI File for M and MEP

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | TAR76127
 Last Modified:  8-JUN-1988    ArticleIdent: Q30828

 Question:
    I have the same commands for M and for MEP. I want to load the
 QUICKHELP utility if I am running OS/2. However, in my TOOLS.INI file,
 if I put in the following information, MEP never reads the rest of
 the TOOL.INI file:

    [mep]
     load:qhmep
    [m mep]
     rest of the commands
     .
     .

    How should I do this without making two (almost identical) files,
 one for [m] and one for [mep]?

 Response:
    Through the use of tags, it is possible to use the same TOOLS.INI
 file in both protect mode and real mode/DOS. The tag must specify the
 program name along with the version of the operating system as in the
 following example:

    [m-3.2]    => MS-DOS 3.2
    [m-10.0]   => OS/2 1.0 protect mode
    [m-10.0R]  => OS/2 1.0 real mode
    [m-10.10]  => OS/2 1.1 protect mode
    [m-10.10R] => OS/2 1.1 real mode

    The following change should be made to your TOOLS.INI file:

        [m mep]
                 commands that are non operating system dependent
             .
             .
             .

        [mep-10.0]
             load:qhmep

    The number used in the tag is the major and minor version number of
 of the operating system being used. Under OS/2 this information can be
 found by calling the API routine DosGetVersion. The call can be made
 from any language that supports the use of the API,including C Version
 5.10, MASM Version 5.10, FORTRAN Version 4.10, PASCAL Version 4.10,
 and BASCOM Version 6.00. Under DOS, this information is displayed with
 the DOS VER command.


 23. Setting TMPSAV in TOOLS.INI file; M.TMP Cannot Be Suppressed

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | TAR76606
 Last Modified:  8-JUN-1988    ArticleIdent: Q30829

 Question:
    How do I get the Microsoft Editor (both ME and MEP) to not create
 and use the M.TMP to record past editing sessions?
    I have tried setting the switch tmpsave:0 in the TOOLS.INI file,
 but this does not solve the problem. Is there some other switch I have
 not set properly or a way to exit without creating M.TMP?

 Response:
    There is no way to prevent the creation of the temporary file.
    The TMPSAV switch is used to control the maximum number of files
 about which information is kept between editing sessions. This
 information includes the cursor position and window layouts.
    When you edit one of these files again, the screen starts up as you
 left it. The default value is 20. If TMPSAV is set to 0, it causes all
 files to be saved. All other numeric values refer to the number of
 files that will be saved. The /t option specifies that any files
 edited are temporary; they are not saved in the M.TMP file.



 24. Protected-Mode C Extensions Fail with "Protection Fault"

 Product Version(s): 1.00 | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 29-AUG-1988    ArticleIdent: Q31009

 Problem:
    I am writing C extensions for the protected mode of OS/2. All my
 extensions fail with a general-protection fault. The sample program on
 Page 85 of the "Microsoft Editor for MS OS/2 and MS-DOS: User's Guide"
 also fails.

 Response:
    Page 78 of the "Microsoft Editor for MS OS/2 and MS-DOS: User's
 Guide" incorrectly states that the second argument is a NULL pointer.
    The programs are crashing because the incorrect value is being
 passed to the FileNameToHandle routine. This routine requires a
 pointer to a null string, not a null pointer.
    For example, the following statement

    cfile=FileNameTohandle("",NULL);

 should read as follows:

    cfile=FileNameTohandle("","");


 25. Two Toned Colors in <assign> Pseudo File Can Occur

 Product Version(s): 1.02    | 1.02
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist1.02
 Last Modified: 29-JAN-1990    ArticleIdent: Q58029

 The <assign> pseudo file can consist of lines in blocks that alternate
 in color starting at the middle of the file. This appears as if you've
 changed multiple editor options, which have just been activated, when
 no changes were actually made. This does not affect the way M.EXE (or
 MEP.EXE) operates.

 To see the blocks of alternating color, follow the steps below:

 1. Invoke the editor.

 2. Press ALT+A <ASSIGN> F2, which implies ARG <ASSIGN> SETFILE.

 3. Press ALT+BACKSPACE, which implies UNDO.

 4. Press F9 ALT+BACKSPACE, which implies META UNDO.

 5. Page down until you see the colored blocks.

 Microsoft has confirmed this to be a problem with the Microsoft Editor
 Version 1.02. We are researching this problem and will post new
 information here as it becomes available.


 26. Return Type for ReadCmd Is PSWI, Not PCMD

 Product Version(s): 1.00 | 1.00
 Operating System:   OS/2 | MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 12-JAN-1989    ArticleIdent: Q31143

 Page 7 of the EXT.DOC file, located in the SOURCE\ME\EXT directory of
 the Microsoft C Optimizing Compiler Version 5.10, incorrectly lists
 the return type for the ReadCmd command as being PCMD.

 The correct return type is PSWI, which is documented in the EXT.H
 file.


 27. MEP Crashes OS/2 when Switching from Real-Mode Screen Group

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |  TAR75546 TAR76522
 Last Modified: 28-OCT-1988    ArticleIdent: Q31144

 When running in OS/2 protected mode, the system may crash when
 switching between protected mode and real mode and using the ALT+ESC
 sequence. It may take several iterations of ALT+ESC before the failure
 occurs.

 The system crashes when switching from the real-mode session into a
 protected-mode session that is running MEP. When the system crash
 occurs, the following message appears:

     TRAP 000D

     <register contents>

     The system detected an internal processing error
     at location # 3430:0590
     Exception while in kernel mode

     The system is stopped

 This is not a problem in MEP; it is a problem in OS/2.

 You can work around this problem by not running MEP in the original
 ("default") protected-mode screen group. Instead, start a second
 protected-mode screen group and run MEP there. To move to the second
 protected-mode screen group, do the following:

 1. Press ALT+ESC from real mode to get to the original
    protected-mode screen group.

 2. Press ALT+ESC again to get to the MEP screen group.

 Running MEP in a second screen group prevents you from switching
 directly from real mode into the MEP screen group.

 Another workaround for this problem is to use the CTRL+ESC hotkey
 rather than the ALT+ESC command to leave the real-mode screen group.
 The CTRL+C hotkey brings you back to the program selector. Once
 there, you can select the next screen group by using the mouse or
 cursor keys.


 28. "Unable to Read TOOLS.INI" Message Appears in OS/2 with MEP

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  8-JUN-1988    ArticleIdent: Q31155

     MEP.EXE, the OS/2 version of the Microsoft editor, will give the
 following message when the INITIALIZE function is invoked (i.e.,
 SHIFT-F8 in the default keyboard setup):

    "Unable to read TOOLS.INI"

    This message will appear if the editor's name is left as MEP while
 the TOOLS.INI tag for the editor is labeled [M]. The two names must
 match.
    To correct the problem, either rename the editor to M, or label the
 tag [MEP].
    The tag can be set to [M MEP] if you wish to use the same TOOLS.INI
 settings for both real-mode and protected-mode versions of the editor.


 29. Purpose of ECH.EXE with the Microsoft Editor

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  8-JUN-1988    ArticleIdent: Q31280

    ECH.EXE is used by the editor to generate the list of files you
 receive when you do <arg> "*.C" <setfile>.



 30. NOSOFTCR Parameter in TOOLS.INI Disables Auto Indentation

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | tar69375
 Last Modified: 14-JUN-1988    ArticleIdent: Q31486

    The automatic indentation at the beginning of lines can be
 disabled.
    The NOSOFTCR parameter prohibits the Microsoft Editor from making
 indentation "guesses." NOSOFTCR is specified in the TOOLS.INI file, as
 follows:

    nosoftcr:



 31. Features Supported when Editing TextArgs in Microsoft Editor

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | tar69726
 Last Modified:  6-JAN-1989    ArticleIdent: Q31487

 When editing TextArgs, not all editing features are supported. The
 following features are supported:

 QUOTE, INSERT, SDELETE, RIGHT, LEFT, UP, DOWN, HOME, and END

 When an unsupported feature is entered, the editor will beep. Macros
 may be used, but they can contain only supported features.

 The END key allows you to find the length of the search/replace
 string; pressing ARG clears the entire string.


 32. UTILITY.DOC: Filetab Switch Expands Tabs

 Product Version(s): 1.00 | 1.00
 Operating System:   OS/2 | MS-DOS
 Flags: ENDUSER | tar71845
 Last Modified: 16-JUN-1988    ArticleIdent: Q31488

    Information about the filetab switch can be found in the
 UTILITY.DOC file that comes with the Microsoft BASIC Compiler Version
 6.00, the Microsoft C Compiler Version 5.10, the Microsoft FORTRAN
 Compiler Version 4.10 and the README.DOC for Microsoft MASM Version
 5.10.
    The filetab switch is a numeric switch that determines how the
 editor translates tabs when loading a file into memory. The value of
 the switch gives the number of spaces associated with each tab column.
    For example, the setting "filetab:4" assumes a tab column every four
 positions on each line of a file.
    Every time the editor finds a tab character in a file, it loads the
 buffer with the number of spaces necessary to get to the next tab
 column. Depending on the value of the entab switch, the editor also
 uses the filetab switch to determine how to convert spaces into tabs
 when writing a file.
    The default value of filetab is eight (8).



 33. Tabs Expanded to Eight Spaces; Filetab Switch Changes Spacing

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | Tar70793
 Last Modified:  1-SEP-1988    ArticleIdent: Q31489

 Question:

 Why are tabs expanded to eight spaces even though I set the tabstop
 variable and the entab switch?

 Response:

 Neither the tabstops or the entab switch affect how tabs are expanded
 when the file is read. The filetab switch is used to determine how
 many spaces to expand each tab. For example, "filetab:4" will expand
 each tab in the file to four spaces.

 The entab switch controls how the editor converts multiple spaces
 into tabs when a line is changed or a file is saved. The default is
 one (1). The following chart shows different values and their
 meanings:

 Value   Meaning

 0       Tabs are not used to represent white space.
 1       All multiple spaces outside of quoted strings
         are converted to tabs (default).
 2       All multiple spaces are converted to tabs.

 Tabstops control the number of spaces between each logical tabstop
 for the editor. The default is four (4).


 34. Resizing Windows

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | tar63957
 Last Modified:  1-SEP-1988    ArticleIdent: Q31490

 It is not possible to directly resize windows in the Microsoft Editor.
 A window can only be opened or closed. To resize a window, it must be
 closed and then reopened. Direct resizing of windows is not currently
 possible.

 This feature is under review and will be considered for inclusion in a
 future release.


 35. Parentheses Matching in Microsoft Editor; Arg Meta PBal

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | tar63957
 Last Modified: 31-OCT-1988    ArticleIdent: Q31491

 The Microsoft Editor has the capability of matching parentheses
 without altering the current file. Meta PBal prevents the file from
 being edited while balancing parentheses and brackets.

 The following are various other options for Pbal:

 1. Pbal: Scan backwards through the file, balancing parentheses and
    brackets. The first unbalanced one is highlighted when found. If it
    is found and is not visible, the editor displays the matching line,
    with the highlighted matching character. Note that the search does
    not include the current cursor position, and that the scan only
    looks for more left brackets or parentheses than right, not just an
    unequal amount.

 2. Arg Pbal: Performs similarly to Pbal, except that it scans
    forward in the file and looks for more right brackets or parentheses
    than left.

 3. Arg Meta Pbal: Performs similarly to Arg Pbal except that the
    file is not updated.


 36. Editing Nonexisting Files with the Microsoft Editor

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | tar62913
 Last Modified: 16-JUN-1988    ArticleIdent: Q31492

    If the Microsoft Editor is invoked to edit a nonexisting file, it
 creates a file with a length of zero in the DELETED directory in
 addition to creating a new file. This occurs with the backup switch
 set to "undel" (the default) in the TOOLS.INI file.
    This behavior is expected and is program design for the product.
 When the Microsoft Editor is invoked to edit an existing file, the
 previous version is moved to the DELETED directory.
    The EXP command allows you to remove this file, and all other files
 from the DELETED directory.



 37. Macro to Toggle HOME Key

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | tar66615
 Last Modified: 12-JAN-1989    ArticleIdent: Q31493

 You can create a macro to do the following:

 1. Press HOME key (cursor goes to beginning of line).

 2. Press HOME key again (cursor goes to top of window).

 3. Press HOME key again (cursor goes to top of buffer).

 This technique usually is used to create a toggle key, but it is
 equally applicable to the desired three-step toggle. The technique is
 as follows:

 home1:= begline arg "home2:f10" assign
 home2:= home arg "home3:f10" assign
 home3:= mark arg "home1:f10" assign
 home1:f10

 After following this procedure, the F10 key will toggle among begline,
 home, and mark.


 38. Inserting Time and Date into Files

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-MAY-1989    ArticleIdent: Q40176

 To write a macro to insert the time and date into your file, use the
 following insert commands:

    Command     Action

    Curdate     Inserts current date
    Curday      Inserts current day of the week
    Curfile     Inserts current filename
    Curfileext  Inserts current file extension
    Curfilenam  Inserts base name of current file
    Curtime     Inserts current time
    Curuser     Inserts name specified in USER environment variable

 The following macro can be inserted into your TOOLS.INI to insert the
 filename, time, and date:

 ;Macro for time and date.
     Header:= Curfilenam tab Curtime tab Curdate
     Header:Alt+H


 39. Macro to Enter Form Feed or Control Characters in Editor

 Product Version(s): 1.00 | 1.00
 Operating System:   DOS  | OS/2
 Flags: ENDUSER | tar62237
 Last Modified:  1-NOV-1988    ArticleIdent: Q31495

 The form-feed characters and control characters below can be entered
 in a file being edited by the Microsoft Editor.

 The following macro inserts a linefeed, (CTRL+L), and a newline, and
 binds it to the F6 key. To enter a CTRL+L, use the Graphic assignment
 on Page 48 of the "Microsoft Editor User's Guide" when editing your
 TOOLS.INI file:

 graphic:ctrl+l

 FFM:="L" newline   ; Instead of the L shown here, insert a CTRL+L
 FFM:F6             ; with the quote function "CTRL+P CTRL+L"

 The macro below allows you to enter control key values. The
 following line binds "quote" to F5. Quote allows you to enter any key
 as input (i.e., control key values, etc). This means if you type "F5"
 followed by a "CTRL+X", you will see a "\030" instead of "arg":

 quote:F5.


 40. "Unsupported Video Mode" When Loading Microsoft Editor

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 28-JUL-1989    ArticleIdent: Q31498

 It is possible when loading M.EXE or MEP.EXE to receive an
 "Unsupported video mode, please change modes and restart" error
 message. This message may mean that the hardware is not supported.

 Graphics cards supported in this situation include IBM's CGA, EGA,
 MCGA, MDPA, and VGA and the Hercules card. An example of an
 unsupported system is the 8514 video adapter.

 In MS-DOS (or OS/2 real mode), the Microsoft Editor (M) supports the
 8514/A graphics card, but in OS/2 protected mode, MEP Version 1.00
 does not support this graphics card. A "video mode not supported"
 error message occurs in protected mode.

 The Microsoft Editor Version 1.02 supports the 8514/A graphics card in
 both real and protected mode. This version is currently available with
 FORTRAN 5.00.


 41. Environment Variables Used by the Microsoft Editor

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 16-JUN-1988    ArticleIdent: Q31547

    The Microsoft Editor uses the following environment variables:

    1. TMP: This directory stores all temporary files.
    2. INIT: This directory stores the TOOLS.INI, M.TMP, and temporary
 files if TMP is not set.

    Please note, if neither environment variable is set, all temporary
 files except M.TMP are written to the root directory of the disk being
 used. M.TMP is written to the current directory.
    The environment variables usually are set in the AUTOEXEC.BAT file.
 For example the following lines can be placed in the AUTOEXEC.BAT
 file:

     SET INIT=c:\init
     SET TMP=c:\temp

    Also, if the TMP environment variable ends with a semicolon, the
 temporary files (i.e., swapping files) will not be created. The editor
 will try to use the semicolon in the name of the file that is created.


 42. Editor Utilities DOS Version 2.x and 8086/8 Corrections

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q31801

 The following files are included in this application note:

    MEGREP.EXE, RM.EXE, UNDEL.EXE, ECH.EXE and EXP.EXE.

 These files are replacements for the original utilities that were
 shipped with the Microsoft Editor Version 1.00. They have been updated
 to correct two specific problems only; they do not include any additional
 functionality over the originals.

 These files correct the problem of embedded 286 instructions that
 prevented the programs from correctly running on 8086 and 8088
 machines (the machines would hang). The files also have been updated
 to correct problems when used with DOS Version 2.x.

 To install the files, copy the files from the appnote disk over the
 files (of the same names) that are installed on the machine.

 This application note can be obtained by calling Microsoft Product
 Support Services at (206) 454-2030.


 43. Preventing Generation of Tabs in the Edited Disk Files

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1988    ArticleIdent: Q32033

    It is impossible to search for a tab or replace a string with a tab
 in the M editor.
    When a file is being edited, there are no tab characters in the
 file. When the M editor reads from disk to memory, it converts tabs to
 spaces. When it writes from memory to disk, it converts spaces to tabs
 (unless you set the ENTAB switch to 0).
    This may create problems when devices other than your machine
 access the file. For example, if you edit a source file on your IBM PC
 with the M editor, then try to compile the source file on a mainframe,
 the source file may not compile because of the tabs in the disk file
 created by the M editor.
    The solution is to set ENTAB to 0 in the TOOLS.INI file; this value
 will prevent tabs from being used to represent white space when
 writing from memory to disk.
    For more information on the ENTAB switch, please refer to Table 7.2
 on Page 59 of the "Microsoft Editor User's Guide."


 44. M Hangs on Tandy 2000 with MS-DOS Version 2.11

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q32052

 M, the Microsoft Editor for MS-DOS, hangs when run on a Tandy 2000
 computer running MS-DOS Version 2.11.

 M does not support the Tandy 2000. There is no workaround to this
 incompatibility.


 45. Scrolling One Line at a Time

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |  buglist1.00
 Last Modified: 20-OCT-1988    ArticleIdent: Q32053

 Problem:

 The editor jumps seven lines at a time when I Scroll off the top or
 bottom of the screen. I want it to Scroll one line at a time, but it
 Scrolls four lines at a time when I set VSCROLL to 1.

 Response:

 Hike and Scroll are designed to be independent functions; however,
 they are incorrectly tied together.

 Microsoft has confirmed this to be a problem in Version 1.00 of the
 editor. We are researching this problem and will post new information
 as it becomes available.

 A workaround to this problem is to set both VSCROLL and HIKE to 1 in
 your TOOLS.INI file in the [M] section, as in the following example:

 [M]
     hike:1
     vscroll:1


 46. Installing M with Msetup

 Product Version(s): 1.00    | 1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | h_fortran
 Last Modified: 19-JUL-1988    ArticleIdent: Q32094

 Question:
    The FORTRAN Version 4.10 setup program did not install the
 Microsoft Editor. I could not find any documentation on how to use
 msetup in the UTILITIES.DOC. How do I set up the Editor?

 Response:
    To run the msetup program, place the "Microsoft Editor" disk in
 Drive A and type "msetup". A help screen will be displayed showing
 the syntax for using msetup. An example of running msetup is as
 follows:

    A:>msetup c: \m \init \binp

    This procedure will install the M Editor and M tools (MEGREP, ECH,
 UNDEL, etc.) in the M directory, TOOLS.INI in the INIT directory, and
 MEP in a BINP directory. If you do not specify any directories, the
 program will use default directories. It will show these default
 directories on the screen and prompt you for any changes. These
 directories must be created before running msetup; otherwise, it will
 not be installed correctly.
    Please note that when the msetup prompts you for the type of
 emulation to use for the TOOLS.INI file, a TOOLS.INI file will not be
 created if you type a "0" for the default tools (the defaults are
 already built into Editor). If any of the other emulations are used,
 msetup will rename the appropriate file to TOOLS.INI and install it.


 47. Exit Does Not Save Files when NoAutosave Is Set

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-OCT-1988    ArticleIdent: Q32095

 When the boolean switch Autosave is disabled (by setting it to
 NoAutosave), a file will not be saved when exiting the editor.

 As documented on Page 61 of the "Microsoft Editor User's Guide," when
 the Autosave switch is turned on, the current file is saved when the
 user switches away from it. When Autosave is off (NoAutosave), the
 file must be explicitly saved when desired; this can be done by
 entering Arg Arg Setfile (ALT+A ALT+A F2 in the default keyboard
 setup).


 48. Arg *.* Setfile: "Bad Command or Filename" Error

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | tar78150
 Last Modified: 29-AUG-1988    ArticleIdent: Q32224

    Entering the command Arg *.* Setfile causes M to display a list of
 all files in the current directory.
    ECH.EXE is a utility used to generate the list of files for ARG
 textarg SETFILE. If this utility cannot be found, you will receive a
 message saying "Bad command or filename." ECH.EXE must be located in a
 directory on the path.


 49. Using the SHORTNAMES Switch

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | tar78150
 Last Modified: 31-MAR-1989    ArticleIdent: Q32225

 SHORTNAMES is a boolean switch. When it is set (the default), if you
 type <arg> "foo" <setfile>, you will be sent to the first file in your
 history list with the base name "foo". You do not have to specify the
 full pathname for a file in another directory. If there is no
 d:\path\foo.xxx anywhere in your file history, you only get foo.

 If you have a file "foo" in your current directory, SHORTNAMES still
 tries to find a file in your history list first. The history of files
 is stored in M.TMP. The number of files saved is determined by the
 TMPSAV switch.

 To disable this feature, set noshortnames: in your TOOLS.INI file.

 To avoid this behavior without changing the switch value, include a
 period in the path specification. For example, enter <arg> "foo."
 <setfile>, which will look only in the current directory. The presence
 of any path character (".", etc.) disables the SHORTNAMES feature for
 the file being referenced.


 50. Cancel Clears the Type-Ahead Buffer

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | tar75933
 Last Modified: 19-JUL-1988    ArticleIdent: Q32226

    The Cancel command clears the type-ahead buffer. This is a feature
 of the editor and is not considered a problem.
    Cancel is mapped to the ESC key in the default keyboard setup.


 51. Loading a TAGGED Section Reinitializes the Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00 tar76973
 Last Modified: 29-AUG-1988    ArticleIdent: Q32228

 When a TAGGED section is initialized (<arg> "section name"
 <initialize>), all current macros are destroyed before
 reinitialization.

 The curdate, curtime, etc., macros are reset, your extmake: settings
 are set to the default, and the OS-dependent and video-dependent
 sections of TOOLS.INI are read in. If you type <initialize>, the main
 section is read in place of the TAGGED section.

 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.



 52. The extmake Compile Switch Is Case Sensitive

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified:  1-MAY-1989    ArticleIdent: Q32242

 The following extmake entry will be ignored, causing the default
 command line to be used:

 extmake:C cl /c /Zi /Od %s

 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.

 Although there is no case sensitivity for the extmake switch name, the
 extension specified ("C" in this example) must be in lowercase. If the
 extension is not in lowercase, the help screen will show a separate
 entry for that extension, as follows:

    C   cl /c /Zi /Od %s
    c   cl /c /Zep /D LINT_ARGS %s

 The second command line will be used when compiling a C program.


 53. Loading Tagged Sections in OS/2 Version 1.10

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | docerr
 Last Modified: 29-AUG-1988    ArticleIdent: Q33348

 Problem:

 I have followed the instructions on Page 64 of the "Microsoft Editor
 User's Guide" for loading tagged sections in OS/2, but the editor
 never loads this section. My TOOLS.INI file has a tag titled [M MEP]
 containing assignments for both protected and real modes and a tag
 titled [M-10.0] for OS/2 protected-mode assignments. I am running
 Microsoft OS/2 Version 1.10.

 Response:

 Your [M-10.0] tag is not loaded in OS/2 Version 1.10 because [M-10.0]
 means OS/2 Version 1.00. The version number should be changed from
 10.0 to 10.10; your tag should be [M-10.10]. If you want the tag to
 work correctly for both OS/2 Versions 1.00 and 1.10, create a tag
 titled [M-10.0 M-10.10].

 This information is not contained in the "Microsoft Editor User's
 Guide."


 54. C.TMP Files in Current Directory

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-SEP-1988    ArticleIdent: Q34251

 Question:

 Every time I edit a file with the Microsoft Editor, I receive a C.TMP
 file in that directory. I am using DOS Version 2.10. Why is it
 creating this file?

 Response:

 The C.TMP file is where the editor keeps its information about
 previous files that have been edited. This file normally is called
 M.TMP; however, due to a limitation of DOS Versions 2.x, the editor
 believes its name is C rather than M.

 The files are placed in the directory where the file was edited
 because unless the INIT environment variable is set, the .TMP file is
 written to the current directory.

 When using M on DOS Versions 2.x, change the tag field of the TOOLS.INI
 from [M] to [C] and set the INIT environment variable to the directory
 that contains TOOLS.INI.



 55. How to Perform Spell Checking in M

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q34274

 Question:
    Does the Microsoft Editor have any spell checking capabilities?

 Response:
    The M editor does not have built-in spell checking. If you have a
 separate spell-check program you can write a macro to invoke it on
 your current file.
    For example, you could use the spell checker that comes with
 Microsoft Word Version 4.00 by doing the following:

     [M]
         ...
         Spell:=Arg "spell-am " Curfile Shell
         Spell:ALT+S

    The macro works as follows:

    1. Arg introduces an argument to the shell command.
    2. "spell-am" is the name of the spell-check utility
       included in Word Version 4.00.
    3. Curfile is the name of the current file you are editing. Note
       the space at the end of "spell-am "; this space is needed so the
       argument you pass to Shell is "spell-am YourCurrentFile" instead
       of "spell-amYourCurrentFile".
    4. The Shell command invokes COMMAND.COM and passes it the
       spell-am command. When spell-am completes its spell-check,
       it will return to the editor.


 56. Changing Height Switch Not Sufficient to Change Video Modes

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q34411

 Microsoft Editor does not immediately change video modes (CGA/EGA/VGA)
 when changing the numeric switch HEIGHT: to either 23, 41, or 48 in the
 TOOLS.INI file.

 For the new height setting to take effect, one of the following must
 be done:

 1. The INITIALIZE function can be invoked to force the editor to
    update its settings based on the switch values in TOOLS.INI. This
    will reset the video-display configuration. (INITIALIZE is ALT+F10
    for Quick and EPSILON emulation, SHIFT+F10 for BRIEF emulation, or
    SHIFT+F8 for the default emulation).

 2. The assignment can be made directly to the editor by invoking
    <arg> height:41 <assign>. In the default keyboard configuration,
    this would be ALT+A "height:41" ALT+=.

 3. While editing the "height:41" line in TOOLS.INI, move to the
    beginning of the line and enter <arg> <assign>, which is ALT+A
    ALT+= in the default keyboard assignments.

 The video mode is stored in the M.TMP file in the directory pointed to
 by the TMP environment variable; if TMP is not set, M.TMP is placed in
 the current default directory. Invoking the INITIALIZE function causes
 M to reset the settings in M.TMP based on the settings in TOOLS.INI.


 57. Accessing Switch Values in C Extensions

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  2-SEP-1988    ArticleIdent: Q35025

 There is no direct function call to access switch values defined in
 the editor, such as rmargin or vscroll or hike, in your C Extension.
 However, you can find the value by using fExecute() to switch to the
 help file, then use the psearch or msearch functions to locate
 rmargin. At the end of that line you will find the value associated
 with rmargin.

 The following is an example:

 fExecute("Arg \"<assign>\" Setfile");  /* switch to "<assign>" file   */
 fExecute("Mark");                      /* go to beginning of it       */
 fExecute("Arg \"rmargin\" Psearch");   /* search for "rmargin"        */
 fExecute("Pword");                     /* get the number after it     */

 You also can use the GetLine() function to read through the <assign>
 file; this method involves more coding, but it will run faster than
 using fExecute() to execute macros.


 58. Passing Textargs to M with the /E Switch

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-SEP-1988    ArticleIdent: Q35028

 Question:

 How can I pass textargs to the editor using the /e command-line
 switch?

 Response:

 Type in the name of the function you want the editor to execute. If
 you want to use more than one function, enclose the functions in
 double-quotation marks. If your functions require arguments, use the C
 syntax for specifying quotation marks within strings, i.e., the
 backslash escape character (\). Thus, a double-quotation mark within
 a string is specified with \".

 The following examples demonstrate various methods of passing
 command-line arguments to M:

 m /e psearch myfile

 This example invokes the Microsoft Editor on the file "myfile",
 passing it the command "psearch" to be executed immediately. The
 psearch will search for whatever string was last specified (in the
 search buffer).

 m /e "mark psearch" myfile

 This example again edits "myfile", but this time it passes two
 commands to M: "mark" and "psearch". The Mark command goes to the
 beginning of the file, and psearch searches forward for an occurrence
 of the search-string (which must have been specified in a previous
 search).

 m /e "arg \"search string\" psearch" myfile

 This example passes the editor the following string:

 "arg "search string" psearch"

 The \" characters are a C escape sequence that evaluates to a
 double-quotation mark ("); as a result, the entire string has a string
 embedded in it. The effect of this command is to tell the editor to
 search for the literal text "search string".

 m /e "arg \"\\\"a quoted search string\\\"\" psearch" myfile

 This is the most complicated case of argument passing. It
 passes the following string to the editor:

 "arg "\"a quoted search string\"" psearch"

 This command searches for the QUOTED literal text ""a quoted search
 string"".  The "\" and \"" are necessary to cause M itself to postpone
 evaluation of the double-quotation marks until actual search time.


 59. A Workaround for the MGREP Problem in M/MEP Version 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 29-JAN-1991    ArticleIdent: Q68386

 In the M/MEP Editor version 1.02, there is a problem in the MGREP
 function; it will fail to find some matches to the query in the file.
 (This is due to certain regular-expression matches failing when they
 shouldn't.) Below is a macro that will use the MEGREP.EXE utility to
 search for a string, and return the results in the compile window. The
 benefits are:

 1. It should be faster, especially under OS/2.

 2. If run under OS/2, it will be a background process enabling you
    to continue working.

 Macro Code
 ----------

 Add the following to your TOOLS.INI file. You can then assign it to a
 keystroke, if desired:

 megreplist:="*.c *.h"
 mg1:=copy arg "<megrep>" setfile mark emacsnewl mark paste begline
 mg2:="arg arg \"megrep \\\"" endline "\\\" " megreplist
 mg3:=" \" compile" begline arg endline execute setfile
 megrep:= mg1 mg2 mg3

 The following is another option, which avoids using an extra
 pseudo-file:

 megreplist:="*.c *.h"
 mg:= copy arg "<clipboard>" setfile            \
      begfile "megrep \"" endline "\" " megreplist  \
      begline arg arg endline compile setfile

 Notes
 -----

 1. The first macro is in three parts due to line-length limits of the
    knowledge base; the macro could be just one line. The second macro
    uses line continuation characters to achieve the same result as
    breaking up the first macro.

 2. The macro assumes that all files on disk are up to date.


 60. MHELP Driver Not Completely Compatible with QuickC Help Files

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc buglist1.02
 Last Modified:  5-MAR-1990    ArticleIdent: Q58603

 The MHELP driver cannot process some cross-references inherent to the
 QuickC Versions 2.00 and 2.01 help files. Results range from the MHELP
 message "Cannot Process Cross Reference," to hanging the computer. In
 general, direct reference to a QuickC help file from within the editor
 is fine. However, moving around within the help file system using the
 built-in cross-references produces unpredictable results.

 The MHELP driver seems unable to access unformatted text files such as
 header, source, and DOC files. For example, QuickC allows you to
 access both the README.DOC file and QuickC header files from within
 the help system. Attempting these feats from within M leads to one of
 the following problems:

 1. "Cannot Process Cross Reference," if file not found.

 2. DOS will hang the machine if the file is found.

 3. OS/2 may cause a SYS 1943 protection violation if the file is
    found.

 The M editor also cannot use the <back> menu option to access a
 previously viewed help file. Attempting this yields the message
 "Cannot Process Cross Reference" at the bottom of the screen. The
 syntax of the <back> cross-reference in unencrypted help form is
 help file to access the previous help screen. This undocumented
 feature is not allowed in MHELP.

 Certain series of cross references cause sporadic errors. You should
 be careful to avoid internal cross-referencing within the QC help
 files. The problem can be shown with the following sequence using the
 QuickC and QuickAssembler help files from within the M Editor.

    <arg> seg <F1> <TAB> <RETURN> <TAB> <RETURN> <TAB>

 This example reaches the help-contents window via the "seg" example
 program. Upon reaching this point, it may hang DOS with the run-time
 error R6003 or R6001. OS/2 displays a black box in the upper-right
 corner of the screen and may crash at this point.

 Microsoft has confirmed this to be a problem with the M Editor Version
 1.02. We are researching this problem and will post new information
 here as it becomes available.


 61. Compiling in M Produces No .OBJ File

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q35233

 If compilation from within the editor gives no .OBJ file when the
 same compilation outside of M succeeds in creating an object module,
 check the CONFIG.SYS files setting.

 In one case, a user had "files=25" while running under DOS Version
 3.20, which doesn't support a file setting greater than 20. If files
 exceed 20, DOS uses its default of eight files. When the user set
 "files=20" an .OBJ was created from a compilation within M.


 62. Creating Windows in M and MEP

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-MAY-1989    ArticleIdent: Q35235

 Question:

 How can I create multiple windows and edit multiple files with the
 Microsoft Editor?

 Response:

 Both horizontal and vertical windows can be created. You can have up
 to eight windows on the screen.

 To create a horizontal window, position the cursor on the screen where
 you would like the window break and press ARG WINDOW (ALT+A F6 in the
 default).

 This process creates a new window with a copy of the file you were
 currently editing. You then can load a different file into that window
 (ARG SETFILE ALT+A F2).

 To create a vertical window, position the cursor on the screen where
 you would like the window break and press ARG ARG WINDOW (ALT+A ALT+A
 F6 in the default). You then can load a different file into the
 window.

 Once you have several windows on the screen you can move around from
 window to window using the WINDOW command (F6 in the default setup).

 See also section 4.6 of the "Microsoft Editor User's Guide."

 Note: Each window must have a minimum of five lines and 10 columns to be
 created.


 63. M Does Not Respond to Changes in the Height Switch

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-MAR-1989    ArticleIdent: Q35252

 The Microsoft Editor does not change video modes (EGA/VGA) when
 changing the numeric switch height to either 23, 41, or 48 in the
 TOOLS.INI file.

 The INITIALIZE function must be invoked to reset the video display
 configuration. (INITIALIZE = ALT+F10 for Quick and EPSILON emulation,
 SHIFT+F10 for BRIEF emulation, or SHIFT+F8 for the default emulation).

 The video mode also is stored in the M.TMP file in the directory
 pointed to by the INIT environmental variable or the current default
 directory.


 64. Toggling Display Modes: 25-, 43-, and 50-Row Modes

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-NOV-1988    ArticleIdent: Q37628

 The following Microsoft Editor macro allows you to toggle the EGA
 display between 25-row mode and 43-row mode by pressing ALT+E:

 ;Macro to toggle 25/43 line EGA modes
     to23:=arg "height:23" assign
     to41:=arg "height:41" assign
     toggle23:=to23 arg "toggle41:alt+e" assign
     toggle41:=to41 arg "toggle23:alt+e" assign
     toggle41:alt+e

 The example below is a variation of the above macro. It allows you to
 toggle the VGA display between 25-row mode, 43-row mode, and 50-row
 mode by pressing ALT+E. Instead of switching back and forth between
 two modes, it cycles through all three.

 The macro is as follows:

 ;Macro to toggle 25/43/50 line VGA modes
     to23:=arg "height:23" assign
     to41:=arg "height:41" assign
     to48:=arg "height:48" assign
     toggle23:=to23 arg "toggle41:alt+e" assign
     toggle41:=to41 arg "toggle48:alt+e" assign
     toggle48:=to48 arg "toggle23:alt+e" assign
     toggle41:alt+e

 These macros should be placed in your TOOLS.INI file as described
 in Chapters 6 and 7 of the "Microsoft Editor User's Guide."

 Note: the "toggle" functions in these macros not only set the video
 mode, they also change the assignment of function ALT+E. This makes
 these macros similar to self-modifying code. For example, "toggle23"
 not only sets the video mode to 23-rows (with a call to "to23"), it
 also assigns ALT+E to "toggle41" by using the following sequence:

    arg "toggle41:alt+e" assign

 This technique is very useful in learning to write macros.


 65. "Softer" Should Be "Softcr" in M 1.0 User's Guide

 Product Version(s):
 Operating System:   1.00   | 1.00
 Flags: MS-DOS | OS/2
 Last Modified: 18-DEC-1989    ArticleIdent: Q35256
 ENDUSER | docerr

 On Page 61 of the "Microsoft Editor User's Guide," there is a
 documentation error. Softcr is listed as Softer; the correct listing
 is Softcr.


 66. Why Compiling after Editing in M Shows Old Errors

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q35258

 When using the M editor (either M.EXE or MEP.EXE) to correct compiler
 or assembler errors, and then compiling/assembling from within M using
 the COMPILE function, it is possible to get the old set of errors
 returned. If the errors occur, check that the autosave switch is set
 correctly. If autosave is off, the corrections are not saved before
 compilation.

 When turned on, the autosave boolean initialization switch causes the
 current file to be saved whenever it is switched away from. The
 default value is on, i.e., the files are automatically saved. The
 setting can be changed from within the editor using Arg textarg Assign
 or else in TOOLS.INI.

 In either case, specify noautosave: to prevent automatic saving of
 files, or autosave: to restore automatic file saving.


 67. How to Read the Contents of the M Editor Clipboard

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-MAR-1989    ArticleIdent: Q35259

 The Clipboard is contained in a pseudofile named <clipboard>. It can
 be loaded the same way any other file is loaded. The contents of the
 Clipboard pseudofile can be examined in several ways.

 The pseudofile <clipboard> can be loaded with the command sequence Arg
 textarg Setfile, which is ALT-A <clipboard> F2 in default keystrokes.
 This process loads the named file. The contents of the clipboard then
 can be seen on the screen, and even can be edited and saved as a
 separate file.

 The file also can be loaded by bringing up the information file with
 the INFORMATION function (SHIFT-F1).

 Finally, if the clipboard is the file most recently switched from, the
 SETFILE function (F2) alone will call it up.

 The information file describes the nature of the Clipboard contents in
 two ways. The Clipboard line appears in the form in the list of
 files, as follows:

 <clipboard>                    *n lines

 Additionally, at the bottom of the information file is a line that
 gives information in one of two ways, as follows:

 n lines in line clipboard

 n lines in box clipboard

 This information indicates whether the Clipboard holds a block of text
 or a stream of text.


 68. How to Write Selected Text to a File in M Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-NOV-1988    ArticleIdent: Q35260

 To write a block or stream of text from a file currently being edited
 to another file (either new or currently existing), do the following:

 1. Select text by using Arg (ALT+A) and the cursor movement keys.

 2. Put the text block or stream into the Clipboard by using the
    functions Copy (CTRL+INSERT, or + on the keypad) or Ldelete
    (CTRL+Y) or Sdelete (DELETE).

 3. Load the desired new file (see the "Working with Multiple Files"
    section of the "Microsoft Editor" manual).

 4. Paste (SHIFT+INSERT) the contents of the Clipboard into the new
    file.

 When writing to a file that does not yet exist, another procedure can
 be used, as follows:

 1. Write the selected text to the Clipboard as described above.

 2. Use Setfile to load the <clipboard> pseudofile the same way that
    other files are loaded.

 3. When the Clipboard contents appear on the screen, save the file to
    the desired new filename with Arg Arg textarg Setfile (ALT+A ALT+A
    filename F2). If a file by that name already exists, it will be
    overwritten.

 4. Return to the originally edited file with Setfile (F2).

 The second method can be put into a macro in one of the following two
 ways:

 1. Create a macro definition for copying to a file of prespecified name
    by using, for example, the following:

 sendtofil:=copy arg "<clipboard>" setfile arg arg "foo.txt" setfile
 setfile

 Assign the macro to a keystroke with an argument of the following
 form, for example:

 sendtofil:alt+s.

 This macro can be placed in TOOLS.INI, or can be the textarg in the
 command to enter a macro, as follows:

 Arg textarg Assign (ALT+A textarg ALT+=).

 2. Create a macro definition for copying to a file of any name by
    using two macros in sequence, for example, as follows:

 send1:=copy arg "<clipboard>" setfile arg arg
 send2:=setfile setfile

 Enter and assign them as described above. To execute this set of
 macros, select the text block or stream, execute the first macro, type
 the desired filename, then execute the second macro.


 69. Macro to Print Part or All of a File from within M

 Product Version(s): 1.00  1.02 | 1.00 1.02
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER |
 Last Modified: 21-AUG-1989    ArticleIdent: Q35261

 Microsoft Editor Version 1.00 contains no built-in primitives for
 printing; there is no actual "print" command. However, a set of steps
 can be performed involving the shell function, and a macro can be
 written to execute the steps conveniently. The 1.02 version of the
 Microsoft Editor does contain a print function. For more information
 on Version 1.02's print function, please see Section 4.9, "Printing a
 File," in the "Microsoft Editor User's Guide for MS OS/2 and MS-DOS
 Operating Systems."

 The following is a sample macro for the 1.00 Editor:

    print1:=copy arg "<clipboard>" setfile
    print2:=arg arg "PRINT.TMP" setfile
    print3:=arg "print PRINT.TMP" shell
    print4:=arg "del PRINT.TMP" shell setfile
    print:=print1 print2 print3 print4

 Note: The DOS PRINT command is a resident program. If you shell out of
 M and invoke the PRINT command for the first time, PRINT will be
 loaded above M and you will fragment memory. To prevent this, invoke
 the PRINT command before entering M, so that it will be loaded into
 low memory.

 The following explains the above example:

 1. copy: This copies the currently selected region into the
    clipboard. This way, you can select a region, using a boxarg or
    linearg, and then execute this macro to print it. Because the
    selected region defines what is to be printed, it can be modified
    to suit your needs.

 2. arg "<clipboard>" setfile: This loads the <clipboard> pseudo file
    as the current file.

 3. arg arg "PRINT.TMP" setfile: This saves the contents of the current
    file (which is now <clipboard>) to the file PRINT.TMP.

 4. arg "print PRINT.TMP" shell: This executes a DOS shell that prints
    PRINT.TMP.

 5. arg "del PRINT.TMP" shell setfile: This executes a DOS shell that
    deletes PRINT.TMP, then uses Setfile to return to the original file.


 70. The Difference between M and MEP

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35522

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 The Difference between M and MEP?

 M.EXE is the Microsoft Editor that runs under DOS or MS OS/2 real
 mode. MEP.EXE runs under MS OS/2 protected mode only. You may want to
 rename MEP.EXE to M.EXE. Functionally, the two editors are the same,
 except for slight differences in background compilation.


 71. Reassigning Default Keystrokes for Editor Functions

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35523

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Reassigning the Default Keystrokes for Editor Functions

 The function can simply be assigned to an unused keystroke, as
 follows:

 Home:Ctrl+H

 Consult your "Microsoft Editor User's Guide" for valid keystroke
 combinations. If necessary, you can unassign a keystroke by assigning
 it to the function Unassigned, as follows:

 Unassigned:Ctrl+Home


 72. Separating TOOLS.INI Entries for M

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35524

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Making Separate TOOLS.INI Entries for M if You Want to Have Different
 Configurations for M Running Under DOS, OS/2 Real Mode, or OS/2
 Protected Mode, or a Combination of the Three

 Various combinations of tags can be used in TOOLS.INI to set up
 different configurations for different environments. Each environment
 has its own recognized tag. The following is an example:

 Environment:                  Tag:

 MS-DOS                        [M-3.30] (your particular
                                        DOS version)
 OS/2 real mode                [M-10.0R]
 OS/2 protected mode           [M-10.0]

 The following is an examples of combinations:

 MS-DOS and OS/2 real mode     [M-3.30 M-10.0R]
 OS/2 real and protected mode  [M-10.0R M-10.0]

 If you have renamed M.EXE, the "M" used in the tag must be replaced
 with the name you are using for the editor. However, each M-XX.XX
 sub-tag only can appear once in a tag. For example, if you used the
 double tags above, and you were running M in OS/2 real mode, only the
 information from first tag would be loaded.

 By using these tags, only certain sections will be loaded from
 TOOLS.INI to initialize the editor, depending on the environment in
 which the editor is running. The statements in the [M] section are
 always loaded.


 73. Loading a New File into the Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35525

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note is
 available from Microsoft Product Support Services by calling (206)
 454-2030

 Loading a New File into the Editor

 Loading a new file into the editor can be done by using the keystrokes
 corresponding to the following functions:

 Arg textarg Setfile, where textarg is the name of the file you wish to
 load.


 74. Exiting without Saving

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35526

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Exit without Saving

 Normally, when the keystroke for exit is invoked, the file will be
 saved before exiting. However, typing the keystroke for "Meta" before
 the exit keystroke allows you to exit without saving your file.


 75. Merging Two Files Together

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35527

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Merge Two Files Together

 A separate file can be merged into the current file by using the
 keystrokes corresponding to the following functions:

    Arg Arg textarg Paste, where textarg is the name of file to be merged.


 76. Placing Control Characters in Text of File

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35528

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Placing Control Characters in the Text of My File

 The editor function "Quote" can be used to place special characters in
 your text. Use the keystroke assigned to "Quote", then enter the
 combination of keys necessary to produce the character. For example, a
 Form Feed would be a combination of the CTRL key and the L key.


 77. Compiling the Program Currently Loaded in Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35529

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Compile the Program Currently Loaded in the Editor

 The current file can be compiled by using the keystrokes corresponding
 to the following functions:

    Arg Arg textarg Compile, where textarg is the compiler command
    line typed as you normally would outside of the editor; however,
    the filename does not have to be the current file.

 The text switch "extmake" can be entered in TOOLS.INI to associate a
 frequently used command line with a particular file extension. The
 following is an example:

    extmake:c cl /Zi /Od %s

 The %s will be replaced with the current filename.


 78. Differences between the vscroll and hike Numeric Switches

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35530

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 The Differences between the vscroll and hike Numeric Switches

 The vscroll switch determines how many lines are vertically scrolled
 when the cursor is moved to a location not visible in (outside of) the
 current window but within vscroll lines of the edge of the current
 window.

 The hike switch determines the cursor position when an editing
 function moves the cursor more than vscroll lines beyond the edge of
 the current window. In this case, the cursor would appear hike lines
 from the top of the window.

 Note: Currently, these switches are broken. Even when vscroll is
 correctly set to 1, hike will overide it if hike has a greater value
 than vscroll. Until this problem is corrected, both switches must be
 set to 1 to scroll one line at a time.


 79. Making the Editor Default to Insert Mode

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35531

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Make the Editor Default to Insert Mode

 The boolean switch "Enterinsmode" can be set in the TOOLS.INI file to
 allow the editor to start up in insert mode rather than overtype mode.
 This switch is off by default, but can be set by adding the following
 entry to TOOLS.INI:

    enterinsmode:


 80. Saving Files Under a Different Name

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35532

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Save Your File Under a Different Name

 Saving a file under a different name can be done by including a
 textarg when saving a file without exiting, as follows:

    Arg Arg textarg Setfile, where textarg is the filename you wish to
    save the file under.


 81. "Unable to Open Swapping File c:\temp\m-0029.vm"

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35533

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 "Unable to Open Swapping File c:\temp\m-0029.vm No Such File or
 Directory" Error

 The editor assumes that environment variables are set so that
 important editor information can be loaded from and saved to your
 disk. The following is an example:

    SET INIT=c:\init
    SET TMP=c:\temp

 In this example, c:\temp would be the directory that would hold
 temporary or swapping files, usually named M-0029.VM. This file is
 used to allow the editor to switch to previous files. C:\INIT would
 hold TOOLS.INI and M.TMP. The swapping file also would be stored here
 if the TMP variable was not set. If neither of these variables is
 set, the swapping file would be stored in the root directory and M.TMP
 would be stored in the current directory.

 However, if the TMP variable is set to a directory that does not
 exist, or if extra characters were included after the "p" in "c:\temp"
 such as a space or a semicolon, the swapping file will not be created
 and the error above will be generated.


 82. Why the Editor Cannot Find or Load TOOLS.INI

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35534

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Why the Editor Can't Find or Load the TOOLS.INI File

 There are several reasons this problem may occur. First of all, you
 may have never created a TOOLS.INI file. If TOOLS.INI is not in the
 working directory, the INIT environment variable must specify the
 directory that contains this file. Within the TOOLS.INI file, there
 must be a tag that has the same name as the editor (M.EXE), as
 follows:

    [m]

 If you have renamed the editor you also must rename the tag. Entries
 concerning the editor then would follow after this tag. Under DOS
 Versions 2.x, the Microsoft Editor looks for a [c] tag rather an [m]
 tag or whatever you have renamed M.EXE to.


 83. Keeping the Editor from Saving Backup Files

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35535

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 How to Keep the Editor from Saving Backup Files

 The text switch "Backup" determines what happens to old copies of
 files that are modified. If you do not wish to keep any backup files,
 a value of "none" can be given, as follows:

    Backup:none

 Backup files can be saved in two ways. A value of "bak" will save the
 previous version of the file with a .BAK extension. A value of "undel"
 will save a history of old copies of your file in a hidden directory
 disk space.

 Older copies can be restored by using UNDEL.EXE. Typing "undel" will
 list all the backup copies; "undel <filename>" will either restore the
 file, or if there is more than one backup, it will allow you to choose
 which version you would like to restore. Because these files take up
 actual disk space, they should be periodically removed from the disk
 by using EXP.EXE. Typing "exp" will delete these files permanently.


 84. How to Write and Use C Extensions

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35536

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 C Extensions and How to Write and Use Them

 C extensions allow you to further customize the editor by creating new
 editor functions and switches through programs that you write in the C
 programming language. They are much more powerful than macros because
 macros depend on the existence of editor functions.

 C extensions are compiled with a special memory-model that does not
 use a main() function, but rather uses special names and structures
 that the editor alone recognizes. They are linked with an object
 module that makes low-level functions used within the editor itself
 available to be called by your C extension. The file produced from
 linking is separate from the main program but is loaded into memory
 with the editor. The editor then will call your module whenever you
 invoke one of your C extension functions.


 85. Developing Macros

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  4-MAY-1989    ArticleIdent: Q35537

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Develop my Own Macros

 Developing a macro is similar to programming in a high-level language.
 Each macro represents a command. Instead of a collection of library
 routines, you have a collection of editor functions. You begin with an
 idea of a process that you would like to be performed by simply
 pressing one keystroke.

 Suppose you would like to be able to move the cursor to the lower-left
 corner of the editing window. You know you can do this "manually" with
 the arrow keys that are assigned to the "Left" and "Down" editor
 functions. However, it can be simplified more. "Meta Down" moves the
 cursor to the bottom of the window; "Meta Begline" moves the cursor to
 the first column of the line. Together, these functions will do the
 job.

 This macro must now be given a unique name, for example, "Bottom". The
 TOOLS.INI statement would look as follows:

    Bottom:=Meta Begline Meta Down

 A macro also can be a combination of other macros. The following is an
 example:

    Waydown:=Meta Down
    Wayleft:=Meta Begline
    Bottom:=Waydown Wayleft

 Suppose that the "Meta Begline" command did not exist. You would need
 to find some way to know that the cursor is in the first column.
 Almost all of the editor functions have boolean (TRUE/FALSE) Return
 Values that can be useful in developing macros.

 For the "Bottom" macro, you know that "Begline" will at least move the
 cursor to the first nonblank character on the line. Any further cursor
 movement would have to be done using "Left". "Left" returns TRUE when
 the cursor moves and FALSE when the cursor does not move.

 You would want to move left until the cursor does not move anymore,
 i.e., move left until "Left" returns FALSE. The editor allows you to
 do this with Macro Conditionals. The following is an example:

    Bottom:=Begline :>LT Left +>LT Meta Down

    :>LT   defines a label LT
    +>LT   if Left returns TRUE, go to label LT
           if Left returns FALSE, continue

 Macro Conditionals and a table of Return Values can be found in the
 "Microsoft Editor User's Guide."

 The final step is to assign the macro to a keystroke, as follows:

    Bottom:CTRL+END


 86. Saving without Exiting

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote
 Last Modified:  6-JAN-1989    ArticleIdent: Q35538

 The following information is taken from an application note called
 "Microsoft Editor Questions and Answers." The application note also is
 available from Microsoft Product Support Services by calling (206)
 454-2030.

 Saving without Exiting

 You can save a file without exiting by using the keystrokes
 corresponding to the following functions:

    Arg Arg Setfile.

 A macro can be written to perform these functions in one keystroke
 (Alt+S), as follows:

    Save:=Arg Arg Setfile
    Save:Alt+S


 87. None Assignment Must Be Lowercase

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-NOV-1988    ArticleIdent: Q35648

 When using the backup:none option in the TOOLS.INI file, the none
 cannot begin with a capitol N.

 The "None is an illegal setting" error will be generated if you have
 Backup:None (capitol N) in the TOOLS.INI file.

 The correct form is backup:none


 88. Width Function Not implemented

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q35649

 Some graphics cards allow the monitor to go into modes greater than 80
 columns. The Microsoft Editor has a function called Width to allow
 more than 80 columns, however, this function has not yet been
 implemented.

 This feature is under review and will be considered for inclusion in
 a future release.


 89. M on an AMDEK System 88 XT Clone

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 30-SEP-1988    ArticleIdent: Q35817

 Problem:

 When running M on an AMDEK System 88, which is an XT clone, the M
 editor hangs the machine requiring a warm boot. The machine was using
 an EPC Keyboard that is an AT style keyboard.

 Response:

 This is a known incompatibility with this hardware configuration and M
 Version 1.00. AMDEK is aware of this problem and has a patch that they
 can send you. To obtain a patch, call AMDEK at (408) 435-2832. The
 patch contains the following three files:

 READ.ME
 CLREPC.EXE
 SETEPC.EXE.

 The problem is that M was checking the keyboard, which in this case
 was an AT style keyboard, and assuming it was running on an AT clone.
 This situation caused the hang.

 By running SETEPC.EXE, a switch is set so M sees the keyboard as a XT
 keyboard and everything functions properly. CLREPC.EXE clears this
 switch.


 90. Placing the NULL Character in a File with M/MEP

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q35819

 Problem:

 I would like to place the null character in a file using M or MEP. I
 have tried using the Quote function and successfully put other
 non-printable characters in the file, such as the bell character.
 However, attempts to place a null in the file with the Quote function
 were ignored. Is this possible?

 Response:

 No. Placing null characters in a file with M/MEP is not possible. The
 editor uses null-terminated strings internally, as well as NULL return
 values from some character functions. Because the editor uses the null
 character, you are not allowed to use null.


 91. Case Sensitivity of Switches

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-OCT-1988    ArticleIdent: Q36415

 The BACKUP text switch is case sensitive with the arguments given it.
 The arguments "undel", "bak", and "none" need to be lowercase, otherwise
 an error will be reported.



 92. Intitialize function is Shift+F8

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  2-NOV-1988    ArticleIdent: Q36567

 There is a documentation error on Page 64 of the "Microsoft Editor for
 MS OS/2 and MS-DOS Operating Systems User's Guide". The line

 3. Invoke the Initialize function (press F10).

 should read as follows :

 3. Invoke the Initialize function (press SHIFT+F8)

 The F10 should be replaced with SHIFT+F8. SHIFT+8 is the default.


 93. Percent (%) Character in Filenames

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 20-OCT-1988    ArticleIdent: Q36570

 The Microsoft Editor cannot handle a percent sign as the first
 character in the filename (%test.dat). While this is a valid DOS
 filename, it will cause garbage to be printed on the status line and
 may generate a run-time error.

 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.

 If you fill a line with 250 characters (the maximum), then press HOME
 to go to the beginning of the line and delete the line by pressing
 CTRL-Y, the editor will crash with the following error:

         run-time error R6003
         -integer divide by 0

 Both of the above problems only occur when a percent sign is used as
 the first character in the filename. To work around this problem, do
 not use the percent sign as the first character.



 94. How Tabs Are Treated in the Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 14-OCT-1988    ArticleIdent: Q36580

 Problem:

 Some text editors preserve tab characters automatically. These editors
 maintain tabs (ASCII 9 characters) as they are stored in a file, and
 distinguish between tab characters and spaces.

 The Microsoft Editor translates tab characters into spaces. This
 behavior only affects lines that you modify. If you load and save a
 file without changing any lines of text, the lines are written back to
 disk with all tab characters and spaces intact. Only the modified
 lines are affected by this conversion.

 It is not possible to disable this translation of tab characters into
 spaces in a modified line.

 In the Microsoft Editor, "tab"  is both a function name and the name
 of a key. The TAB key is assigned to the tab function by default. As a
 function, tab is nothing more than a move-to-next-column movement
 function. The placement of columns in determined by the TABSTOPS
 switch.

 When ever you edit a line, tab characters are translated to space
 characters using the FILETAB switch. So modified lines in the file are
 stored in the editor with spaces only. The FILETAB switch determines
 how the editor translates tab characters to spaces when reading in a
 line of text. If ENTAB is set to 1 or 2, then FILETAB also determines
 how the editor translates spaces to tabs when you save the file to
 disk. (Again, only modified lines are affected.)

 If you need to view the tabs as they are situated in your file you can
 use the TABDISP switch to show you which spaces will be compressed
 into a tab character at the next write to the disk file.


 95. 43- and 50-Line Modes

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q36613

 The M editor can make use of the 43-line EGA text mode and 50-line VGA
 text mode. The "height" numeric switch in the TOOLS.INI file specifies
 the number of lines used in the editing window; however, this number
 does NOT include the dialog and status display lines. Thus, to use 43
 lines of text you must set height=41; to use 50 lines you must set
 height=48.


 96. Microsoft System Journal M macros Fail

 Product Version(s): 1.00 1.01 | 1.00 1.01
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 20-OCT-1988    ArticleIdent: Q36798

 In the September 1988 issue of the "MS System Journal," the article
 entitled "Customizing the Features of the M Editor Using Macros and C
 Extensions" contains erroneous examples.

 Both of the macros below fail in Version 1.00. Only the Bigprint macro
 fails in Version 1.01.

 The following is an example:

 Macro 1)

 ;print selected text macro
 print1:= copy arg "<clipboard>" setfile
 print2:= arg arg "TEMP.DAT" setfile setfile
 print3:= arg "PRINT TEMP.DAT" shell
 print4:= arg "DEL TEMP.DAT" shell
 printa:=print1 print2 print3 print4
 Printa:alt+P

 The above macro is supposed to print selected text. In M Version 1.00
 it works correctly the first time it is called from inside a file.
 However, it fails on subsequent calls to the macro prior to exiting
 the file. It does work correctly in the unreleased Version 1.01
 referenced in the article.

 The following macro is supposed to print the entire file. Instead, it
 prints only the line on which the cursor sits when the macro is
 called. As mentioned above, this fails in both Versions 1.00 and the
 unreleased Version 1.01 referred to in the article on Pages 59-72.

 The following is an example:

 Macro 2)

 ;bigprint macro to print entire file
 select1:= arg ppage
 select2:= arg arg "endoffile" mark
 select3:= arg mpage
 select4:= arg "endoffile"
 selectall:= select1 select2 select3 select4
 bigprint:=meta +>nometa cancel selectall meta :>nometa meta printa

 bigprint:Alt+z
 ;end of bigfoot macro.


 97. meta Anomalous Behavior

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 31-OCT-1988    ArticleIdent: Q37072

 The following macros written for the M editor exhibit anomalous
 behavior for the function modifier meta. It appears that meta cannot
 modify itself, as demonstrated by the following macros.

 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.

 Consider the following macros:

    MetaTest:= meta meta +> "meta off"=>0 :>1 "meta on":>0
    MetaTest:alt+0
    ; the above macro is supposed to check to see if the function
    ; modifier meta, invoked by the F9 key, is on or off. Compare
    ; the results of this macro with the macro immediately following.
    MetaTest1:= meta +> "meta off"=>0 :>1 "meta on":>0
    MetaTest1:alt+1
    ; the MetaTest1 macro fails to differ from the MetaTest macro in
    ; a significant manner. in contrast, consider the following
    ; macro, employing the insetmode function modifier.
    InsertTest:=insertmode insertmode +> "ins off"=>0 :>1 "ins on":>0
    InsertTest:alt+2.


 98. MASM m.exe Is Different than FORTRAN m.exe when Using DOS Comp

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | h_fortran
 Last Modified:  6-JAN-1989    ArticleIdent: Q38015

 Question:

 When I do a Comp command at the DOS prompt, why do the FORTRAN Version
 4.10 and MASM Version 5.10 packages contain m.exe files that differ at
 offset 15F9F, where the MASM m gives 37 and the FORTRAN m gives 38?
 Which one should I use for mixed-language programming?

 Response:

 This behavior is an error that was discovered after MASM Version 5.10
 was released, but before FORTRAN Version 4.10 was shipped. You can see
 this by invoking the editor and entering SHIFT+F1, which gives you
 file information. The date given in the MASM file is Jan. 29, 1987
 (hex37) when it should be Jan. 29, 1988 (hex 38). Other than this
 character in the date, they are identical, so you can use either one
 for mixed-language programming.


 99. Selecting Large Text Blocks with Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  4-MAY-1989    ArticleIdent: Q38309

 Question:

 When I want to select a large block of code for the clipboard, I press
 ALT+A, then the DOWN ARROW key until I reach the last line I want to
 select. This process is very slow if the block I am selecting is
 several pages long (almost a whole file). Is there a way to move
 faster to select a block than by using the CURSOR key (such as the
 equivalent of ^K-B and ^K-K in Wordstar)?

 Response:

 CTRL+PGDN (Ppara) serves this purpose, as documented on Pages 91 and
 104 of the "Microsoft Editor for MS OS/2 and MS-DOS Operating Systems:
 User's Guide." This key sequence will move you to a new paragraph each
 time you press the keys. If the movement sequence you want to use
 contains an Arg, it is either used by the command or canceled.

 A faster method is to define a couple of macros to help out. First, we
 need a macro that will mark the beginning spot in the text, as
 follows:

    txtmark:=arg arg "first" mark
    txtmark:alt+t

 The second macro automates using the mark as an argument, as follows:

   callmark:=arg "first"
   callmark:alt+u

 You can put these lines in your TOOLS.INI file.

 To use this pair, move to the first spot, press ALT+T, then move up or
 down using any movement keys to the second spot. Finally, press ALT+U
 and press a key that allows a markarg as an argument. (The Copy and
 Ldelete functions are among these.) Note: no highlighting occurs, so
 you'll have to be careful.

 Note: if you want the argument to be entire lines rather than a box,
 the cursor MUST be in the same column when you press ALT+U as it was
 when you pressed ALT+T. If you put it in a different column, you will
 be selecting a box argument rather than a line argument.


 100. Moving to the Beginning of the Line with Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-JAN-1989    ArticleIdent: Q38310

 Question:

 Is there a way to go to column 1 of the screen with a key sequence
 instead of pressing the LEFT ARROW key until the cursor stops at
 column 1? I find myself wasting a lot of time doing this repetitive
 chore. The HOME key only takes me to the beginning of the text on the
 line, not the beginning of the line, which is where I want to be if I
 want to delete a line, for example. I currently use ^K-S with the
 Wordstar extension.

 Response:

 Meta Begline (F9 HOME in the standard configuration) will do it. If
 you'd like it on one key, you can assign the functions to a key using
 the macro facility.


 101. Inserting a Line from Clipboard into File with Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1989    ArticleIdent: Q38311

 Question:

 I am confused by the way a line is inserted from the clipboard into a
 file. It seems to depend on whether Insert is On or Off. Also, it
 sometimes pushes the other lines down and sometimes it pushes the
 existing line to the right. I see no consistency to all this. Can you
 explain the concepts?

 Response:

 The Insert mode has no bearing on line insertion. However, how you
 delete the line has a lot to do with it. In general, don't use the
 DEL key for multiple-character deletions. It is usually assigned to
 the sdelete function, which always deletes a stream of text, as
 documented on Page 107 of the "Microsoft Editor for MS OS/2 and MS-DOS
 Operating Systems: User's Guide."

 A stream is all of the text between the place where the cursor was
 when you typed Arg and where it is when you press sdelete, regardless
 of the beginning and ending cursor columns or how many lines are
 contained in the region. Whenever you mark an area and press sdelete
 (the DEL key), you will delete the STREAM you have marked, even
 though the region highlighted may look different.

 It's usually best to use CTRL+Y (Ldelete) for deletions which begin
 and end on different lines. Note that the COPY key (CTRL+INS) does not
 accept stream arguments, therefore, it always copies the highlighted
 area.


 102. Use a Colon when Assigning a Macro to a Keystroke

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 12-JAN-1989    ArticleIdent: Q39574

 There is a documentation error on Page 50 of the "Microsoft Editor
 User's Guide." Section 6.3.2 incorrectly shows a semicolon when
 assigning a macro to a keystroke as follows:

    Header;ALT+H

 The correct example should contain a colon as follows:

    Header:ALT+H


 103. Quote Function and Typing in Graphic Characters in M

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q39806

 Question:

 I want to input some graphics characters in the M editor. However,
 when I try to input the ASCII character 31 using the ALT key and the
 numeric keypad, the M editor beeps and displays the following message:

    "ctrl+_ is not assigned to any editor function"

 For the ASCII character 30, the M editor displays the following
 message:

    "ctrl+^ is not assigned to any editor function."

 How can I input those characters?

 Response:

 Use the editing Quote function in the M editor. The Quote function is
 associated with CTRL+P by default. After the Quote function is
 invoked, the following keystroke is taken literally. This function is
 mentioned in the "Microsoft Editor for MS OS/2 and MS-DOS Operating
 Systems User's Guide" on Page 105.

 The first 32 characters in the ASCII character set have two
 conflicting uses. As standard ASCII characters, they are used for
 communications control and printer control. They are also used by IBM
 to represent some useful graphics characters.

 Using the Quote function in the M editor can prevent these ASCII
 characters from being interrupted as control characters.


 104. M Hangs if the textarg Given to ArgCompile Is Incomplete

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-JAN-1989    ArticleIdent: Q40235

 If you want to compile a program inside the M editor using the
 following command, textarg should contain the full compile line as
 typed at the DOS prompt:

    Arg Arg textarg ArgCompile

 The following is an example:

    cl /Zi /Od demo.for

 If textarg contains just the name of the program (demo), the hard disk
 light will come on and the message "compilation complete" will appear
 on the bottom of the screen even though demo.for was not compiled.

 If textarg contains the full program name (demo.for), your computer
 hangs if you press SHIFT+F3. Sometimes, there will be lost clusters
 and allocation errors as reported by chkdsk.

 This problem was not encountered under OS/2.



 105. Redirecting Errors to an Error File in M

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-MAY-1989    ArticleIdent: Q40177

 Under DOS, M Version 1.00 will store the error messages in the M.MSG
 file. This file is located in the directory the TMP environment
 variable points to. If TMP is not set, this file is located in
 the current working directory. Under OS/2, MEP uses named pipes, so
 there is no file to look at.


 106. FileWrite() Function Fails to Write Back Out to the File

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1989    ArticleIdent: Q40356

 Problem:

 I have a problem using the FileWrite Function programming with the M
 and MEP Editor Version 1.00. I want to read a file (EXAMPLE.DOC) and
 write exactly the same in a new file (FOO.DOC).

 Response:

 To test the example below, you only have to create a file named
 EXAMPLE.DOC. See the compiler switches at the end of this article. The
 second file FOO.DOC is created, but it is never written to it always
 has zero length.

 This is a problem with MEP Version 1.00's FileWrite() function. This
 is one of the problems that kept the filter extension described in the
 "Microsoft Systems Journal" September 1988 from working in Version
 1.00.

 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.

 The following is a short example where the problem (Function FileWrite
 does not write) occurs:

 #include "ext.h"
 #define TRUE    -1
 #define FALSE   0
 #define NULL    ((char *) 0)

 flagType pascal EXTERNAL Write(
 unsigned int argData,
 ARG far * pArg,
 flagType fMeta)
 {
     flagType flg;
     PFILE pFile;
     char  *p = "EXAMPLE.DOC";
     char  *w = "FOO.DOC";

     if((pFile = FileNameToHandle(p,NULL)) == 0)
     {
         pFile = AddFile(p);
         FileRead(p, pFile);
     }
     flg = FileWrite(w, pFile);
     return (flg);
 }

 struct swiDesc  swiTable[] ={
     { NULL, NULL, 0 }
 };

 struct cmdDesc  cmdTable[] ={
     {"Write", Write, 0, NOARG },
     {NULL,  NULL, 0, 0}
 };

 void EXTERNAL WhenLoaded (void)
 {
     SetKey("Write", "alt+w");
     DoMessage("Write function now loaded.");
 }

 /*

 *** Compiler switches I used ***

 cl /c /Gs /Asfu %1.c
 cl /Lp /AC /Fe%1.dll exthdrp.obj %1.obj skel.def

   */


 107. Optimizing C or QuickC 2.00 Required for Writing C Extensions

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C S_QuickC
 Last Modified: 17-MAY-1989    ArticleIdent: Q39997

 Question:

 I would like to customize the Microsoft Editor by writing C
 extensions. Can I use QuickC Version 1.00, QuickC Version 1.01, or
 QuickC Version 2.00?

 Response:

 No. You must use the Microsoft C Version 4.00 Optimizing Compiler or a
 later version to write C extensions to the Microsoft Editor. QuickC
 Versions 1.00 and 1.01 cannot be used because they do not support the
 required switch /Asfu.

 However, Version 2.00 does support the /Asfu switch when using QCL.
 Therefore, you can use Version 2.00 and QCL to create C extensions.

 For more information, see Pages 68 and 83 of the "Microsoft Editor for
 MS OS/2 and MS-DOS Operating Systems: User's Guide."


 108. Search and Replace Macro for M Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 12-JAN-1989    ArticleIdent: Q39998

 Question:

 Can you write a macro to perform a search and replace on a particular
 string? When I try to do so, the replace function prompts me for a
 string argument. I want the replace function to read the string from
 the macro.

 Response:

 The following is an example of a replace macro that accepts its
 argument from inside the macro:

    myreplace:=replace "oldtext" newline "newtext" newline

 When the myreplace macro is invoked, all the occurrences of "oldtext"
 string, from the cursor position to the end of the file, are replaced
 with the "newtext" string. The use of the newline function allows the
 macro to respond to the replace-function prompt for a string argument.

 To define the myreplace macro and assign it to the F12 key, enter the
 following keystrokes from inside the M editor:

    ALT+A
    MyReplace:=replace "oldtext" newline "newtext" newline
    ALT+=

    ALT+A
    MyReplace:F12

 To execute the myreplace macro, press the F12 key.


 109. M.TMP Reset When Window Closed

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | mep buglist1.00
 Last Modified: 15-MAY-1989    ArticleIdent: Q40681

 Question:

 When I invoke the M editor, open a second window (arg F6 or arg arg
 F6), and close the first window (meta F6), my M.TMP file is reset. The
 only file in my M.TMP file is the one that I edited to perform this
 operation. Is there a way to prevent this from happening?

 Response:

 This phenomena occurs whenever you close a window that has had a file
 opened in it. Hence, if you open a file in the second window, then
 close the second window, M.TMP is reset. To avoid this behavior, don't
 close a window in which a file has been opened.

 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.



 110. QHMEP.DLL Remaps Two Keys in MEP Version 1.00

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 16-MAY-1989    ArticleIdent: Q41324

 Problem:

 I have remapped the keys CTRL+S and CTRL+P in MEP Version 1.00 to the
 psearch and up functions. After loading the extension QHMEP.DLL, which
 comes with the Version 1.06 OS/2 SDK, the two keys CTRL+S and CTRL+P
 are not mapped to psearch and up anymore. Furthermore, these keys
 cannot be reassigned back to psearch and up. I seem to be locked out
 of using these keys.

 Response:

 This problem occurs because the editor is taking over these keys,
 preventing them from being reassigned.

 Microsoft has confirmed this to be a problem in MEP Version 1.00. We are
 researching this problem and will post new information as it becomes
 available.



 111. Useful Macros for the Microsoft Editor

 Product Version(s): 1.00    |  1.00
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q40755

 Below are macros for the Microsoft Editor that allow you to save a
 marked portion of a file and insert it into another file. Also, there
 are macros that speed up marking large areas of text.

 To save a marked area of a file, mark the area and invoke this macro
 by typing ALT+V. Note that although the macro is broken onto two lines
 here, you should put it on one line in your TOOLS.INI file.

 savemark:=copy arg "command /c del c:\\t" shell arg "\\t" setfile
           refresh paste setfile
 savemark:alt+v

 A one-key way to include the file in another file is to use the macro
 by typing ALT+I:

 insertmark:=arg arg "\\t" paste
 insertmark:alt+i

 To mark the top and bottom of the text area, use these macros. Type
 ALT+T to place the marker, then ALT+U to use it. Type CTRL+INS or
 CTRL+Y to copy or delete the text. Note that if your cursor is not in
 the same column when you type ALT+U as when you typed ALT+T, the area
 marked will be a box rather than a set of lines. Note also that the
 marked area will NOT show up on the screen.

 tempmark:=arg arg "temp" mark
 usemark:=arg "temp"
 tempmark:alt+t
 usemark:alt+u



 112. Using Brief Emulation and Tags in TOOLS.INI

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 17-MAY-1989    ArticleIdent: Q41475

 If you invoke a tagged section from your TOOLS.INI when using the
 Microsoft editor with brief keystroke emulation, some of the key
 assignments will revert back to the default.

 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.

 As demonstrated in the following example, some of the keystrokes are
 reassigned to the default keystrokes if you rename the BRIEF.INI file
 to be TOOLS.INI and then add a new tag section:

 [m-mono]
     height:23
     fgcolor:07
     errcolor:0F
     stacolor:70
     infcolor:70

 Start editing a file, then bring in this new tag field by typing the
 following:

    arg "mono" shift+f10

 The following demonstrates this behavior and all compile lines revert
 to default:

    window             will change from F1 to unassigned
    help               will change from ALT+H to F1
    argcompile         will change from ALT+F10 to F5
    save               will change from ALT+W to undefined
    linemark           will change from ALT+I to undefined
    linetotop          will change from CTRL+T to undefined
    leftsideofwindow   will change from SHIFT+HOME to undefined
    rightsideofwindow  will change from SHIFT+END to undefined
    createhorizwindow  will change from F3 to undefined
    createvertwin      will change from F4 to undefined
    deletewindow       will change from F5 to undefined



 113. Minimum Requirements for Writing a M Extension

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 16-MAY-1989    ArticleIdent: Q42241

 Question:

 What files and software do I need to be able to write an extension for
 the Microsoft Editor?

 Response:

 To create C extensions, you need to have the following files and
 software present in your current directory (or directories listed in
 the PATH or INCLUDE environment variables, as appropriate):

 1. The Microsoft C Optimizing Compiler Version 4.00 or later;
    or Microsoft QuickC Version 2.00

 2. The Microsoft Overlay Linker Version 3.60 or later; or the
    Microsoft Segmented-Executable Linker Version 5.01

 3. EXTHDR.OBJ (supplied with the editor) or EXTHDRP.OBJ (a file
    supplied with the editor for creating protected-mode extensions)

 4. EXT.H header file provided with the editor

 5. SKEL.DEF, the standard definitions file supplied with the editor;
    to be used with all extension

 You need a minimum 150K of available memory for the editor to load a C
 extension at run time in addition to the size of the extension itself.


 114. 43- and 50-Line Modes with the IBM 8514 Monitor

 Product Version(s): 1.00 1.02
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 fixlist1.02
 Last Modified: 28-JUL-1989    ArticleIdent: Q42365

 The Microsoft Editor does not go into 43- or 50-line line mode on the
 IBM 8514 monitor.

 Version 1.00 of the Microsoft Editor does not support higher line
 modes with the IBM 8514 monitor. Regardless of the switch setting you
 give in the TOOLS.INI file, it always comes up in 25-line mode.

 For example, setting the height:41 or height:48 switch in the
 TOOLS.INI file results in the Microsoft Editor coming up in 25-line
 mode.

 Microsoft has confirmed this to be a problem in Version 1.00 of the
 Microsoft Editor. This problem was corrected in the Microsoft Editor
 Version 1.02.


 115. Savecur and Restcur Save Relative Position in File, on Screen

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42758

 The Microsoft Editor functions Savecur and Restcur save the current
 cursor position relative to the file and the screen. Therefore, the
 screen will be restored exactly as it appeared when the Savecur
 function was invoked.

 The following macros were intended to scroll the screen up and down
 while leaving the cursor position relative to the terminal screen to
 be stationary:

 ReposDown:=Savecur Meta Up Up Restcur
 ReposDown:Ctrl+Down

 ReposUp:=Savecur Meta Down Down Restcur
 ReposUp:Ctrl+Up

 Because Savecur and Restcur preserve and restore the cursor position
 relative to the screen, the macros appear to do nothing. But actually,
 each executes correctly. For example, the ReposDown does the following:

 1. Savecur : saves the current position relative to the file and the
              screen

 2. Meta Up : moves the cursor to the top of the screen

 3. Up      : moves the cursor up one line, (thus scrolling the screen
              down one line)

 4. Restcur : restores the screen to the original configuration
              (appears as if nothing had happened)

 One way to achieve the desired result is to use the Mark function. The
 Mark function saves the current location in the file. The relative
 screen position is not preserved, whereas the Savecur and Restcur
 functions do save the relative screen position.

 The following macros give the desired result:

 ReposDown:=Arg Arg "tag" Mark Meta Up Up Arg "tag" Mark Up
 ReposDown:Ctrl+Up

 ReposUp:=Arg Arg "tag" Mark Meta Down Down Arg "tag" Mark Down
 ReposUp:Ctrl+Down

 The word "tag" is an arbitrary tagname for the Mark function.


 116. Copy Is a Reserved Word

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42763

 The word copy is a reserved word in the Microsoft Editor. If you write
 an M extension and name it "copy", the editor will load but not
 execute your extension.

 If you name the function (for example) cpy rather than copy, it will
 work correctly.

 The following declaration incorrectly uses the reserved word "copy."
 Renaming the the function "cpy" will resolve the problem:

 flagType pascal EXTERNAL copy (argData, Parg, fMeta)
 unsigned int argData;
 ARG far *Parg;
 flagType fMeta;



 117. A C Extension to Select an Arbitrary Number of Lines of Text

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | extension highlight select
 Last Modified:  1-JUN-1989    ArticleIdent: Q43006

 To select an arbitrary number of lines of text in the Microsoft
 Editor, I must use the Arg function, then use the DOWN ARROW key until
 the desired number of lines are selected. This is inconvenient if more
 than a few lines are to be selected.

 This article provides a simple editor extension that selects the
 number of lines you specify.

 For information on loading the function, refer to the M editor
 reference manual.

 To invoke the function, use the Arg key to introduce the argument
 (i.e., the number of lines to be selected), then press the key
 assigned to the function. In Version 1.00 of M, the selected text will
 not be highlighted.   In Version 1.02 of M, the selected text will be
 highlighted, however further cursor movements will change the selected
 area without altering the highlighted area.

 ================ Make file ===============

 BASE=select
 CFLAGS=-c -W2 -Asfu -Gs
 LINKFLAGS=/NOI /NOD

 $(BASE).obj : $(BASE).c
     cl $(CFLAGS) $(BASE).c

 $(BASE).exe : $(BASE).obj
     link exthdr.obj $(BASE), $(BASE), \
     $(LINKFLAGS),clibcer.lib;

 ================ select.c ================

 #include "ext.h"
 #include <stdlib.h>

 #define TRUE    -1
 #define FALSE   0
 #define NULL    ((char *) 0)

 flagType pascal EXTERNAL Select (argData, pArg, fMeta)
 unsigned int argData;
 ARG far * pArg;
 flagType fMeta;
 {
     int  nCount, i ;

     if (pArg->argType == TEXTARG)
         if (nCount = atoi (pArg->arg.textarg.pText))
             {
             for (i = 0 ; i < nCount ; i++)
                 fExecute ("Arg Down") ;
             }

     return TRUE;
 }

 struct swiDesc  swiTable[] =
 {
     {   NULL, NULL, NULL    }
 };

 struct cmdDesc  cmdTable[] =
 {
     {"Select", Select, 0, TEXTARG},
     {NULL,  NULL, NULL, NULL}
 };

 WhenLoaded ()
 {
      SetKey("SELECT","ALT+B");
      return TRUE;
 }


 118. Cannot Use Standard Device Names as Filenames

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q43074

 You cannot use the standard device names (COMx, LPTx, and CON) as the
 base filename in the Microsoft Editor.

 For example, the command "M COM1.C" under DOS will attempt to open the
 communications port for editing and will hang the computer.

 This information has been tested for the following devices: COM1,
 COM2, LPT1, LPT2, CON. The different devices give slightly different
 results. COM1 and COM2 will hang the computer immediately, but the
 others will give errors or hang when the file is saved.

 The protect-mode editor behaves in the same fashion.


 119. Accessing Predefined Switches in C-Extension

 Product Version(s): 1.02   |  1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | FindSwitch
 Last Modified: 17-MAY-1989    ArticleIdent: Q43436

 When writing a C extension for Microsoft Editor Version 1.02, you can
 access the predefined editor switches through the function
 FindSwitch(). FindSwitch() is intended to be used to access the values
 of the predefined editor switches, not to modify the values. Modifying
 the switches through FindSwitch() has undefined results.

 The following code fragment retrieves the value of the switch
 "tabstops" for use in your C extension:

 #include "ext.h"
       .
       .
       .

 PSWI pTabStops ;
 int  nTabStops ;
       .
       .
       .

 pTabStops = FindSwitch ("tabstops") ;
 nTabStops = *(pTabStops->act.ival) ;

 Any change to the value of the switch "tabstops" made outside your
 C extension will be reflected in the value of nTabStops inside your
 C extension.

 You can find the FindSwitch() prototype in the include file EXT.H. The
 function FindSwitch() is not available in the Microsoft Editor Version
 1.00.

 The structure, swiTable, consists of a series of structures, each
 structure describing a user-defined switch. The purpose of swiTable is
 to add user-defined, not predefined, switches. It is incorrect to name
 the predefined switches in the switch table. For that reason the
 following example is incorrect as it names "tabstops," a predefined
 switch:

 struct swiDesc swiTable [] =
  {
   {"tabstops", &nTabStops, NUMERIC | RADIX10}   /*  INCORRECT  */
   { NULL, NULL, 0}
  } ;

 Do not modify the predefined switches through the switch table. You
 can change the values of the predefined switches from within an
 editing session or in TOOLS.INI.


 120. The Editor Can Be Very Slow When MEP Memory Limit Is Pushed

 Product Version(s): 1.00 1.02
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q44000

 Problem:

 I have a file FOO, which is 21733 bytes long and contains 850 lines.
 When I perform the following steps the compiler appears to hang. In
 fact, however, the compiler is being forced to go to disk for its own
 memory management.

 When performing the steps described below with the README.DOC from C
 Version 5.10 (which is 64964 bytes) and running on a 16mHz machine,
 after Arg Refresh, it took almost 30 seconds for MEP to return
 control.

 This problem is due to the fact that MEP does its own memory
 management. When you do Arg Refresh, MEP must reread the buffer
 containing the modified file from disk. In addition, MEP must store
 back to disk the buffer containing the last block of text pasted to
 the file. This swapping of two large files is what causes the delay.

 Microsoft has confirmed this lack of speed to be a limitation with
 Version 1.00 and 1.02 of the Microsoft Editor. We are researching this
 problem  and will post new information as it becomes available.

 To duplicate this problem, perform the following steps:

 1. Invoke the following to run the editor:

       [C:\]m foo

 2. Make some changes to modify the buffer.

 3. Issue the following command to the editor:

       arg "bar" setfile

    The editor responds "File c:\bar does not exist, create?"

 4. Respond "y" for yes. You are now in bar's buffer.

 5. Issue the following command to read in the original contents of the
    file:

       arg arg "foo" paste

    This process should work correctly.

 6. If you now want to get rid of the new buffer, issue the following
    command:

       arg refresh

    The editor responds with something similar to the following:

       "Do you really want to delete the buffer?"

 7. Respond "y" for yes.

    The editor appears to hang.


 121. Why Syntax Errors Might Not Display While Compiling in M

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  1-MAY-1989    ArticleIdent: Q43647

 Question:

 While inside the Microsoft Editor, I compiled a program that I know
 contained syntax errors. The message "Compilation Complete - return
 code is x" (where "x" is an integer value) appeared, signifying that
 an error had occurred while compiling.

 I pressed SHIFT+F3 to display those errors and the message "No more
 compilation messages" was displayed on the bottom of the screen. Why
 aren't my program's error messages displayed inside the editor?

 Response:

 You see error messages only if the compiler or linker runs correctly
 and passes the error messages in the correct format to the editor; if
 the compiler itself fails, you will not see any messages.

 Because M spawns the compiler, you could be running out of file
 handles. You know that the system has run out file handles if the
 M.MSG file is not created. Setting files=20 in your CONFIG.SYS file
 should correct the problem.

 Other possible causes for not getting error messages are as follows:

 1. You could be running out of memory. You can check this by shelling
    out of M.EXE (with SHIFT+F9) and issuing the DOS CHKDSK command to
    display the available memory.

 2. The compiler might not be able to find the specified file.
    Consider the following example, in which you invoke M.EXE as
    follows:

       C:\> M c:\c5\source\test.c

    If you compile the program with ARG COMPILE, the information line
    displays the following:

       CL /c /Zep /D LINT_ARGS test.c.

    The compiler will not find TEST.C in the current directory, so an
    error is returned.

    For more information, query on the following phrases:

       Microsoft Editor
       full path

 3. The EXTMAKE switches might have been incorrectly modified in the
    TOOLS.INI file, as in the following example:

       EXTMAKE:bas BC /Zi /O %s

    The line above is incorrect because it is missing a semicolon (;)
    at the end. The command line following the extension must be complete.
    Both the Microsoft BASIC Compiler and MASM will prompt you for
    additional information if a semicolon is not at the end of the line.

 4. Make sure the options used are valid for the compiler. In the
    following example, the option /Fa is an invalid option for the
    QCL.EXE compiler:

       QCL /Fa filename.c

 5. The compiler must be in the current path. If the compiler fails to
    execute, due to some problem external to the editor, M will
    display the ambiguous message "No more compilation messages."

    A good way to check the validity of the Compile command and to check
    for the presence of the compiler is to type in the compile line with
    all of the options directly from DOS.


 122. MEP GP Faults After Consecutive Searches.

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified:  1-JUN-1989    ArticleIdent: Q44887

 MEP gets an access violation and crashes after several searches for a
 string.

 Microsoft has confirmed this to be a problem with MEP.EXE Version
 1.00. This problem was corrected in MEP.EXE Version 1.02.

 Note: Version 1.02 of the Microsoft Editor is only available with
 FORTRAN 5.00. The documentation required for M and MEP Version 1.02
 make it impossible to release except with a major language release.

 The text file that caused MEP to fail was 54400 bytes and contained
 the string "error" in 81 different locations. To reproduce this
 problem, search for the string "error". The default keystrokes are

    Arg "error" F3

 for the first search, and the following for each additional search:

    F3

 On the 81st search, the Microsoft Editor for Protect, generates a
 General Protection Violation.


 123. Status Line Input with a Blinking Cursor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | GETINPUT.ARC S12311.EXE
 Last Modified: 13-SEP-1989    ArticleIdent: Q44925

 Question:

 Is it possible in the Microsoft Editor to write an extension that will
 accept a line of input from the user, preferably from the status line?

 Response:

 Version 1.02 of the Microsoft Editor offers a very convenient way to
 do this. The GetString() callback function performs exactly this type
 of input. Version 1.00 of the Editor, however, does not have such a
 callback. It is possible to put together a routine that reads user
 input using the ReadChar() function in M Version 1.00. However, since
 ReadChar() waits for the next available character, there is no
 convenient way to flash a cursor during input when using this
 approach.

 The function provided below is a status-line input routine that does
 provide a flashing cursor. It uses the KbHook() and KbUnHook()
 functions to prevent the editor from scanning the keyboard and then
 reads the keyboard directly using the kbhit() and getch() functions
 from the C run-time library.

 An example C extension that demonstrates this function is available
 in the Software\Data Library. This file can be found by searching on
 the keyword GETINPUT, the Q number of this article, or S12311.
 GETINPUT was archived using the PKware file-compression utility.

 Status-Line Input Routine
 -------------------------

 #include "ext.h"
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <conio.h>

 #define TRUE            1
 #define FALSE           0

 typedef unsigned        BOOL;

 char *GetInput( int BufLen, char *theBuffer );

 /* GetInput provides a means of getting user input from the status line
  * with a blinking cursor in a manner similar to M 1.02's GetString().
  * KbUnHook is used to capture keyboard input. KbHook restores normal
  * keyboard reading to the editor.
  *
  * Receives:    BufLen - Length of input buffer
  *              theBuffer - Pointer to input buffer
  *
  * Returns:     A pointer to the modified buffer, or NULL if ESC was
  *              used to cancel input.
  */
 char *GetInput(
     int             BufLen,
     char            *theBuffer )
 {
     char            Key;                        /* ASCII code of key */
     int             i = 0;                      /* Position in buffer */
     BOOL            CursorOn = TRUE;            /* State of cursor */
     int             FlashCount = 0;             /* Cursor state counter */
     int             CursorToggleCount = 100;    /* Iterations between changes
                                                    in cursor state */
     char            *r;                         /* Return pointer */

     /* Unhook the keyboard so that the editor no longer intercepts
      * keystrokes.
      */
     KbUnHook();

     /* Get keyboard input from user, stopping when ESC or ENTER is hit.
      * Characters not in the range of 32 to 127 are ignored.  Backspace
      * will work properly.  No more than (BufLen - 2) characters may
      * be entered.
      */
     do
     {
         /* Flash a cursor while waiting for the next keypress.
          */
         while( !kbhit() )
         {
             if( ++FlashCount == CursorToggleCount )
             {
                 FlashCount = 0;
                 CursorOn = !CursorOn;
                 if( CursorOn )
                 {
                     strcat( theBuffer, "_" );
                     DoMessage( theBuffer );
                 }
                 else
                 {
                     theBuffer[i] = '\0';
                     DoMessage( theBuffer );
                 }
             }
         }

         /* Snarf the key
          */
         Key = (char)getch();

         /* Handle backspace.
          */
         if( (Key == 8) && (i > 0) )
         {
             theBuffer[--i] = '\0';
             DoMessage( theBuffer );
         }

         /* Handle normal character.
          */
         if( (Key >=32) && (Key <= 127) && (i < BufLen - 2) )
         {
             theBuffer[i++] = Key;
             theBuffer[i] = '\0';
             DoMessage( theBuffer );
         }
     } while( (Key != 13) && (Key != 27) );

     /* If ESC was pressed, toss the input and NULL the input buffer,
      * else perform a little cleanup.
      */
     if( Key == 27 )
     {
         theBuffer[0] = '\0';
         DoMessage( theBuffer );
         r = NULL;
     }
     else
     {
         if( CursorOn )
             theBuffer[i] = '\0';
         DoMessage( theBuffer );
         r = theBuffer;
     }

     /* Restore normal keyboard input.
      */
     KbHook();

     return( r );
 }


 124. CALLTREE Produces No Warnings When Out of Disk Space

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C H_MASM H_Fortran S_PasCal
 Last Modified: 23-JUN-1989    ArticleIdent: Q45618

 The CALLTREE.EXE utility shipped with the Microsoft Editor (included
 with MASM, Optimizing C, FORTRAN, and Pascal) does not produce a
 warning if it runs out of disk space while writing output files. It
 simply closes the file being currently written and attempts to produce
 the next file. If the disk has no space free, the file will be created
 and closed with a length of 0 (zero) bytes. No error messages are
 produced in any case.

 Microsoft is aware of this limitation of CallTree. The error checking
 and messages features are under review and will be considered for
 inclusion in a future release.


 125. Documentation Errors in "Configuring On-Line Help" for M 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 11-SEP-1989    ArticleIdent: Q46272

 There are several documentation errors in the section "Configuring
 On-Line Help" on Page 101 of the "Microsoft Editor User's Guide for MS
 OS/2 and MS-DOS Operating Systems." This is the documentation for the
 Microsoft Editor (M) Version 1.02, which first became available with
 FORTRAN Version 5.00. These errors prevent access to M help. The
 documentation says to add the following tagged section to your
 TOOLS.INI file:

    [m-help.mxt mep-help.mxt]
    helpfiles:path\file.hlp

 The tag header should be as follows:

    [m-help mep-mhelp]

 Including ".mxt" prevents M from accessing help.

 Also, in the paragraph labeled Number 2 that describes installation
 for on-line Help when running under OS/2 protected mode only, there is
 a misprint. The following sentence refers to a nonexistent file
 "MHELP.DLL":

    MHELP.DLL is an extension to the editor.

 The correct file is MHELP.PXT, so the sentence should read as follows:

    MHELP.PXT is an extension to the editor.


 126. CMD.EXE Shell Fails with Incorrect COMSPEC

 Product Version(s): 1.00 1.02
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified: 26-SEP-1989    ArticleIdent: Q47763

 Question:

 When I attempt to shell out of the MEP editor environment via the
 Shell editor function (SHIFT+F9), why does the following message
 appear at the bottom of the screen?

    Spawn failed on C:\OS2\CMD.EXE   - No such file or directory

 Response:

 The problem is usually due to an incorrect setting of the COMSPEC
 environment variable in the CONFIG.SYS file. A faulty setting of this
 variable, which informs the operating system of the command
 interpreter's location, prevents the DOS EXEC system call from finding
 and executing the command interpreter. Use the following procedure to
 eliminate the problem:

 1. Verify that the CMD.EXE file is in the directory specified by the
    COMSPEC environment variable.

 2. Ensure the syntax correctness of the COMSPEC setting. There should
    be no spaces on either side of the equal sign, and a carriage
    return must appear immediately following the last character of the
    path and filename setting.

        Correct example:       SET COMSPEC=C:\OS2\CMD.EXE<cr>

        Incorrect examples:    SET COMSPEC = C:\OS2\CMD.EXE<cr>
                               SET COMSPEC=C:\OS2\CMD.EXE;<cr>
                               SET COMSPEC=C:\OS2\CMD.EXE<space><cr>

 Under MEP 1.02, the COMSPEC environment variable is used to locate the
 command interpreter. If the command interpreter is not found according
 to the COMSPEC variable, the "Spawn failed...." error message is
 displayed. MEP Version 1.02 does not use the PATH environment variable
 for additional searching of CMD.EXE.

 Under MEP Version 1.00, however, the PATH variable is used when the
 CMD.EXE is not found via the COMSPEC setting. Hence, if the spawn
 failure error occurs when attempting to shell out of the MEP 1.00
 environment, examine the COMSPEC setting and also verify that CMD.EXE
 is traversed by the search path of the PATH environment variable in
 the CONFIG.SYS.


 127. Curtime Function Pulls In Time Editor Was Invoked

 Product Version(s): 1.00 | 1.00
 Operating System:   OS/2 | MS-DOS
 Flags: ENDUSER | buglist1.00 fixlist1.02
 Last Modified: 28-JUL-1989    ArticleIdent: Q46790

 The Microsoft Editor Version 1.00 does not implement the Curtime
 function correctly. The manual states that the current time will be
 inserted at the cursor when this function is invoked. Actually, the
 time the editor was invoked is inserted at the cursor. To get around
 this problem, simply initialize the editor before calling the Curtime
 function.

 Microsoft has confirmed this to be a problem in Version 1.00. This
 problem was corrected in Version 1.02 of the Microsoft Editor.

 The following macro illustrates how the Curtime function is invoked.
 This macro should be placed in the TOOLS.INI file under the [m] tag.

    time:=Curtime
    time:ALT+T

 When editing a file, pressing ALT+T inserts the time that the editor
 was loaded at the cursor. To obtain the current system time, either
 invoke the Initialize function by pressing SHIFT+F8 before ALT+T, or
 change the macro as follows:

    time:=Initialize Curtime
    time:ALT+T

 Now, pressing ALT+T inserts the current system time at the cursor.

 This function is documented on Pages 30 and 96 of the "Microsoft
 Editor User's Guide," which is contained in the "CodeView and
 Utilities, Microsoft Editor, Mixed-Language Programming Guide" manual
 from the Microsoft C Optimizing Compiler Version 5.10.


 128. QUICK.INI Needs Modification for Use with M 1.02 or MEP 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 28-JUL-1989    ArticleIdent: Q46802

 To use the QUICK.INI file provided with the Microsoft M Editor Version
 1.02 as the TOOLS.INI file, it is necessary to make two modifications
 to the file. Without the modifications the editor gives the following
 error messages:

    Argcompile is not an editor function               press any key...
    Help is not an editor function                     press any key...

 To get past the Argcompile error message, add the following line to
 the TOOLS.INI file before the Argcompile:F5 line:

    Argcompile:=arg compile

 The Argcompile macro is also defined in the TOOLS.PRE file provided
 with the editor. The Help:F1 line is a leftover from previous versions
 of the editor and is not implemented in this version. To eliminate the
 Help error message, either delete or comment out the Help:F1 line.


 129. Documentation Error for "Mark" Functions in M User's Guide

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  2-AUG-1989    ArticleIdent: Q47236

 On Page 179 of the Version 1.02 "Microsoft Editor for MS OS/2 and
 MS-DOS Operating Systems: User's Guide," there is a documentation
 error. In the section of the reference table describing the "Mark"
 function, the marker deletion and marker definition descriptions are
 reversed. To define a marker at the cursor position, the correct
 syntax is Arg Arg textarg Mark. To delete a marker definition, the
 syntax is Arg Arg textarg Meta Mark. The entries SHOULD appear as
 follows:

    Entry                         Function
    -----                         --------

    Arg Arg textarg Mark          Defines a file marker at the
                                  initial cursor position. This
                                  does not record the file marker
                                  in the file specified by the
                                  markfile switch, but allows you
                                  to refer to this position as
                                  textarg.

    Arg Arg textarg Meta Mark     Deletes a marker definition.

 On Page 39, the reference to Arg Arg textarg Mark is correct.


 130. CopyBox Function Doesn't Work Across Files

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | S_C S_Pascal H_Fortran H_MASM
 Last Modified: 26-SEP-1989    ArticleIdent: Q47765

 CopyBox is a C-extension function for the Microsoft editor that is
 designed to copy square regions of text from one location to another,
 including to another file.

 This function works properly when copying to the same file, but fails
 when copying to another file. The function appears to work
 successfully, but the copied text does not appear in the target file.
 This lack of functionality has been corrected in Version 1.02 of the
 editor.

 You can work around this problem by using the GetLine and PutLine
 functions. A line can be read from the source file, trimmed to get the
 proper portion of the line, and then written to the target file. This
 procedure must be followed for each line of the box to copy.


 131. Getting SYS2070 While Using MEP

 Product Version(s): 1.02
 Operating System:   OS/2
 Flags: ENDUSER | MEP
 Last Modified: 26-SEP-1989    ArticleIdent: Q47767

 Problem:

 When I start MEP, I receive the following error:

      |---------------------------------------------------------------|
      | SYS2070: The system could not demand load the                 |
      | application's segment. MSHELP HELPGETINFO is in error.        |
      | For additional detailed information also see message SYS0127. |
      |---------------------------------------------------------------|
      |                     End the program                           |
      |_______________________________________________________________|

 After selecting "End the program," I receive the following message:

    A non-recoverable error occurred.
    The process ended.

 Response:

 The MEP program is picking up an old version of MSHELP.DLL. The likely
 source is from the OS/2 Presentation Manager Toolkit. To correct this
 problem, replace the old MSHELP.DLL with the current MSHELP.DLL.

 If there is no MSHELP.DLL on the LIB path, then MEP loads and seems to
 function correctly, but there will be no help available.


 132. Possible Explanation for "Cannot Close This Window" Error

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 26-SEP-1989    ArticleIdent: Q47770

 Problem:

 Under M Version 1.00 I have two horizontal windows open, each viewing
 separate files. When I attempt to close a window (META+WINDOW or F9+F6),
 I sometimes get the error message "Cannot close this window." Under
 seemingly similar conditions, this error message does not occur and
 the window closes properly.

 Response:

 This message occurs when you attempt to close a window that contains
 modified text. If you want to abandon edits on the file, you can
 reread the file using SHIFT+F7 and then successfully close the window.


 133. ECH.EXE Utility Is Used Internally by the Microsoft Editor

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 26-SEP-1989    ArticleIdent: Q47772

 ECH.EXE is a character echoing utility that is included with the
 Microsoft Editor (M) Version 1.00. This utility is mentioned in the
 appendix of the editor's user guide simply because it is an external
 file.

 The file is used with the Setfile command using wildcards. When
 issuing the command "Arg *.* Setfile", M will use ECH.EXE to display
 the files in alphabetical order. If ECH.EXE is not found in the
 current path, the message "NO MATCHING FILES" is generated.

 If this error message occurs in a subdirectory that does contain
 files, then ECH.EXE is not being found.

 M 1.02 does not use this external file. The utility has been
 incorporated into the editor.


 134. Invoking M or MEP with the /D Switch Prevents Initialization

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | reinitialize
 Last Modified: 26-SEP-1989    ArticleIdent: Q48687

 Invoking the Microsoft M editor with the /D switch to prevent it from
 initializing from the TOOLS.INI file also prevents the Initialization
 function (SHIFT+F8) from reading the TOOLS.INI file.

 There is currently no workaround for this designed limitation other
 than to exit the editor and re-invoke M without using the /D switch.


 135. Microsoft Editor (M) Version 1.02: On-Line Help Not Loaded

 Product Version(s): 1.02
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-SEP-1989    ArticleIdent: Q48130

 Trying to access on-line help after initializing (reloading the editor
 settings from TOOLS.INI) generates the following message:

    Online Help Not Loaded

 The following steps will demonstrate the problem:

 1. M (Start the editor, with or without a file.)

 2. F1 (Request on-line help -- success.)

 3. SHIFT+F8 (Initialize editor settings.)

 4. F1 (Request on-line help -- receive error message.)

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


 136. Invalid Arg Filename Followed By F2 Causes Screen Error

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.00
 Last Modified: 26-SEP-1989    ArticleIdent: Q48871

 When trying to read in a file with the Arg Setfile function, an
 improper filename returns an operating system error. If the Microsoft
 editor (M) is in split-screen mode, any horizontal divider bars are
 lost in MEP. The error contains the two following lines, which cause
 the screen to scroll one position erroneously:

    Next filSYS1041: The name specified is not recognized as an
    internal or external command, operable program, or batch file.

 In M, screen integrity is preserved, but the following error is
 returned:

    Bad command or filename.

 For example, invoke arg (ALT+A) to start an argument and enter about
 20 or so shifted numbers (e.g. ^&%$&^%$^%$#^%$#^%$@%(^&*(*^&&*), and
 then invoke Setfile (F2).

 The screen becomes corrupted and the next keystroke may crash the
 editor with an integer divide by 0 (zero).

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


 137. How to Search and Replace Control Characters with M Editor

 Product Version(s): 1.00 1.01 1.02 | 1.00 1.01 1.02
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 10-OCT-1989    ArticleIdent: Q49010

 To search for and replace control characters with the M editor, use
 the following procedure:

 1. Invoke the search and replace function (CTRL+\).

    The editor prompts with "Query Search String:".

 2. Invoke the quote function (CTRL+P).

 3. Type the control character and press ENTER.

    The editor prompts with "Replace string:".

 4. Invoke the quote function.

 5. Type the control character.


 138. Background Color Greater Than Seven Causes Region to Blink

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 26-FEB-1990    ArticleIdent: Q57585

 It is possible to configure both the background and foreground color
 of the various text items that the Microsoft Editor (M) displays. If
 you attempt to set the background color to a color greater than seven,
 the color region blinks. This behavior, however unusual, is expected,
 and is documented in the "Microsoft Editor for MS OS/2 and MS-DOS
 User's Guide" on Page 87.

 The following M Editor color switches control the colors of various
 text display regions:

    Switch        Controls
    ------        --------

    hgcolor       Background and text color
    hgcolor       Search highlight colors
    infocolor     Information message colors
    selcolor      Cursor highlight colors
    stacolor      Status line colors
    wdcolor       Window border colors

 The following are the colors these switches can be set to:

    Black                 0
    Blue                  1
    Green                 2
    Cyan                  3
    Red                   4
    Magenta               5
    Brown                 6
    Light Gray            7
    Dark Gray             8   Will blink when set to background
    Light Blue            9   Will blink when set to background
    Light Green           A   Will blink when set to background
    Light Cyan            B   Will blink when set to background
    Light Red             C   Will blink when set to background
    Light Magenta         D   Will blink when set to background
    Light Yellow          E   Will blink when set to background
    White                 F   Will blink when set to background

 These colors are set in your TOOLS.INI as follows:

                +------------------- Background Color
                |
                v

    colorswitch:BF <---------------- Foreground Color

 The following example, inserted in your TOOLS.INI, sets the foreground
 and background colors of the editing windows (90 percent of the
 screen):

    fgcolor:62 < ------------------- Green

            ^
            |
            +----------------------- Brown


 139. M Editor Version 1.00 Does Not Clear Compiler Error Buffer

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER  | buglist1.00 fixlist1.02
 Last Modified: 11-OCT-1989    ArticleIdent: Q49536

 When using the compile function from within the editor, the errors
 stored in memory are not cleared. Thus, if you do not go through all
 errors with the nextmsg function, the errors remain even if another
 compile is done. Therefore, if the second compile process does not
 produce any errors, the errors from the previous compile show up and
 put the cursor on an unpredictable line.

 To work around this problem, make sure you look at all of your error
 messages from each compile.

 Microsoft has confirmed this to be a problem with the Microsoft Editor
 Version 1.00. This problem was corrected in Version 1.02 of the
 Editor.


 140. Configuring On-Line Help for M 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q49576

 The following is the correct way to configure on-line help for the
 Microsoft Editor (M) Version 1.02 for both MS-DOS (real mode) and
 OS/2 (protected mode).

 Copy files from the distribution disk, as follows:

 1. Under MS-DOS real mode, copy M.HLP and MHELP.MXT to any directory
    specified in the PATH environment variable in the AUTOEXEC.BAT
    file.

 2. Under OS/2 protected mode, copy M.HLP and MHELP.PXT to any
    directory specified in the PATH environment variable in the
    STARTUP.CMD file. Also copy MSHELP.DLL to any directory listed in
    the LIBPATH variable in the CONFIG.SYS file.

 3. For both DOS and OS/2, perform both the preceding steps.

 Other Microsoft products include .HLP files that the editor can
 read. If you want to add additional .HLP files to help, you must
 include the following tagged section in your TOOLS.INI:

 1. Include the following tagged section:

       [M-MHELP]                    ; For DOS real mode

       [MEP-MHELP]                  ; For OS/2 protected mode

       [M-MHELP MEP-MHELP]          ; For both DOS and OS/2

 2. Add the following switch to load in the help files:

       Helpfiles: M.HLP .BAS:C:\QB\QB.HLP .C.H:C:\QC\QC.HLP .PAS:C:\QP\QP.HLP

    This is an example of help files that are loaded upon startup of M
    or MEP. Help searches QB.HLP first when the file has a .BAS
    extension, QC.HLP when the current file has a .C or .H extension,
    and QP.HLP when the current file has a .PAS extension. Please note
    that these help files come with their respective language, not M
    1.02.

 For more information on this topic, refer to the Microsoft Editor for
 MS OS/2 and MS-DOS Operating Systems: User's Guide" that accompanies
 with M 1.02.


 141. Undocumented Switch "Sethelp" for M Version 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 24-JAN-1991    ArticleIdent: Q50012

 If you have the M (or MEP) Editor version 1.02 configured for online
 help, you can use the undocumented "Sethelp" switch to load additional
 help files within the editor by using the following syntax:

    Arg textarg Sethelp      ;ALT+A textarg ALT+S

 Textarg corresponds to the full pathname of the .HLP file you want to
 load. By default, the sethelp function is mapped ALT+S.

 For example, load the QC.HLP help file that comes with QuickC with the
 following command:

    ALT+A D:\QC\QC.HLP ALT+S

 Now you could place the cursor on printf (or any other C language item
 that is in the Help file) and press F1 to get help on that topic.


 142. Printing Double Quotation Marks from within an M Editor Macro

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50223

 To get double quotation marks ("") printed from within a macro in the
 M Editor, use the backslash key (\) followed by the double quotation
 marks (""). The following example (placed in the correct section of
 the TOOLS.INI file) demonstrates how this is done:

    text:=arg "say \"hello\"" paste
    text:alt+z

 In this case, pressing ALT+Z inserts the following string into your
 text, with the double quotation marks around the word hello.

    say "hello"


 143. Controlling the Use of Tabs in the Microsoft Editor

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50588

 The Microsoft Editor (M) provides the following two ways of using tab
 characters:

 1. Treat tabs as real characters.

 2. Convert each tab into a series of spaces. This is controlled
 through the use of the "realtabs" switch. Other switches may also
 effect the way tabs appear to be handled by the editor.

 The following chart, taken from Section 7.2.6 of "Microsoft Editor for
 MS OS/2 and MS-DOS User's Guide" describes the switches dealing with
 tabs.

 1. realtabs

    On by default, controls whether or not tabs are treated as real tab
    characters.

 2. entab

    Controls the extent to which the editor converts a series of tabs
    and spaces to tabs when saving a file. The following are the valid
    choices:

       0 - The editor does not replace spaces by tabs. If realtabs is off,
           tabs are converted to spaces.

       1 - (default) The editor can replace a series of tabs and spaces by
           tabs when the tabs fall outside of quoted strings.

       2 - The editor will replace all series of tabs and spaces with
           tabs.

    Note: The entab switch only effects the lines you modify during the
    current editing session.

 3. filetab

    Controls the meaning of tab characters on a disk file. If realtabs
    is on, the filetab switch determines tab alignment. If realtabs is
    off, the filetab switch determines how the editor translates tab
    characters to spaces when a line of text is modified.

    If entab, as described above, is set to 1 or 2, filetab also
    determines how the editor translates spaces to tabs when you save
    the file to disk.

    Note: The filetab switch only effects the lines you modify during
    the current editing session.

 4. tabalign

    When off (the default), the cursor may be placed anywhere inside a
    column of a tab character. If turned on, along with realtabs, the
    cursor is placed to the first column position of tab characters.

 5. tabstops

    Determines the size of columns associated with the TAB and BACKTAB
    ( SHIFT+TAB) keys. This only moves the cursor and has no effect on
    the actual tab character. The default value is 4.

    The following example sets up tabs so that they act the same way
    they do in other editors, such as QuickC or Word:

       realtabs:yes
       tabalign:yes
       graphic:tab
       trailspace:yes
       filetab:4

 The trailspace switch is needed to use tabs on blank lines. The
 tabdisp switch may also be used with realtabs to make the tab
 characters visible on the screen.


 144. Mhelp Function Is Always Assigned to SHIFT+F1

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 17-JUL-1990    ArticleIdent: Q50642

 In the Microsoft Editor (M) Version 1.02, the mhelp function is like
 any other function that can be assigned to any key. However, mhelp is
 always assigned to SHIFT+F1 unless this key is unassigned using the
 unassigned keyword in the m-mhelp block of the TOOLS.INI file.

 It is perfectly acceptable to assign the mhelp to any key, and it will
 work properly with that keystroke. However, in addition to the newly
 assigned key, the mhelp function is always assigned to SHIFT+F1. This
 assignment can be taken out by placing the following line in the
 [M-MHELP] section of the TOOLS.INI file:

    [M-MHELP]
    unassigned:shift+f1


 145. Adding helpwindow in TOOLS.INI as a Switch

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q50644

 To get the Microsoft Editor (M) to recognize helpwindow as a switch in
 the TOOLS.INI file, the switch must be under the [M-MHELP] or
 [MEP-MHELP] tag section. The example below shows what a TOOLS.INI file
 might look like:

    [M-MHELP MEP-MHELP]
    nohelpwindow:

    [M MEP]
      .
      .

 The helpwindow switch can also be set in the environment by typing the
 following:

    <arg> nohelpwindow: <assign>


 146. Searching in the M Editor with Regular Expressions

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 30-NOV-1989    ArticleIdent: Q51324

 Question:

 When using the M Editor, every time I execute a search command using a
 Regular Expression, the editor takes the command literally and doesn't
 recognize the textarg as a Regular Expression. How can I get this
 search to work?

 Response:

 The correct method is as follows:

       arg arg textarg <search_function>

               arg -> ALT+A
           textarg -> A Regular Expression (i.e., ^S[te].*end)
 <search_function> -> Psearch, Msearch, Replace, Qreplace

 For more information, see Chapter 5, Pages 51-63, in the "Microsoft
 FORTRAN Microsoft Editor User's Guide."


 147. mgreplist Incorrectly Documented As megreplist in Example

 Product Version(s): 1.02
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 15-MAR-1990    ArticleIdent: Q51622

 The examples given on Pages 180 and 181 of the FORTRAN "Microsoft
 Editor User's Guide" incorrectly identifies the megreplist command as
 mgreplist. The documentation shows the following:

    megreplist:="DATA.FIL *.FOR $INCLUDE:*.H"

 This should be the following:

    mgreplist:="DATA.FIL *.FOR $INCLUDE:*.H"

 The megreplist macro does not exist and should be changed to
 mgreplist.

 The example above sets mgreplist to a series of files to be searched
 when Mgrep is called. If the textarg string (specified as an argument
 to Mgrep) is found in any of these files, the instance will be
 reported in the pseudo file <compile>. All succeeding calls to Mgrep
 will reset this file.

 The following are the files that are searched in the above example:

 1. DATA.FIL.

 2. Any file in the current directory with a .FOR extension.

 3. Any file along the INCLUDE environment variable path with a .H
    extension.


 148. C Extensions: Link Errors on __acrtused and _main Explained

 Product Version(s): 1.00    | 1.02
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER |
 Last Modified: 21-DEC-1989    ArticleIdent: Q51636
 Question :

 I am writing a C extension for the Microsoft Editor (M). When I link,
 I get the following error message:

    c:\usr\lib\CLIBCE.LIB(dos\crt0.asm)
            error  L2044:  __acrtused
            symbol multiply defined, use /NOE  pos
            1CC Record type: 53E4

    LINK : error L2029: Unresolved externals:
    _main in file(s):  c:\usr\lib\CLIBCE.LIB(dos\crt0.asm)
    Two errors were detected.

 I am compiling and linking as follows:

    cl /c /Gs /Asfu c_extension.c
    link /NOI /NOE exthdr.obj c_extension.obj, c_extension;

 These options seem to be correct according to the Editor manuals. Why
 am I getting these linker errors?

 Response:

 The linker gives these error messages if you are linking with a
 run-time function that must be initialized from the C start-up source
 code. This start-up source code is not used within a C extension.

 The art of writing C extensions for M Version 1.00 is documented in
 Chapter 8 of the Editor section of the "CodeView and Utilities,
 Microsoft Editor, Mixed-Language Programming Guide," which is included
 with C 5.00, C 5.10, Pascal 4.00, FORTRAN 4.10, and MASM 5.10.
 References to M Version 1.02 extensions are discussed in Chapter 8 of
 the "Microsoft Editor User's Guide," which came with FORTRAN 5.00.

 Please contact Microsoft Product Support Services at (800) 454-2030 to
 obtain an application note that discusses further techniques of writing C
 extensions for the Microsoft Editor.


 149. U1013 Link: Error 2: Not Enough Memory for Exec in M

 Product Version(s): 1.00 1.02
 Operating System:   MS-DOS
 Flags: ENDUSER | s_nmake s_make
 Last Modified: 23-JAN-1991    ArticleIdent: Q57653

 Question:

 In DOS, I am spawning either MAKE or NMAKE within the Microsoft Editor
 (M), and I receive an error message from the Editor on the status line
 saying "U1013 : Link file.obj: Error 2." What does this error mean and
 how do I get around it?

 Response:

 The U1013 error means that one of the procedures called by MAKE or
 NMAKE returned a nonzero error code. In this case, the error can be
 understood as M's equivalent of a "Not enough memory for exec" error,
 meaning that there is not enough memory for the parent process to
 execute a child process. The error typically occurs when you spawn
 either MAKE or NMAKE from within the Editor, the compilation is
 complete, and the link process is beginning.

 If you receive this error, you may be able to free up memory by
 removing any TSRs and unnecessary device drivers. However, the best
 workaround would be to use MAKE or NMAKE to link your file outside of
 M, because M will have problems exec'ing the linker in any sizable
 application due to the size of LINK and MAKE.


 150. Mgrep Can Skip Occurrences of Pattern When Using Mgreplist

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.02
 Last Modified: 16-JAN-1990    ArticleIdent: Q57705

 "Mgrep" may find every other occurrence of a search string when used
 to search a list of input files defined my the "mgreplist" macro.

 Mgrep searches all files defined by the mgreplist macro, then writes
 the location of a match to the <compile> pseudo file. When using
 either regular expression search patterns or standard search strings,
 mgrep may post every other occurrence of the matched string to the
 <compile> pseudo file. This also causes SHIFT+F3 to display every
 other match in the file being searched.

 To see the problem, set the mgreplist:="test.dat" where TEST.DAT
 contains the following:

    #include1
    #include2
    #include3
    #include4
    #include5
    #include6
    #include7
    #include8
    #include9
    #include10
    #include11
    #include12

 Invoke the mgrep search on the string "include" and then press
 SHIFT+F3 to view the next match. You will see that only every other
 occurrence of "include" is found. Also, if you view the <compile>
 pseudo file it will only contain a list every other occurrence of
 "include".


 151. M "Keyboard" Switch Doesn't Work As Documented

 Product Version(s): 1.02
 Operating System:   MS-DOS
 Flags: ENDUSER | S_FORTRAN buglist1.02
 Last Modified: 20-JAN-1990    ArticleIdent: Q57750

 The Microsoft Editor (M) Version 1.02 "keyboard" switch, documented on
 Page 198 of the the "Microsoft Editor User's Guide for MS OS/2 and
 MS-DOS Operating Systems," does not work as documented.

 The switch was implemented to allow control of which BIOS keyboard
 calls are used to get keystrokes. The "compatible" setting uses the
 standard INT 16H, AH = 0 to get keystrokes. The "enhanced" setting
 uses INT 10H, allowing the F11 and F12 keys to be read, and allowing
 you to use old versions of packages that may fail when your keyboard
 is treated as enhanced.

 If you set the "keyboard" option in your TOOLS.INI file by adding a
 line reading

    keyboard:"compatible"

 and then bring up the editor, M accepts the setting, but fails to set
 correctly. If you press SHIFT+F1 for help and choose Current
 Assignments, the list of current key assignments is given. The
 keyboard switch will now be set to the following:

    keyboard::enhanced

 Note the double colon, and that the compatible option has been
 changed to enhanced.

 If you try to set the option within the editor by entering the
 following, the editor returns the same options as above:

    ALT+A keyboard:compatible ALT+=

 Microsoft has confirmed this to be a problem in the Microsoft Editor
 Version 1.02. We are researching this problem and will post new
 information here as it becomes available.


 152. Incorrect Message from "searchall" with Regular Expressions

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | M MEP buglist1.02
 Last Modified: 23-JAN-1990    ArticleIdent: Q57932

 The Microsoft Editor searchall function (that is, SHIFT+F6) may return
 the following invalid error message when using regular expressions:

    +'pattern' not found

 'pattern' is the actual regular expression for which the search was
 requested.

 In this situation, searchall still finds all occurrences of the search
 pattern correctly -- only the message is incorrect.


 153. Version 1.02 of M and MEP Incorrectly Reports Version As 1.2

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 26-FEB-1990    ArticleIdent: Q58687

 If you access help for the Microsoft Editor (M/MEP) Version 1.02, the
 version is incorrectly displayed as 1.2, rather than 1.02. This
 incorrect version number appears in both the internal online help and
 when invoking help from the command line with the /? switch.

 The following information is incorrectly displayed when using the /?
 command-line switch for help:

    Microsoft (R) Editor Version 1.2
    Copyright (C) Microsoft Corp 1987-1989. All rights reserved
    Usage: [/D] [/e cmd-string] [/m mark] [/r] [[/t] filename]*


 154. Quote Function (CTRL+P) Can Fail to Work Properly

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.00 buglist1.02
 Last Modified: 26-FEB-1990    ArticleIdent: Q58720

 The Quote function (CTRL+P) in conjunction with CTRL+I or CTRL+T fails
 to display the valid character associated with that key sequence. For
 CTRL+P with CTRL+I, a space character (Hex 20) results instead of the
 correct foreground color rectangle with a background color dot (hex
 09). For CTRL+P with CTRL+T, a lowercase "a" with an accent mark (hex
 A0) results instead of the paragraph sign (hex 14).

 The Quote function reads one keystroke from the keyboard and treats it
 literally. This is useful for inserting text into a file that happens
 to be assigned to an editor function. For example, the key sequence
 Quote (CTRL+P) CTRL+A displays a happy face character.

 For the Quote CTRL+I sequence, the only workaround is to use a Quote
 TAB key sequence. This puts the correct hex value in that position
 (09H), but the correct character is not displayed and the tab is
 treated as a tab by the M Editor.

 For the Quote CTRL+T sequence, there is no workaround.

 Microsoft has confirmed this to be a problem with the M Editor Versions
 1.00 and 1.02. We are researching this problem and will post new
 information here as it becomes available.



 155. Replacing Normal String Takes Longer Than Regular Expression

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.00 buglist1.02
 Last Modified: 15-MAR-1990    ArticleIdent: Q59085

 Replacing a regular expression takes less time than replacing a normal
 string in the Microsoft M Editor, Versions 1.00 and 1.02. To
 demonstrate the time difference, perform test replacements in the
 following manner:

 1. Load the M Editor with a large file -- greater than 5000 lines.

 2. Perform and time a replacement on a regular expression, one that
    fails to match in the file, for example:

       arg arg CTRL+L     zzzz   <- search for this regular expression
                          zzzz   <- replace with this regular expression

 3. Perform and time a replacement on a normal string (one that fails
    to match in the file), for example:

       arg CTRL+L     zzzz   <- search for this string
                      zzzz   <- replace with this string

 The string replacement may take twice as long as the
 regular-expression replacement. To obtain the higher replace speed,
 use the regular-expression replacement (arg arg CTRL+L) even when you
 are not fully using the regular-expression syntax.

 Note that a psearch on a regular expression psearch is NOT quicker
 than a psearch on a normal string.

 Microsoft has confirmed this to be a problem in Versions 1.00 and
 1.02. We are researching this problem and will post new information
 here as it becomes available.

 For details on regular expression, refer to the "Microsoft Editor
 User's Guide," Chapter 5, "Regular Expressions."


 156. Incorrect Version Numbers Cause Tagged Sections to Be Ignored

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | pwb
 Last Modified: 25-MAY-1990    ArticleIdent: Q59256

 With the Microsoft Editor (M) or the Programmers WorkBench (PWB), it
 is possible to include information in your TOOLS.INI file that is
 specific to the operating system you are using. For information on how
 to create sections with tags, see the "Microsoft Editor User's Guide,"
 Section 7.5.1. However, you must be sure to include a trailing 0
 (zero) on the label for OS/2 versions 1.10 or 1.20. Failure to do so
 causes these sections to be ignored by the Editor.

 The following headers cause the tagged sections to be ignored when
 running under OS/2 version 1.10:

    [M-10.0 M-10.1]
    fgcolor:0B
    hgcolor:30
    stacolor:0E

    [M-3.30 M-10.0R M-10.1R]
    fgcolor:0E
    hgcolor:E0
    stacolor:0B

 The tags must be rewritten as follows:

    [M-10.0 M-10.10]
    fgcolor:0B
    hgcolor:30
    stacolor:0E

    [M-3.30 M-10.0R M-10.10R]
    fgcolor:0E
    hgcolor:E0
    stacolor:0B

 Furthermore, the tagged sections must not be placed in the middle of
 an [M] or [M MEP] tagged section. They must be placed before or after
 the [M] or [M MEP] sections. Failure to do this causes information
 located below these sections to be ignored in the DOS compatibility
 box.

 Note: For the PWB, the above examples would change to PWB-xxxx instead
 of M-xxx.


 157. Unassigning Help Keystrokes Must Be Done Under

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 13-MAR-1990    ArticleIdent: Q59494

 It is possible with the Microsoft Editor Version 1.02 to disable
 an assigned keystroke so that it invokes no editor function at all.
 The keystroke can then be assigned to any other function or macro. By
 putting the disable information in the M Editor section of the
 TOOLS.INI file, the changes will be in effect whenever the Editor is
 invoked. For further information, see the Version 1.02 edition of
 "Microsoft Editor User's Guide," Section 6.2.3, Page 70.

 To regularly disable a keystroke that has been assigned to any preset
 Editor HELP function, such as F1 or SHIFT+F1, the command must be
 placed under the [M-MHELP MEP-MHELP] tag in TOOLS.INI -- not under the
 [M MEP] tag.

 For example, to disable the keystroke for F1, include the following
 line in your TOOLS.INI file:

    unassigned:F1

 Placing this line under the section tagged [M MEP] rather than the
 [M-MHELP MEP-MHELP] tag causes this command to be ignored. This is
 also applicable to the undocumented "sethelp" function, whose default
 keystroke is ALT+S. You can unassign ALT+S, as well as reassign a
 different keystroke to "sethelp", but it must be done under the
 [M-MHELP MEP-MHELP] tag.


 158. Using RIGHT ARROW on Dialog Line Locks Keyboard or GP Faults

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.02
 Last Modified: 15-MAY-1990    ArticleIdent: Q59527

 Manipulating text on the dialog line must be handled differently in
 the Microsoft Editor (M) Version 1.00 than in 1.02. If you use an M
 Version 1.00 procedure in M Version 1.02 under DOS, the keyboard will
 lock up and alternating screens of jumbled characters may appear on
 the screen. Under OS/2, you will get a GP fault resulting in the
 termination of MEP by the operating system.

 The problem can be observed by using the following steps from within
 the editor:

 Note: Remember that under DOS your machine will hang!

 1. Press ALT+A to invoke the <arg> function.

 2. Type any character (for example, the letter "d").

 3. Hold down the RIGHT ARROW key. When the text in the dialog line has
    scrolled off the left side of the screen, in M 1.00 the editor will
    issue a beep. In M 1.02, the machine will lock in DOS or GP fault
    in OS/2. This problem occurs even if you omit Step 2, but it is
    more difficult to see the error.

 To retain the same functionality in M 1.02, instead of using the RIGHT
 ARROW key to move the cursor to the right, use the SPACEBAR. Using
 the SPACEBAR rather than the RIGHT ARROW key allows you to take
 advantage of the maximum arg line limit without the error.

 Microsoft has confirmed this to be a problem in Version 1.02. We are
 researching this problem and will post new information here as it
 becomes available.


 159. Reference to "Push" Function Incorrect Editor User's Guide

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-JUL-1990    ArticleIdent: Q60339

 On Page 61 of the "Microsoft Editor User's Guide" for Microsoft C
 5.10, there is a documentation error. It is stated that the Boolean
 switch Savescreen is "for use with the Push and Exit functions." Since
 there is no "Push" function, this should read "for use with the Shell
 and Exit functions."


 160. Prototype in User's Guide for tglcase() Is Incorrect

 Product Version(s): 1.02    | 1.02
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 15-APR-1990    ArticleIdent: Q60487

 In the sample program for a C extension on Page 126 of the "Microsoft
 Editor User's Guide" for Microsoft FORTRAN 5.00 and Microsoft BASIC
 PDS Version 7.00, the prototype for tglcase() is incorrect.

 The function is prototyped as follows:

    flagType pascal EXPORT tglcase (unsigned int, ARG far *, flagType);

 It should be as follows:

    flagType pascal EXTERNAL tglcase (unsigned int, ARG far *, flagType);

 Note: The word EXTERNAL replaces EXPORT.


 161. Creating a Compile Window Macro for the M Editor Version 1.02

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 27-JUL-1990    ArticleIdent: Q63950

 The macro below creates a "compile window" in either the M or MEP
 Editor version 1.02 when you press ALT+C. Note that a compile window
 is helpful for viewing general compilation errors and errors generated
 from utilities that were invoked.

 The following macro, CompWindow, can be added to the [M] or [MEP]
 tagged section of the TOOLS.INI file to create a compile window:

    CompWindow:= savecur home meta down  \
                 up up up up arg window  \
                 window arg "<compile>" setfile  \
                 window restcur

    CompWindow: alt+c

 The CompWindow macro above creates a compile window by performing the
 following steps:

 1. Use the "savcur" function to save the current position of the
    cursor.

 2. Use the "home" function to place the cursor in the upper-left
    corner of the screen. This function guarantees that the cursor will
    be in a left-most position when the compile window is created.

 3. Use the "meta down" function to move the cursor to the bottom of
    the window without changing the column position.

 4. Use "up up up up arg window" functions to create a horizontal
    window four lines above the bottom of the screen. A larger compile
    window can be created by adding more "up" functions to this line in
    the macro.

 5. Use the 'arg "<compile>" setfile' function to create a
    dynamic-compile log. More information concerning the
    dynamic-compile log can be found on Pages 47-48 of the "Microsoft
    Editor User's Guide."

 6. Finally, the original position of the cursor is restored in the
    original window by using the "window restcur" functions.

 7. The macro is assigned to the ALT+C keystroke, although any unused
    keystroke may be used.

 Error messages will now be displayed in the compile window when
 running a compilation or invoking a utility.


 162. C 6.00 UNDEL.EXE Is Not Compatible with the Microsoft Editor

 Product Version(s): 1.00 1.02 | 1.00 1.02
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 25-JUL-1990    ArticleIdent: Q64024

 If backup copies of files are stored in the \DELETED subdirectory by
 the M Editor, typing "undel" should bring up a listing of backup
 copies. However, if the C 6.00 version of UNDEL.EXE is used, the
 following message will be displayed: "

    0(0) bytes in 0 deleted files.

 The C 5.10 version of UNDEL.EXE will successfully bring up a listing
 of backup copies saved by either the M Editor or the Programmer's
 WorkBench (PWB).

 This problem can be reproduced by setting the text backup switch in
 the M section of the TOOLS.INI file to "undel". After saving various
 copies, backups are added to the \DELETED subdirectory and a listing
 can be brought up by using the C 5.10 UNDEL.EXE. Using the C 6.00
 version of UNDEL.EXE causes the erroneous message listed above to be
 displayed. This incompatibility was caused by adding OS/2 version 1.20
 filename support to UNDEL.EXE and EXP.EXE.

 As a workaround, rename the C 5.10 UNDEL.EXE to UNDEL51.EXE and the C
 6.00 UNDEL.EXE to UNDEL60.EXE.


 163. Invalid Switch and Extensions in Brief Emulation

 Product Version(s): 1.02   | 1.02
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  6-FEB-1991    ArticleIdent: Q67762

 The M editor version 1.02 comes with a BRIEF.INI file, which contains
 the key settings for Brief emulation. If you want Brief emulation, you
 must rename this file to "TOOLS.INI". This file will generate the
 following three messages when M loads the TOOLS.INI file during
 initialization:

    mhctx is not an editor switch
    load:$PATH:ulcase - no such file or directory
    load:$PATH:justify - no such file or directory

 The messages are caused by the following three lines:

    Line 223: "mhctx:Alt+H"
    Line 263: "load:$PATH:ulcase"
    Line 369: "load:$PATH:justify"

 Deleting these three lines will not change the performance of the M
 editor, and will eliminate the messages they cause when M is
 initialized.






 Microsoft NMake [Make Utility]
 =============================================================================


 1. NMAKE and the Backslash "\" Character

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  3-MAY-1989    ArticleIdent: Q43064

 The backslash "\" character in NMAKE has two different meanings
 depending on how it is used. One of its uses is as a line-continuation
 character. The other use is as a path specifier.

 The primary use of "\" is as a line continuation-character. For
 example, if you have a dependency line that extends more than one
 line, use the "\" character to continue to the next line. It is
 correct to include a space prior to the "\" or to append it to the
 last dependent, as in the following examples:

 FOO : obj1 obj2 obj3 obj4 obj5 \  (CORRECT)
 obj6 obj7...etc.

 FOO : obj1 obj2 obj3 obj4 obj5\   (CORRECT)
 obj6 obj7...etc.

 The "\" character is also used as a path specifier. When "\" is the
 last character on the line and is meant as a path specifier, you must
 precede it with the caret "^" character to tell NMAKE to override its
 meaning as a line-continuation character.

 The following macro definition is an example demonstrating the use of
 "\" as a path specifier:

 exe_dir = c:\bin^\    (CORRECT)

 exe_dir = c:\bin\     (INCORRECT)

 The following will be interpreted as a line-continuation character.

 exe_dir = c:\bin\     (INCORRECT)

 Preceding the "\" with another "\" will nullify the meaning as a
 line-continuation character. However, when this macro is expanded,
 both backslashes will appear, producing an incorrect path.


 2. NMAKE Is Case Sensitive

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-MAY-1989    ArticleIdent: Q43999

 It is not clearly stated in the manual that NMAKE IS case sensitive.
 Case sensitivity is imposed on the following:

 1. Macros

    For instance, if you define "TEXT" as a macro, you must use $(TEXT)
    to insert it. If $(text) is used, the macro is undefined and
    nothing happens.

 2. Predefined Macros (.SUFFIXES;.PRECIOUS, CC, etc.)

    Predefined macros such as .SUFFIXES must be in all in uppercase
    letters. If you use .suffixes, NMAKE returns the error ".suffixes
    too long: truncated to 8.3".

 3. File extensions

    When adding file extensions to the .SUFFIXES list, you must
    preserve case. For example, to add the file extension .dll to the
    suffix list, you would put the following line in your makefile:

       .SUFFIXES : .dll

    Then, all files with the .dll extension must have the .dll
    extension in lowercase letters.


 3. NMAKE Uses "makefile " Ignoring File Name on Command Line

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC
 Last Modified: 10-NOV-1989    ArticleIdent: Q44777

 When using NMAKE, you normally put the makefile's name on the command
 line as follows:

    NMAKE test.mak

 Although this works correctly for most cases, if there is a file named
 "makefile." in the current working directory, NMAKE uses that file
 instead of the one specified on the command line.

 To be sure NMAKE uses the makefile specified on the command line, you
 must have a /F switch before the makefile name as follows:

    NMAKE /F test.mak

 This is expected behavior, as documented on Page 156 of the "Microsoft
 QuickC ToolKit" manual for QuickC Version 2.00.


 4. Modifications for an Existing Make File Used with MAKE

 Product Version(s): 1.00   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc  s_c  h_FORTRAN
 Last Modified: 16-JAN-1990    ArticleIdent: Q44130

 Question:

 What modifications need to be made to an existing make file that was
 used with MAKE, and why?

 Response:

 To use NMAKE on make files originally designed for MAKE, the first
 descriptor block (target:dependent) must be a pseudotarget (see QuickC
 Version 2.00 ToolKit, Sections 7.3.5 and 7.5) that lists all of the
 original make targets in the file as the dependent files. The
 following is an example:

    ALL : test.exe test1.exe test2.exe

 The reason you must include a pseudotarget descriptor block as the
 first descriptor block in a make file is that the previous MAKE
 utility tested EACH descriptor block sequentially throughout the file.
 NMAKE, however, tests only the FIRST descriptor block unless targets
 are specifically listed on the NMAKE command line. By using a
 pseudotarget, ALL in the above example, NMAKE must now assume
 that each dependent is out of date and attempt to make it. NMAKE now
 searches the make file for each dependent file listed (test.exe,
 test1.exe, and test2.exe) to see if a descriptor block exists for it.
 This causes NMAKE to behave just like MAKE.

 Example:
 -------

    ALL : test.exe test1.obj

    test1.obj : test1.c
            cl /c test1.c

    test.exe : test.obj test1.obj
            link test test1;

 Without the pseudotarget, NMAKE tests only the first descriptor block
 and ignores any following descriptor block.


 5. How to Specify Paths in Inference Rules in NMAKE

 Product Version(s): 1.00   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc  s_c  h_FORTRAN
 Last Modified: 23-MAR-1990    ArticleIdent: Q44131

 Question:

 How to I specify paths in inference rules?

 Response:

 Note: For a complete description of this feature, see QuickC Version 2.00
 Toolkit, Section 7.3.3. One of the most powerful new features of
 NMAKE is that it allows paths to be specified in an inference rule.

 The syntax of an inference rule without paths is as follows:

    .fromext.toext:

 This syntax is somewhat limited, however, because both the "fromfile"
 and the "tofile" are evaluated as if they existed in the current
 directory. With NMAKE, a path specifier may be added to an inference
 rule by doing the following:

    {frompath}.fromext{topath}.toext:

 Note: If you use a path on one element of the inference rule, you must
 use it on both. For instance, if you want to compare any .c file in
 the current directory with its .obj file in my object directory, the
 inference rule would look like the following:

 {.}.c{c:\objects}.obj:
         cl /c $<;

 Note that the fromext (.c) has to be preceded with a path. In the case
 of the current directory, the ".", or current directory works nicely.

 When NMAKE encounters a descriptor block that has no commands
 following, it will look for an inference rule that matches the
 descriptor block. When checking for matching, NMAKE expects that the
 base name of both the target and the dependents be the same. Also, the
 paths must match exactly. In other words, the following descriptor
 line would not use the inference rule just defined because the paths
 do not match on the .obj file:

    test.obj : test.c

 In this case, the predefined inference rule for .c.obj: would be
 invoked. To invoke the inference rule just defined, the descriptor
 line would be as follows:

    c:\objects\test.obj : test.c


 6. Multiple Targets in NMAKE Do Not Work

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist2.00 docerr S_QUICKC
 Last Modified:  2-JUN-1989    ArticleIdent: Q44757

 Multiple targets in the QuickC Version 2.00 NMAKE utility do not work
 properly. The example on the top of Page 167 of the "Microsoft QuickC
 Tool Kit" manual shows that each target listed before the dependencies
 should be evaluated; however, only the first target is evaluated, and
 the others are ignored. Make files that are simplified even more
 respond the same way.

 The following make file demonstrates the problem:

     target1.exe target2.exe: depend1.obj depend2.obj
         echo $@

 For the make file to work properly, change the file to the
 following:

     BUILD: target1.exe target2.exe

     target1.exe: depend1.obj depend2.obj
         echo $@

     target2.exe: depend1.obj depend2.obj
         echo $@

 Microsoft has confirmed this to be a problem in QuickC Version 2.00.
 We are researching this problem and will post new information as it
 becomes available.



 7. Modifying a QuickC 2.00 Make File to Run MAKE

 Product Version(s): 1.00   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_quickc  s_c  h_FORTRAN
 Last Modified: 26-MAY-1989    ArticleIdent: Q44133

 Question:

 What modifications must I make to a make file generated by QuickC
 Version 2.00 so that I can run NMAKE on it and use my Microsoft C
 Version 5.10?

 Response:

 Only a few modifications must be made to allow a make file generated
 by QuickC to invoke C Version 5.10. The following three items need to
 be changed:

 1. Change the CC macro from qcl to cl. To do this, locate the
    following line in the make file generated by QuickC and change qcl
    to cl:

       CC=qcl

 2. Take out references to ilink. The ilink references are embedded
    into your make file if you have the ilink option turned on in your
    environment. The following line in the make file

       ilink -a -e "link $(LFLAGS) @$(PROJ).crf" $(PROG)

    must be changed to the following:

       link "$(LFGLAGS) @$(PROJ).crf" $(PROG)

 3. Remove any compiler switches in the make file that cl will not
    recognize. To eliminate this problem, turn off incremental compile
    in the QuickC environment prior to making the make file.


 8. NMAKE Version 1.00 with "!" and User and Predefined Macros

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | S_QuickC buglist1.00 fixlist1.01
 Last Modified: 30-NOV-1989    ArticleIdent: Q48859

 The following NMAKE file does not produce the correct results when
 using NMAKE Version 1.00, which is supplied with the Microsoft QuickC
 compiler Version 2.00. The file replaces the user-defined macro in the
 second command line with the predefined macro in the first command
 line. The workarounds are as follows:

 1. Remove the "!" at the beginning of the first command line, which
    causes the command to be executed for each dependent file if the
    command uses one of the special macros $? or $**.

 2. Do not use a predefined macro for the first command.

 3. Do not use the predefined macro $**, a complete list of dependent
    files, for the dependent files in the first command line.

 4. Do not use a user-defined macro in the second command line.

 5. Update to the Microsoft QuickAssembler package, which is shipped
    with NMAKE Version 1.01, in which this problem is corrected.

 More information on the NMAKE utility can be found starting on Page
 155 of the "Microsoft QuickC Toolkit" manual. The following is the
 NMAKE file that fails:

 SOURCE=test.c

 test.exe: $(SOURCE)
     !$(CC) $**
     copy $(SOURCE) new

 This produces the following output:

 cl test.c
 copy cl new

 The following is the NMAKE file with the first workaround:

 SOURCE=test.c

 test.exe: $(SOURCE)
     $(CC) $**
     copy $(SOURCE) new

 This produces the following correct output:

 cl test.c
 copy test.c new

 The following is the NMAKE file with the second workaround:

 SOURCE=test.c

 test.exe: $(SOURCE)
     !cl $**
     copy $(SOURCE) new

 This also produces the correct output.

 The following is the NMAKE file with the third workaround:

 SOURCE=test.c

 test.exe: $(SOURCE)
     !$(CC) $(SOURCE)
     copy $(SOURCE) new

 This also produces the correct output.

 The following is the NMAKE file with the fourth workaround:

 SOURCE=test.c

 test.exe: $(SOURCE)
     !$(CC) $(SOURCE)
     copy test.c new
     copy $(SOURCE) new

 This produces the following output:

 cl test.c
 copy test.c new
 copy test.c new


 9. Incrementally Updating Libraries with NMAKE

 Product Version(s): 1.00 1.01 1.10 1.11 1.12 | 1.11 1.12
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER |
 Last Modified: 25-FEB-1991    ArticleIdent: Q48862

 The repetition modifier "!" (without the quotation marks) provided in
 NMAKE allows libraries to be maintained and incrementally updated very
 easily. By using this modifier with the special macro for dependents
 out-of-date with the target (for example, "$?"), the library update
 becomes an automated part of modifying a project.

 The following NMAKE makefile keeps FOO.LIB up-to-date based on the
 four object files listed in the OBJS macro. These object files can be
 based on C or assembly source files. The list of source-file types can
 be extended by adding the appropriate inference rules to the
 description file.

 Sample NMAKE Makefile
 ---------------------

     #
     # List of object files to be kept in library
     #
     OBJS = foo1.obj foo2.obj foo3.obj foo4.obj

     .c.obj:
         cl /c $?

     .asm.obj:
         masm $?;

     foo.lib : $(OBJS)
         !lib foo.lib -+ $?;

 The command for the library dependency line uses a predefined macro
 and a special NMAKE directive. Placing "$?" on the end of the LIB line
 expands to the list of all dependents that are out-of-date with the
 target. This list combined with "!" causes the LIB line to be executed
 once for each member in the list.

 If FOO1.OBJ and FOO3.OBJ are out-of-date with respect to FOO.LIB, "$?"
 evaluates to "FOO1.OBJ FOO3.OBJ". With "!", the following commands are
 executed:

    lib foo.lib -+ foo1.OBJ;
    lib foo.lib -+ foo3.OBJ;


 10. Explanation of Why NMAKE May Not Produce .OBJ and .EXE Files

 Product Version(s): 1.00 1.10 1.11 | 1.00 1.11
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER |
 Last Modified: 27-OCT-1989    ArticleIdent: Q49502

 Question:

 When using the NMAKE utility, no warnings occur and the compiler
 appears to execute properly; however, the .OBJ and .EXE files are not
 created.

 If I use the MAKE utility on the same .MAK file, I get the following
 two warnings:

    warning U4000: Target does not exist.

    warning U4001: Dependent does not exist; Target not built.

 The first warning message is a standard warning that I would expect.
 Why is there a second and why aren't the .OBJ and .EXE files created?

 Response:

 Remove unexpected trailing characters from the .MAK file.

 This problem can occur because extra characters occur at the end of a
 line within the .MAK file. Common mistakes such as placing a trailing
 semicolon in the CL compile line or in the dependency line can cause
 this behavior. This applies to any unexpected characters, not just
 semicolons.

 The following example demonstrates the problem:

    file.obj: file.c <ENTER>
       CL /c /Lp file.c;  <-- Semicolon CANNOT be used with the CL command.

    file.exe: file.obj <ENTER>
       LINK file;      <-- OK, Semicolon CAN be used with the LINK command.

 Removing the semicolon at the end of the CL line eliminates the
 problem.


 11. Command Line Too Long in Makefile Can Cause Error: U1082

 Product Version(s): 1.00 1.01 1.10 1.11 1.12 | 1.11 1.12
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER | s_make
 Last Modified: 24-JAN-1991    ArticleIdent: Q49757

 NMAKE and MAKE require that all commands issued after a target
 dependency are less than the DOS command-line limit of 128 characters.
 If the command is too long, you may receive the following error

    U1082:  Not enough memory '...' cannot execute '...'

 where '...' is the command that was attempted. This problem most
 likely occurs with the link command line and can be easily resolved
 with a response file. Response files are documented in the utilities
 manual or the online help supplied with each compiler.


 12. Special Macros Not Recognized in NMAKE Inline Files

 Product Version(s): 1.00 1.01 | 1.00 1.01
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER |
 Last Modified: 10-NOV-1989    ArticleIdent: Q50693

 When you use special macros to indicate targets or dependents in
 inline files, NMAKE Version 1.00 will generate the error message
 U4108, "special macro undefined." These special macros are $@, $*,
 $**, and $?.

 To prevent the problem, avoid use of these special macros in inline
 files. Instead of using those << inline files, create the response
 file in a separate NMAKE target, and redirect TYPE and ECHO commands
 to the desired file.

 $@ refers to the full name of the target, base plus extension. $*
 refers only to the base name of the target.

 $** represents the complete list of dependent files for the target. $?
 represents only the dependents that are out of date relative to the
 target.

 The following makefile will generate U4018 for $**:

 #makefile test
 FOO.EXE: *.OBJ
     LINK @<<FOO.LRF
 $**;
 <<

 To avoid the problem, break this up into two steps, the makefile and a
 linker response file with output redirected:

 #makefile test
 FOO.EXE: *.OBJ FOO.LRF
     LINK @FOO.LRF

 FOO.LRF: *.OBJ
     echo $**; >FOO.LRF


 13. Inference Rule May Fail If Blank Command Line Contains Spaces

 Product Version(s): 1.00 1.01 1.10 1.11 1.12 | 1.11 1.12
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER |
 Last Modified: 24-JAN-1991    ArticleIdent: Q50383

 When using inference rules in an NMAKE description file, the target/
 dependency line must be followed by a blank line (no space
 characters); otherwise, the inference rule commands will not be
 executed. NMAKE checks this line for any ASCII characters; if ANY
 characters exist, NMAKE will ignore the inference rule and try to
 execute the line, even if it contains only a space or spaces.

 The following is a simple example, which demonstrates this problem:

 .c.exe:
   cl $**

 ALL : main.exe

 main.exe : main.c
 <space>

 Nothing happens if this description file is passed to NMAKE because
 the space character will cause NMAKE to assume there are explicit
 commands following the target/dependency line, causing it to ignore
 the inference rule. Note that this is expected behavior for NMAKE.

 MAKE version 4.x inference rules/description blocks do not exhibit
 this behavior. This is something to keep in mind when converting
 description files from MAKE to NMAKE.


 14. Using "." for Path in Inference Rules Causes U1073

 Product Version(s): 1.00 1.01 | 1.01
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.01
 Last Modified: 18-DEC-1989    ArticleIdent: Q51723

 NMAKE does not accept a dot (.) to identify the current directory in
 inference rule paths. When specifying paths for each of the
 extensions, using the following form

    {frompath}.fromextension{topath}.toextension

 and using "{.}" (without the quotation marks) to indicate the current
 directory for the "topath", causes the following error:

    NMAKE : fatal error U1073: don't know how to make 'filename.ext'

 To work around this, the current directory for topath must be
 specified with "{}". However, both notations are acceptable when
 specifying the "frompath".

 The following makefile causes the error:

 .SUFFIXES: .h .c .obj .exe

 #macros
 a=tools.h
 jbo=grdemo.obj turtle.obj menu.obj
 cc=qcl -c

 #inference rules
 {d:\qc2\work}.c{.}.obj:          #*** the '{.}' must be '{}' ***
  $(cc) $<

 {}.obj{d:\qc2\lib}.exe:
  link $(**R),,, graphics.lib;

 #target-dependencies
 run: d:\qc2\lib\grdemo.exe

 d:\qc2\lib\*.obj: d:\qc2\work\*.c

 d:\qc2\lib\grdemo.exe: $(jbo)


 15. Redirecting NMAKE 1.00/1.01 Output with -p Gives False Errors

 Product Version(s): 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 fixlist 1.11
 Last Modified: 24-JAN-1991    ArticleIdent: Q57500

 Redirecting the output of NMAKE version 1.00 or 1.01 can cause
 inference rules to fail if all of the following conditions are met:

 1. The inference rules are in uppercase letters.
 2. The -p option is used.
 3. The output is redirected.

 This problem is somewhat obscure, and it can be frustrating if you
 unwittingly meet all of these conditions. The error message displayed
 depends on the inference rule used, but it resembles the following:

    NMAKE : warning U4017: ignoring rule .C.OBJ (extension not in
            .SUFFIXES)

 The above error message is displayed with the following description
 file initiated with the command "NMAKE -p > out.txt":

 Description File
 ----------------

 # start

 .C.OBJ:
   cl $*

 main.obj : main.c

 # end

 Microsoft has confirmed this to be a problem in NMAKE versions 1.00
 and 1.01. This problem was corrected in NMAKE version 1.11.


 16. Missing Right Parenthesis in Sample NMAKE File Hangs Machine

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | h_fortran s_quickc s_quickasm buglist1.00
 Last Modified: 15-MAR-1990    ArticleIdent: Q59069

 If you forget the right parenthesis in an IF "$(flag)"=="comparison"
 line in a makefile and run the makefile through NMAKE, you can receive
 machine hangs or corrupt COMMAND.COM messages under DOS or an Internal
 Processing Error under OS/2.

 Microsoft has confirmed this to be a problem with Version 1.00. We are
 researching this problem and will post new information here as it
 becomes available.

 The following makefile, simplified from the sample makefile on Page
 172 of the "QuickC ToolKit" manual, demonstrates this problem:

 debug=Y
 CC=qcl
 !CMDSWITCHES +D
 HELLO.EXE : HELLO.OBJ
 !IFDEF debug
 !   IF "$(debug"=="y"
                 LINK /CO hello;
 !   ELSE
                 LINK hello;
 !   ENDIF
 !ELSE
 !   ERROR Macro named debug is not defined.
 !ENDIF

 Adding a right parenthesis after "$(debug solves the problem.

 The error seems to occur because NMAKE does not recognize the end of
 the line and continues to parse the line until the end of the file. A
 customer has reported receiving "U1076, Line too long" messages,
 followed by a DOS level error reading "Invalid COMMAND.COM - system
 halted."

 Testing the same problem under an OS/2 1.20 DOS Box returned Internal
 Processing Errors and halted the system with no other error messages.


 17. NMAKE 1.01 Does Not Properly Expand Wildcard Arguments

 Product Version(s): 1.01   | 1.01
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q59254

 NMAKE version 1.01 doesn't properly expand wildcard command-line arguments.
 For example, if we were to have a makefile that looked similar to the
 following

 a.exe : a.c
     echo cl a.c

 b.exe : b.c
     echo cl b.c

 And we were to say:

 NMAKE *.exe /A

 NMAKE wouldn't properly expand "*.exe" to equate to both a.exe and
 b.exe; it would merely build only the first target in the list.

 NMAKE versions 1.00 and 1.10 do not exhibit this behavior.


 18. NMAKE /D /C Switches Suppress Modification Date

 Product Version(s): 1.00 1.01 1.10 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 buglist1.01 buglist1.10 buglist1.11
 Last Modified: 18-NOV-1990    ArticleIdent: Q59384

 When using the NMAKE /D and /C switches together, the modification
 date of each file will not be displayed when the date is checked. A
 short description of each switch is described as follows:

    /D  Displays the modification date of each file when the date is
        checked.

    /C  Suppresses the NMAKE copyright message and prevents nonfatal
        error or warning messages from being displayed.

 Microsoft has confirmed this to be a problem with NMAKE Versions 1.00,
 1.01, and 1.10. We are researching this problem and will post new
 information here as it becomes available.


 19. Trouble with Filenames Containing a Dollar Sign ($)

 Product Version(s): 1.01    | 1.01
 Operating System:   MS-DOS  | OS/2
 Flags: ENDUSER | buglist1.01
 Last Modified: 14-MAR-1990    ArticleIdent: Q59409

 If you use a filename that contains a dollar sign ($) in a NMAKE
 description file, you can use the escape character (^) to tell NMAKE
 that the dollar sign is part of your filename, not a macro character.
 However, using the escape character within an inline response file
 does not work and you must use the double dollar sign ($$).

 Consider the following NMAKE description file:

     all:test^$.exe;

     test^$.obj: test^$.c
        cl /c test^$.c

     test^$.exe: test^$.obj
        link @<<
              test^$.obj,
              test^$.exe,
              NUL,;
     <<

 In this file, the escape character (^) is used to tell NMAKE that the
 $ is part of the filename TEST$.* and is not denoting the use of a
 macro. When TEST$.C is compiled, everything works correctly until you
 get to the inline response file for LINK. NMAKE does not interpret the
 ^ character, but instead passes it on to LINK.EXE. LINK then tries to
 link TEST^$.OBJ instead of TEST$.OBJ and fails. If you eliminate the ^
 to pass TEST$.OBJ to link, NMAKE fails with an error about an invalid
 macro.

 NMAKE is in error here. NMAKE should do one of two things when parsing
 the inline response file.

 1. NMAKE should interpret the ^ to leave the $ as part of the filename.

 2. NMAKE should ignore the $ so that you can just list TEST$.OBJ
    because it doesn't make sense to have macros in external response
    files when parsing an inline response file.

 Microsoft has confirmed this to be a problem with NMAKE Version 1.01.
 We are researching this problem and will post new information here as
 it becomes available.

 The following are two suggested workarounds:

 1. Use an external response file. Then your link line would appear
    similar to link @FILE.RES and you could put TEST$.OBJ directly in
    the response file.

 2. Use $$ as the escape sequence instead of ^$ in the inline response
    file. For example, change

       link @<<
           test^$.obj,
           test^$.exe,
           NUL,;
       <<

    to the following

       link @<<
           test$$.obj,
           test$$.exe,
           NUL,;
       <<

    and NMAKE will correctly pass TEST$.OBJ to the linker.


 20. In What Order Does NMAKE Build Files?

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 15-MAY-1990    ArticleIdent: Q59420

 Question:

 I need to have my source files built in a particular order but I can't
 get NMAKE to build them that way. NMAKE seems to build the source
 files in the order it wants. What is the order in which NMAKE builds
 files?

 It is definitely possible to specify the order in which NMAKE builds
 your files.

 The first thing NMAKE does is check the command line. You can specify
 the targets in the order you want them built and NMAKE will build them
 in that order. If NMAKE doesn't find any targets on the command line,
 it builds the first target in the description file.

 NMAKE will build all of the dependents in the order in which they are
 specified on the first target line. For most description files, the
 first target in the file is the ALL:FILENAME.EXE pseudotarget. In this
 case, NMAKE will build FILENAME.EXE, and then the order depends on the
 dependency for FILENAME.EXE.

 This can be more clearly explained in the following examples:

 Example 1
 ---------

 Consider the following description file:

             all:three.obj two.obj one.obj main.exe

             one.obj:one.c
                 cl /c one.c

             two.obj:two.c
                 cl /c two.c

             three.obj:three.c
                 cl /c three.c

             main.exe:three.obj one.obj two.obj
                 link one two three, main;

 In this example, the files are compiled in the order: THREE.C, TWO.C,
 ONE.C. After those three files are compiled, the link for MAIN.EXE is
 executed. They are executed in that order because that is the explicit
 order given in the first target in the file and NMAKE builds the first
 target in the file when nothing is specified on the command line.

 Example 2
 ---------

 Now, consider the following description file that has been slightly
 modified from the one shown in Example 1 above:

             all:main.exe

             one.obj:one.c
                 cl /c one.c

             two.obj:two.c
                 cl /c two.c

             three.obj:three.c
                 cl /c three.c

             main.exe:three.obj one.obj two.obj
                 link one two three, main;

 In this example the files are compiled in the order: THREE.C, ONE.C,
 TWO.C. After that, the link statement will then be executed because
 there is nothing specified on the command line, so NMAKE will build
 the first target in the file, which is MAIN.EXE. When NMAKE looks at
 what it needs to build MAIN.EXE, it sees the list of dependents and
 builds them in that order.

 In summary, NMAKE looks first on the command line. If nothing is found
 there, it builds the first target in the description file by building
 each of its dependents in the order specified. If the dependent of the
 first target specifies another target, the dependents of that target
 are built in the order they are specified and so on.


 21. Multiple Dependency Blocks Are Not Cumulative

 Product Version(s): 1.00 1.01 1.10 1.11 | 1.01 1.10 1.11
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 16-OCT-1990    ArticleIdent: Q59526

 Question:

 Specifying a target in multiple dependency blocks seems to confuse
 NMAKE. If my make file says something similar to the following

 FOO.EXE:: FOO1.obj
 FOO.EXE:: FOO2.obj
 FOO.EXE:: FOO3.obj
   link foo.exe

 FOO.EXE:: FOO.RES
   RC FOO.RES FOO.EXE

 and FOO1.OBJ and FOO2.OBJ are newer than FOO.EXE but FOO3.OBJ is not,
 FOO.EXE will not be built. To further confuse the issue, the following
 is the output from running NMAKE with the /d (display file dates)
 option:

 C:\>NMAKE /d foo.mak

   foo.exe                    Wed Mar 07 08:42:38 1990
     foo1.obj                 Thu Mar 08 15:25:44 1990
 ** foo1.obj newer than foo.exe
     foo2.obj                 Wed Mar 08 08:38:56 1990
 ** foo2.obj newer than foo.exe
     foo3.obj                 Thu Mar 01 09:49:52 1990
     foo.res                  Thu Mar 01 09:49:52 1990
 'foo.exe' is up-to-date.

 Obviously, NMAKE realizes the foo1 and foo2 .OBJs are newer, but
 FOO.EXE is never linked. Why not?

 Response:

 The multiple dependency construct, indicated by a double colon (::)
 following the target, is very useful in NMAKE because it allows the
 programmer to specify what operations are to take place on a target
 based on various dependents. For instance, in PM (Presentation
 Manager) programming the MAKE file can indicate that if the .OBJs
 change, execute the linker to rebuild the application. On the other
 hand, if all that changes is the resource file, only the resource
 compiler needs to be executed.

 However, there is a limitation to this feature. The command block for
 a target-dependency group MUST immediately follow it. They are not
 cumulative like normal dependency blocks. Therefore, one workaround to
 the above example is the following:

 FOO.EXE:: FOO1.obj
   link foo.exe

 FOO.EXE:: FOO2.obj
   link foo.exe

 FOO.EXE:: FOO3.obj
   link foo.exe

 FOO.EXE:: FOO.RES
   RC FOO.RES FOO.EXE

 The second alternative is to put all the dependencies on the same
 line as the target, for example:

 FOO.EXE:: FOO1.obj FOO2.obj FOO3.obj
   link foo.exe

 FOO.EXE:: FOO.RES
   RC FOO.RES FOO.EXE


 22. A Complete Example of Utilizing Paths in NMAKE

 Product Version(s): 1.00 1.01 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q60340

 The make file shown below is an NMAKE example of using paths in
 macros, inference rules, and target dependencies (descriptor blocks).
 This is a working example of what is described on Page 298 of the
 "Microsoft FORTRAN CodeView and Utilities User's Guide" and Page 168
 of the "Microsoft QuickC Tool Kit."

 This make file compares the modification dates of the .H and the .C
 files with the .OBJ files, and the .OBJ files with the .EXE files. If
 any of the dependent files have changed more recently than the target
 files, the specified series of commands is executed. The .H and the
 .C files in the work directory are compared to the .OBJ files of the
 lib directory.

 If any of the source file(s) have changed since the last .OBJ was
 .created, then it is recompiled and copied from the current
 directory to the lib directory. The .OBJ files in the lib directory
 are compared to the .EXE files in the current directory. If any of the
 .OBJ files have changed since the last .EXE was created, then the
 .OBJs are relinked.

 Sample Make File
 ----------------

 #macros

 objdir =d:\qc2\lib
 wrkdir =d:\qc2\work
 list   =$(objdir)\grdemo.obj $(objdir)\turtle.obj \
 $(objdir)\menu.obj
 cc     =qcl -c

 #inference rules

 #compile
 {$(wrkdir)}.c{$(objdir)}.obj:
  $(cc) $<
  copy $(*F).obj $(*R).obj
  erase $(*F).obj

 #link
 {$(objdir)}.obj{}.exe:
  link $(**R);

 #target-dependencies

 run: grdemo.exe

 $(objdir)\*.obj: $(wrkdir)\$$(@B).c $(wrkdir)\menu.h \
 $(wrkdir)\turtle.h

 grdemo.exe: $(list)


 23. NMAKE May Invoke MASM Instead of the C Compiler

 Product Version(s): 1.00 1.01 1.11 | 1.01 1.11
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | docsup s_pwb h_fortran
 Last Modified: 17-JUL-1990    ArticleIdent: Q60746

 When using an NMAKE file in combination with adding /Fa to the
 compiler options within Programmer's WorkBench (PWB), NMAKE will
 invoke the Macro Assembler, if it is in the current search path.

 This does not occur the first time you build your application, but it
 does occur the second time, and thereafter, because of the generation
 of the .ASM created by the compiler.

 Files with the .ASM extension have a predefined inference rule within
 NMAKE to invoke MASM. However, the inference rule for .ASM files takes
 place before the rule for files with the .C or .OBJ extension.
 Therefore, if you have a filename with the same base name, but one has
 an .ASM extension and the other has a .C extension (as is the case
 with the /FA switch), the .ASM file will be assembled before the .C
 file will be compiled. Since the assembly step generates an .OBJ file
 that is newer than the .C file, the .C file is never compiled.

 Use the following procedures to work around this behavior:

 1. The best workaround is to use /Fa [LSTFILE.EXT] with a filename
    included as a compiler option, instead of allowing the /Fa option
    to default to its <filename>.ASM.

    Example: /Fa <filename>.ASC

    In using this method, the .C file will be compiled, instead of the
    .ASM version being assembled.

 2. Use the /Fc compiler option in place of the /Fa option (if you just
    want to look at an assembly source listing). This produces a .COD
    file (combined assembly and C source listing).

 3. Use the /R switch for the NMAKE invocation to ignore inference
    rules and macros that are predefined or defined in the TOOLS.INI
    file.

 For a more in-depth discussion on the /R switch and its effects, see
 the following references:

 1. The "Microsoft C Advanced Programming Techniques" reference manual

    Page(s) 112-114 Predefined macros
            118-119 Predefined inference rules
            125     /R Switch

 2. The "Microsoft FORTRAN, CodeView and Utilities User's Guide"

    Page(s) 288     /R Switch
            295-297 Predefined macros
            299-230 Predefined inference rules

 3. The "Microsoft QuickC Toolkit" reference manual

    Page(s) 158     /R Switch
            165-197 Predefined macros
            169     Predefined inference rules


 24. Looking for Files in Different Directories

 Product Version(s): 1.00 1.01 1.10 1.11 | 1.01 1.10 1.11
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_c s_quickc s_quickasm h_fortran
 Last Modified: 17-JUL-1990    ArticleIdent: Q60867

 If you use the "directory search" feature of NMAKE (curly braces "{}")
 to use a separate directory for some files, the location of these
 files cannot be inferred in subsequent dependency rules.

 The following code example demonstrates this confusion:

    test.exe: {\obj}test.obj
       link \obj\test.obj graphics.lib;

    test.obj: test.c test.h
       cl /c /Fo\obj\test.obj test.c

 If TEST.EXE and \OBJ\TEST.OBJ were up to date and we were to change
 one of the dependencies for TEST.OBJ, nothing would happen. This is
 because \OBJ\TEST.OBJ doesn't have any dependencies. The TEST.OBJ
 dependency line is only for the current directory. If we were to
 change the TEST.OBJ line to the following

    {\obj}test.obj: test.c test.h

 a change to TEST.C or TEST.H would cause \OBJ\TEST.OBJ and TEST.EXE
 to be updated.

 Note: NMAKE has a predefined inference rule for C.EXE that causes
 TEST.EXE to be relinked in the above example if it is out of date with
 TEST.C.


 25. /MAKE Option Is Invalid with NMAKE

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 25-MAY-1990    ArticleIdent: Q61619

 On Page 43 of the "Microsoft C Reference" manual for version 6.00,
 NMAKE is described as being upwardly compatible with the earlier MAKE
 utility through the use of the /MAKE option. Since NMAKE does not
 support the /MAKE option, it produces the error "U1065:  Invalid
 option 'm'."

 To work around this problem, you can either use the earlier MAKE
 utility, or use a pseudo-target on the first line of your make file.
 The pseudo-target line should read as follows:

    ALL: [target name.exe/obj]

 For more information about the differences between MAKE and NMAKE, see
 Section 6.9 of the "Microsoft C Advanced Programming Techniques"
 manual for version 6.00.


 26. Using "!" and "$?" Do Not Work as Expected with NMAKE 1.11

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.11
 Last Modified:  6-FEB-1991    ArticleIdent: Q61808

 Applying the "!" (exclamation point) operator to the beginning of a
 command line using the macro "$?" should cause the command to be
 executed once for every out-of-date dependent file. (This is
 documented on Page 108 of the "Advanced Programming Techniques" manual
 included with the Microsoft C Optimizing Compiler version 6.00.)

 This feature works correctly in NMAKE version 1.00, but does not work
 as expected in version 1.11. NMAKE version 1.11 is included with the
 Microsoft C Compiler version 6.00.

 In version 1.11 of NMAKE, the $? macro evaluates to the list of every
 dependent, regardless of whether it is out of date or not. This is not
 the correct behavior.

 To re-create this problem, save the following lines to a file called
 MAKEFILE:

    new.lib: a.obj b.obj c.obj
        !lib $@-+$?;

 Assuming that only a.obj is out-of-date with respect to new.lib, the
 following will be produced upon running NMAKE:

 1. NMAKE 1.00:

       lib new.lib-+a.obj;

 2. NMAKE 1.11:

       lib new.lib-+a.obj
       lib new.lib-+b.obj
       lib new.lib-+c.obj

 Example 1 above shows the correct function of the $? macro.

 Fortunately, the problem above is easy to fix.  NMAKE performs
 correctly if two colons (::) are placed after the target new.lib on
 the dependency line.  The NMAKE file has been re-written below so that
 the $? macro will work with NMAKE 1.11.

 MODIFIED NMAKE FILE
 -------------------
 new.lib::a.obj b.obj c.obj
    !lib $@-+$?;

 The use of the two colons on the dependency line is described on page
 109 of the Advanced Programming Techniques manual included with the
 Microsoft C compiler version 6.00.

 Microsoft has confirmed this to be a problem with NMAKE version 1.11.
 The problem has been resolved with later versions of NMAKE.


 27. NMAKE U1001 Illegal Character Caused by Corrupted MAKEDIR

 Product Version(s): 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.11
 Last Modified:  4-DEC-1990    ArticleIdent: Q61978

 NMAKE version 1.11 may produce a U1001 "syntax error: illegal
 character <character> in macro" while building a project.

 NMAKE has an internal macro, MAKEDIR, which contains the full drive
 and path to the directory from where NMAKE was invoked. This macro is
 corrupted in NMAKE version 1.11 under DOS. Rather than the correct
 pathname, the macro contains "garbage" or graphics characters. This
 macro can cause the U1001 "illegal character" error message.

 To display the contents of MAKEDIR, invoke NMAKE with the /P switch.
 This switch causes all macros to be displayed to the screen. To work
 around this problem, manually set MAKEDIR in the .MAK file for the
 project. Set it to the drive and path where the project is being
 built. If MAKEDIR is manually set in the .MAK file, it will override
 the default setting and correct the problem.

 Microsoft has confirmed this to be a problem with NMAKE version 1.11.
 We are researching this problem and will post new information here as
 it becomes available.

 NMAKE version 1.11 comes with Microsoft C Professional Development
 System version 6.00 for MS-DOS and MS OS/2.

 This problem does not occur with NMAKE version 1.10. The problem
 occurs only with the DOS version of NMAKE, not the protected mode
 version of NMAKE version 1.11.


 28. Can't Use Multiple Description Blocks with NMAKE Version 1.10

 Product Version(s): 1.10
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.10 fixlist1.11 b_basiccom
 Last Modified: 25-JUL-1990    ArticleIdent: Q62332

 Page 639 of "Microsoft BASIC 7.0: Programmer's Guide" explains how you
 can use NMAKE to specify more than one description block for the same
 target.

 The example given on this page is the proper way to specify more than
 one description block; however, this feature does not function
 correctly in NMAKE version 1.10. It does function correctly in NMAKE
 version 1.11.

 NMAKE version 1.10 shipped with the Professional Development System
 (PDS) BASIC version 7.00. NMAKE version 1.11 shipped with Microsoft C
 Professional Development System (PDS) version 6.00.

 The following example specifies more than one description block for
 the same target by using two colons (::) as the separator instead of
 one. The following example is taken from Page 639 of "Microsoft BASIC
 7.0: Programmer's Guide":

       TARGET.LIB :: A.ASM B.ASM C.ASM
          MASM A.ASM B.ASM C.ASM;
          LIB TARGET -+A.OBJ -+B.OBJ -+C.OBJ;
       TARGET.LIB :: D.BAS E.BAS
          BC D.BAS;
          BC E.BAS;
          LINK D.OBJ E.OBJ;
          LIB TARGET -+D.OBJ -+E.OBJ;

 Given the two description blocks above, NMAKE should update the
 library named TARGET.LIB. In the first description block, if any of
 the assembly language files have changed more recently than the
 library, the assembly files will be assembled and the library will be
 updated with the new .OBJs. In the second description block, the BASIC
 files that have changed should be compiled and the library should also
 be updated with the new OBJs.

 When using NMAKE version 1.10, the commands in the first description
 block are executed correctly; however, the commands in the second
 description block are never executed.

 Microsoft has confirmed this to be a problem in NMAKE version 1.10.
 This problem was corrected in version 1.11.


 29. Expression in Brackets "

 Product Version(s): 1.00 1.01 1.10 1.11 | 1.01 1.10 1.11
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 27-JUN-1990    ArticleIdent: Q63146

 When using the !IF directive in conjunction with the square brackets
 "[]" in the NMAKE utility, all expressions inside square brackets will
 be evaluated when NMAKE initially reads the makefile, before any
 commands are executed (and before dependency blocks are evaluated).

 The square brackets are used within NMAKE to denote program
 invocations in expressions within an !IF directive, as documented in
 Section 6.3.5, Pages 120-121 of the "Advanced Programming Techniques"
 manual shipped with the Microsoft C compiler version 6.00.

 By design, all the program invocations are executed when NMAKE starts
 up, regardless of whether or not they are contained in a dependency
 block. The return values of these program invocations can then be used
 within the !IF expression to evaluate the expression.

 The following makefile displays this behavior:

    test.exe: test.c
    !IF ( [check /f] < 3 )
       cl test.c
    !ENDIF

 In this example, the program "check /f" will be executed each time the
 makefile is called, regardless of whether or not the file TEST.EXE is
 up to date.


 30. Changing Directories in Make Files Not Supported by NMK.COM

 Product Version(s): 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.11 S_QUICKC S_C
 Last Modified: 31-AUG-1990    ArticleIdent: Q64028

 Using a command to change directories in a make file will cause
 unexpected results with NMK.COM version 1.11. This is a side effect of
 a problem with NMAKE.EXE where directory changes within make files are
 executed while processing the make file, and the current directory is
 not reset upon exit.

 NMK spawns NMAKE to do its processing. While NMAKE is processing, if
 it sees a change drive/directory command, it must make the change to
 finish processing the make file. The problem is that it doesn't reset
 the drive when it is through processing. This causes NMK, when control
 is returned to it, to spawn the actual commands from the final
 drive/directory, rather than where it was originally invoked.

 The make file below, if run from Drive D, will demonstrate the
 problem. It works properly with NMAKE.EXE but not with NMK.COM.

 all: cded.exe

 cded.exe: cded.obj
   c:\
   copy cded.obj cded.exe

 cded.obj: cded.mak
   copy cded.mak c:\cded.obj

 To work around the problem, add a line at the end of each place block
 where you change the drive/directory to the original one (if known).
 For example, change the above make file to the following:

 all: cded.exe

 cded.exe: cded.obj
   c:\
   copy cded.obj cded.exe
   d:

 cded.obj: cded.mak
   copy cded.mak c:\cded.obj


 31. Spaces in Inference Rules Corrupt NMAKE Macro Expansion

 Product Version(s): 1.00 1.11 | 1.00 1.11
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_quickc
 Last Modified: 28-AUG-1990    ArticleIdent: Q65084

 If a space is inserted between the target and dependent extensions in
 an inference rule, it will cause NMAKE's default macros to expand
 incorrectly. The correct syntax for inference rules is to list the
 dependent file extension followed by the target file extension WITHOUT
 any embedded spaces.

 The following sample make files demonstrate a few of the problematic
 results that are possible if spaces are used in an inference rule. In
 both cases below, note that it is the embedded spaces that cause NMAKE
 to invoke the commands incorrectly. Removing the spaces allows NMAKE
 to generate the desired commands.

 Example 1
 ---------

 {c:\source\}.c {c:\objs\}.obj:
   cl $*

 ALL: c:\objs\foo2.obj

 c:\objs\foo2.obj: c:\source\foo2.c

 Command executed by NMAKE:

 cl {c:\objs\}

 Example 2
 ---------

 .c .obj:
   cl $<

 ALL: foo.obj

 foo.obj: foo.c

 Command executed by NMAKE:

 cl


 32. In-line File in Inference Rule Causes Bad Macro Substitution

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.11
 Last Modified: 11-NOV-1990    ArticleIdent: Q66459

 Using an in-line file inside of an inference rule can cause improper
 results in macro substitutions following the in-line file. The example
 below demonstrates the problem.

 Make File Example
 -----------------

 EXENAME=test.exe
 SAMPLEDIR=\test

 .obj.exe:
   link @<<lrf     <--- In-line file with $(EXENAME) macro
 $<                     causes the problem.
 $(EXENAME);
 <<KEEP
   cd $(SAMPLEDIR)

 test.exe:test.obj

 test.obj:test.c

 The above NMAKE description file produces the following output:

    cl -c test.c
    link @lrf
    cd test.exe    <---- This is wrong.  It should be "cd \test"
 NMAKE: fatal error U1077: 'cd' return code 1
 Stop.

 The third line of the output is incorrect. The macro $(SAMPLEDIR) is
 replaced with the value of $(EXENAME).

 Microsoft has confirmed this to be a problem in version 1.11. We are
 researching this problem and will post new information here as it
 becomes available.


 33. Documentation Error: Extmake Syntax for %|partsF Incorrect

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  6-NOV-1990    ArticleIdent: Q66474

 The extmake syntax for determining the complete name of the first
 dependent in a NMAKE description file is incorrectly described in the
 "Advanced Programming Techniques" manual on Page 124.

 The extmake syntax described on Page 124 of the "Advanced Programming
 Techniques" manual lists the syntax as

    %|partsF

 where parts is one or more of the following:

    Letter            Description
    ------            -----------

    d                 Drive
    e                 File extension
    f                 File base name
    p                 Path
    s                 Complete name

 However, "s" is not a valid selection. You may use %s, or you may use
 %|partsF, where "parts" is one or more of the above (d, e, f, or p,
 but not s). The following makefile illustrates the problem.

 Sample Makefile
 ---------------

    sample.obj: sample.c
         cl /c %|sF

 If this makefile is run, it will produce the following error message:

    NMAKE : fatal error U1098: extmake syntax in sF incorrect

 The online help specifies the correct syntax for using the extmake
 switch:

    Letter     File-Specification Part
    ------     -----------------------

    p          Path
    d          Drive
    f          Base name
    e          Extension

 The makefile below shows the correct extmake syntax for obtaining the
 complete name of the first dependent:

 Correct Makefile
 ----------------

    sample.obj: sample.c
         cl /c %s


 34. Problem in NMAKE 1.11 with Multiple Dependency Blocks

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.11 fixlist1.12 s_c
 Last Modified:  9-NOV-1990    ArticleIdent: Q66571

 The sample makefile below will be correctly executed in all cases
 except if the target is missing. In that case, both sets of commands
 will be executed even though the second set is not necessary.

 Microsoft has confirmed this to be a problem in NMAKE version 1.11.
 This problem has been corrected in version 1.12, which shipped with
 Microsoft COBOL version 4.00.

 Multiple Dependency blocks are supposed to be evaluated one at a time.
 In the sample makefile, because the target is missing when NMAKE is
 invoked, it assumes that both sets of commands will need to be
 invoked. This is incorrect behavior.

 Sample Makefile
 ---------------

 test.exe :: test.obj test.def
     link /nod test,,,slibcew libw, test.def
     rc test.res

 test.exe :: test.res
     rc test.res


 35. NMAKE 1.11 Fails to Stop If Command Is Redirected

 Product Version(s): 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.11 fixlist1.12
 Last Modified:  9-NOV-1990    ArticleIdent: Q66572

 If the command line that NMAKE invokes is redirected to another
 output file and the command returns a non-zero return code, NMAKE
 version 1.11 will not stop the build process.

 Microsoft has confirmed this to be a problem in the DOS version of
 NMAKE.EXE. This problem has been corrected in version 1.12.

 The following is a sample make file that, with NMAKE version 1.11,
 will fail to stop if the compiler returns an error; with version 1.12,
 it correctly stops the build process:

 all: foo.exe

 foo.obj: foo.c
    cl /c /AS foo.c >foo.err

 foo.exe: foo.obj
    link /NOI /NOE foo.obj;

 The easiest way to workaround this is to redirect from the command
 line, for example:

    nmake /f foo.mak >foo.err

 The drawback to this is that you can only have one error log.


 36. NMAKE /N Doesn't Work Across Multiple Dependency Blocks

 Product Version(s): 1.11 1.12 | 1.11 1.12
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.11 buglist1.12
 Last Modified:  7-NOV-1990    ArticleIdent: Q66644

 Given the sample makefile below and the fact that mod2.c has been
 changed, invoking NMAKE /N displays the following commands:

    cl /c -c mod2.c
    lib sub.lib -+ mod2.obj;

 However, if NMAKE is run without the /N parameter, the following
 commands will be executed:

    cl /c -c mod2.c
    lib sub.lib -+ mod2.obj;
    link boss.obj,,,sub.lib;

 The /N switch is used to debug the logic of makefiles without actually
 processing them. In this case, the commands that /N indicates will be
 executed are not the same as those that actually are executed. This is
 caused by the multiple dependencies for sub.lib. If the makefile is
 changed to eliminate the multiple dependency blocks, the /N switch
 will function correctly.

 Microsoft has confirmed this to be a problem in NMAKE versions 1.11
 and 1.12. We are researching this problem and will post new
 information here as it becomes available.

 Sample Code
 -----------

 CFLAGS=/c

 .obj.exe:
         link $<,,,sub.lib;

 all:boss.exe

 boss.exe:boss.obj  sub.lib

 boss.obj:

 sub.lib:: mod1.obj
         lib $@ -+ mod1.obj;

 sub.lib:: mod2.obj
         lib $@ -+ mod2.obj;


 37. U4007 Error Can Be Caused By Not Using Quotation Marks

 Product Version(s): 1.11 1.12
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  7-NOV-1990    ArticleIdent: Q66646

 If you have a makefile for OS/2 that uses long filenames, you must use
 quotation marks around the long filenames. For instance, if the
 following makefile is used, it will generate the U4007 error message
 ("file name too long:  truncating to 8.3"):

 Sample Makefile
 ---------------

 all: thisisalongfilename.exe

 thisisalongfilename.exe: thisisalongfilename.obj
    link thisisalongfilename.obj;

 thisisalongfilename.obj: thisisalongfilename.c
    cl /c /Tcthisisalongfilename.c

 If the makefile above is changed to the following version, the error
 will not be generated:

 Sample Makefile
 ---------------

 all: "thisisalongfilename.exe"

 "thisisalongfilename.exe": "thisisalongfilename.obj"
    link "thisisalongfilename.obj";

 "thisisalongfilename.obj": "thisisalongfilename.c"
    cl /c /Tc"thisisalongfilename.c"

 For more information on this behavior, please see the README.DOC file
 shipped with Microsoft C version 6.00.


 38. Cause of U4004 Error Message

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified:  7-NOV-1990    ArticleIdent: Q66649

 The U4004 error message is generated by NMAKE when it encounters
 multiple build dependency blocks for a single target. The following is
 a sample makefile:

 all: tty.exe

 tty.res: tty.rc tty.dlg tty.h
     rc -r tty.rc

 tty.obj: tty.c
    cl -c -AS -Gsw -Os -Zdp tty.c

 wstdio.obj: wstdio.c
    cl -c -AS -Gsw -Os -Zdp wstdio.c

 tty.exe: tty.obj wstdio.obj tty.def
     link /NOD tty wstdio,,,libw slibcew,tty.def
     rc tty.res

 tty.exe: tty.res tty.dlg tty.h
    rc tty.res

 To eliminate the error, use the multiple dependency block separator --
 a pair of colons (::). In the above makefile, the two dependency
 blocks for tty.exe should use this syntax. The multiple dependency
 block separator is documented further on page 109 of the "Advanced
 Programming Techniques" manual, as well as in the online help.

 The following is the corrected makefile:

 all: tty.exe

 tty.res: tty.rc tty.dlg tty.h
     rc -r tty.rc

 tty.obj: tty.c
    cl -c -AS -Gsw -Os -Zdp tty.c

 wstdio.obj: wstdio.c
    cl -c -AS -Gsw -Os -Zdp wstdio.c

 # Note the use of the double colon below and in the next block...

 tty.exe:: tty.obj wstdio.obj tty.def
     link /NOD tty wstdio,,,libw slibcew,tty.def
     rc tty.res

 tty.exe:: tty.res tty.dlg tty.h
    rc tty.res


 39. Link Not Performed During Build or Make

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.00 fixlist1.10 fixlist1.11 s_c s_link s_pwb
 Last Modified: 14-DEC-1990    ArticleIdent: Q67482

 During a build inside the Programmer's WorkBench (PWB) (using PWB.COM)
 or while using NMK.COM from the command line, the build operation
 returns successfully but no .EXE file is created.

 This problem may be caused by an incorrectly set COMSPEC environment
 variable. If the COMSPEC environment variable contains any extra
 characters, NMK.COM fails to properly spawn the linker. This affects
 the PWB as well because, under DOS, PWB.COM spawns the build commands
 the same way as NMK.COM. Two examples of COMSPEC environment variables
 that cause this problem are shown in the following:

    COMSPEC=C:\COMMAND.COM /E:512 /P
    COMSPEC=C:\COMMAND.COM;

 Microsoft has confirmed this to be a problem in PWB.COM version 1.00
 and NMK.COM version 1.00. This problem was corrected in PWB.COM
 version 1.10 and NMK.COM version 1.11.


 40. NMK.COM Will Execute PWB.SHL If it Exists

 Product Version(s): 1.00 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | S_C S_PWB S_QUICKC S_NMK
 Last Modified: 28-DEC-1990    ArticleIdent: Q67776

 NMK.COM will execute the PWB.SHL file if it exists in the subdirectory
 specified by the TMP environment variable. After spawning NMAKE to
 parse the desired makefile, PWB.SHL will be executed as a batch file
 with the commands listed in reverse order.

 This is expected behavior since NMK actually spawns NMAKE with the /z
 option. This instructs NMAKE to preprocess the makefile, writing out
 the commands to be performed into the file PWB.SHL, which is placed in
 the directory pointed to by the TMP environment variable. After NMAKE
 is finished, NMK reads the PWB.SHL file and executes the required
 commands. Once it is finished, the PWB.SHL file is set to 0 bytes or
 deleted.

 To see this behavior, create a file and name it PWB.SHL, placing the
 following two lines in it:

    type listing.txt
    dir > listing.txt

 Place this file in the subdirectory pointed to by the TMP environment
 variable. The following command will spawn NMAKE /z in an attempt to
 parse PROGRAM.MAK, and then execute PWB.SHL:

    nmk /f program.mak

 PWB.SHL will be set to 0 bytes or deleted after all commands have been
 executed.

 If PROGRAM.MAK does not exist, NMAKE will report an error informing
 you of that fact, and then NMK will proceed to execute PWB.SHL as
 described above.

 If you do not have a TMP environment variable, PWB.SHL will be
 executed if it exists in the current subdirectory.

 A side effect to be aware of is the following scenario. If you have
 shelled out of the Programmer's WorkBench to run your program (from
 the Execute selection on the Run menu) and your program hangs, forcing
 you to reboot, a PWB.SHL file will be left in your TMP subdirectory.
 If, after rebooting, you happen to run NMK before going into PWB, NMK
 will find the PWB.SHL file in the TMP subdirectory and execute it,
 causing PWB to be invoked even though you had not explicitly invoked
 PWB since the reboot.


 41. NMAKE Does Not Expand Wildcard Characters

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified:  6-FEB-1991    ArticleIdent: Q67794

 Page 107 of the "Advanced Programming Techniques" manual that shipped
 with Microsoft C version 6.00 states:

    NMAKE expands wild cards in target names when it reads the
    description file.

 NMAKE does not expand these wildcard characters when passing the
 wildcard to the compiler. The example given works correctly because
 the compiler expands the wildcard on its own. If you use a compiler
 that does not expand wildcards, the example given will not work.


 42. NMAKE Default Is to Build Only the First Target in a Makefile

 Product Version(s): 1.00 1.01 1.11 1.12 | 1.01 1.11 1.12
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER |
 Last Modified: 15-JAN-1991    ArticleIdent: Q40184

 The NMAKE file maintenance utility will only "make" the first target
 in the makefile if no target is explicitly given on the command line.

 Although the following sample makefile will both compile and link
 PROG1.EXE when used with MAKE, it will only compile when the NMAKE
 utility is used. This is an important consideration when porting
 makefiles from MAKE to NMAKE.

 # Sample makefile MAKEFILE1

 PROG1.OBJ : PROG1.C
     cl /Zi /c PROG1.C

 PROG1.EXE : PROG1.OBJ
     link /CO PROG1.OBJ

 If all files are out of date with PROG1.C, and MAKEFILE1 is executed
 with the standard invocation as follows

    NMAKE /f makefile1

 the only command executed from MAKEFILE1 will be the following:

    cl /Zi /c prog1.c

 The LINK command will not be executed because NMAKE did not receive a
 specific target; thus, it only makes the first target in the makefile.
 To achieve the desired results, the desired target (PROG1.EXE) must be
 specified on the NMAKE command-line or the following line could be
 added to MAKEFILE1 (it must be the first line in the makefile):

    ALL : PROG1.EXE

 This pseudotarget "ALL" will be made because it will be the first
 target in the makefile. By using the pseudotarget, it is guaranteed
 that all dependencies will be made because the dependents are always
 out of date. This will force NMAKE to make all targets dealing with
 PROG1.EXE.

 Please refer to the NMAKE documentation shipped with your compiler or
 assembler for more information.


 43. Accessing Environment Variables Inside MAKE or NMAKE Makefile

 Product Version(s): 1.00 1.01 1.10 1.11 1.12 | 1.01 1.10 1.11 1.12
 Operating System:   MS-DOS                   | OS/2
 Flags: ENDUSER | s_make
 Last Modified: 23-JAN-1991    ArticleIdent: Q59141

 You can access environment variables within a MAKE or NMAKE makefile
 in the same way that you access user-defined macros. The only
 difference is that the names of environment variables must be
 capitalized when used in this manner. For example:

 SOURCE=c:\mysource
 # the INCLUDE "macro" will pick up your INCLUDE environment variable

 file.obj : $(SOURCE)\file.c $(INCLUDE)\file.h
     cl /c /Zi /Od $(SOURCE)\file.c


 44. Recursively Calling NMAKE Using the MAKEFLAGS Macro

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 17-JAN-1991    ArticleIdent: Q68234

 According to page 113 of the "Microsoft C Advanced Programming
 Techniques" manual, if you want to invoke NMAKE recursively, the macro
 $(MAKEFLAGS) can be used to pass the command-line switches to the
 recursively invoked NMAKE. However, the $(MAKEFLAGS) macro will
 contain only the letters of the switches and will not contain the
 actual command-line syntax.

 For example, if the original command line contained "/D /N", the
 $(MAKEFLAGS) macro will contain "DN". This results in NMAKE trying to
 use the $(MAKEFLAGS) macro as the name of the makefile, rather than as
 command-line switches. To use the $(MAKEFLAGS) macro to invoke NMAKE
 recursively, it is necessary to precede it with a hyphen (-) or
 forward slash (/) so that NMAKE uses the macro as a set of
 command-line switches. The documentation should read:

    $(MAKE) -$(MAKEFLAGS)


 45. Placing a Target File in Different Directory Than Dependents

 Product Version(s): 4.07   | 4.07
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_make
 Last Modified:  6-FEB-1991    ArticleIdent: Q46354

 To put a target file in a directory different from its dependent file
 in a makefile, you must explicitly name the path for the target file.
 When compiling, use the /Fo switch and a path to place the .OBJ file
 in a different directory from the source. When linking, give the full
 pathname when specifying the .EXE file parameter.

 The following example demonstrates both aspects:

 # MAKE SURE THERE IS A TRAILING BLANK AFTER THE FINAL BACKSLASH
 LONGPATH=e:\c51\binr\
 SHORTPATH=e:\c51\

 pixel.obj:  $(LONGPATH)pixel.c
 # USE /Fo SWITCH TO PUT .OBJ FILE IN DIFFERENT DIRECTORY
   cl /Fo$(SHORTPATH) /c $(LONGPATH)pixel.c

 Note that if you use a macro in the makefile for the pathname (as
 shown above), then you must be sure the final backslash (\) in the
 pathname is followed by a trailing space. If there is no trailing
 space, the backslash will be interpreted as a line-continuation
 character. When you create the makefile, use an editor that will
 preserve a trailing space, such as the Programmer's WorkBench or the
 Microsoft Editor (if you set the "trailspace" switch).


 46. Extmake Switch Does Not Expand Macros

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.11
 Last Modified: 24-JAN-1991    ArticleIdent: Q68379

 The following NMAKE description file shows that macro substitution
 does not occur when using the extmake switch.

 To show the error, set SUBDIR to a subdirectory and execute NMAKE on
 the makefile while in ANOTHER subdirectory.

 Sample Makefile
 ---------------

 SUBDIR = subdir

 foo.exe: $(SUBDIR)\foo.c
      cl %|pfeF

 Resulting command:  cl $(SUBDIR)\foo.c

 The workaround for this particular problem is to replace the extmake
 switch with the predefined macros (that is, $** and $?).


 47. The D Modifier to $? Is Broken in NMAKE Version 1.11

 Product Version(s): 1.11   | 1.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.11 fixlist1.12
 Last Modified: 24-JAN-1991    ArticleIdent: Q68381

 The D modifier to the $? macro is supposed to return the directory and
 drive portion of the dependent. This does not work properly with NMAKE
 version 1.11. Instead, the full pathname and filename are returned.
 This was corrected in NMAKE version 1.12, which shipped with Microsoft
 COBOL version 4.00.

 Sample Makefile
 ---------------

 all : c:\dos\command.com
    echo The D modifier of $? is $(?D)


 48. $$(@F) Macro Doesn't Work with NMAKE Version 1.01

 Product Version(s): 1.01   | 1.01
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | buglist1.01 fixlist1.11
 Last Modified: 24-JAN-1991    ArticleIdent: Q68388

 The $$(@F) macro illustrated on page 297 of the "Microsoft FORTRAN
 CodeView and Utilities User's Guide" for version 5.00 will not
 function correctly in NMAKE version 1.01. This has been corrected in
 NMAKE version 1.11, which shipped with Microsoft C version 6.00.

 The following is the example from page 297:

 DIR=c:\include
 $(DIR)\global.h $(DIR)\types.h $(DIR)\macros.h: $$(@F)
      !COPY $? $@

 With NMAKE version 1.01, this will only work for the first file in the
 list. Subsequent files are not processed. NMAKE 1.11 correctly copies
 all three files to the c:\include directory.


 49. NMK Displays Only First of Multiple Commands

 Product Version(s): 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.11 S_C S_NMK
 Last Modified:  1-FEB-1991    ArticleIdent: Q68658

 NMK version 1.11 displays only the first of multiple commands it is
 executing when the exclamation point (!) command modifier is used with
 the predefined macro $? or $**.

 The ! command modifier executes the command for each dependent file if
 the command uses the predefined macro $? or $**. The $? macro refers
 to all dependent files that are out-of-date with respect to the
 target. The $** macro refers to all dependent files in the description
 block.

 The sample makefile below echoes each filename to the screen. The
 NMAKE output shows the correct result; each ECHO command is displayed
 and executed. Likewise, the NMK output executes each ECHO command;
 however, only the first command is displayed to the screen.

 Sample Makefile
 ---------------

 ALL: foo1.c foo2.c foo3.c
       !ECHO $**

 Output:

       NMAKE                      NMK
 -----------------         -----------------
       ECHO foo1.c               ECHO foo1.c
 foo1.c                    foo1.c
       ECHO foo2.c         foo2.c
 foo2.c                    foo3.c
       ECHO foo3.c
 foo3.c

 Microsoft has confirmed this to be a problem in NMK version 1.11. We
 are researching this problem and will post new information here as it
 becomes available.


 50. NMAKE Doesn't Allow CD Command That Only Specifies Drive

 Product Version(s): 1.11 1.12 | 1.11 1.12
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | buglist1.11 buglist1.12
 Last Modified:  5-FEB-1991    ArticleIdent: Q68836

 DOS and OS/2 command lines allow you to see the current directory of a
 drive by using the CD (change directory) command. For example, the
 command "CD D:" will return the current directory for the D drive.
 Because this is a valid DOS or OS/2 command, NMAKE should allow you to
 perform the command without error. However, when the NMAKE file below
 is executed, the following message occurs:

    NMAKE: fatal error U1077: 'cd' :return code '1'

 NMAKE treats the CD command as a special case and fails to execute the
 command correctly.

 Sample NMAKE File:

 all:
    cd d:

 Microsoft has confirmed this to be a problem in NMAKE versions 1.11
 and 1.12. We are researching this problem and will post new
 information here as it becomes available.


 51. NMK Macros Do Not Override Environment Variables

 Product Version(s): 1.11
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist1.11
 Last Modified:  6-FEB-1991    ArticleIdent: Q68946

 Macros that are created to redefine environment variables (such as
 INCLUDE, LIB, and PATH) do not work correctly when the description
 file is executed using NMK.COM, rather than NMAKE.EXE.

 The description file below, when executed by NMAKE.EXE, will look for
 the include files in the directory "E:\C\INCLUDE". If the same
 description file is executed by NMK.COM, the include directory will be
 determined by the include environment variable.

 Sample Code
 -----------

 INCLUDE=E:\C\INCLUDE

 FOO.EXE : FOO.OBJ
    link foo.obj;

 FOO.OBJ : FOO.C
    cl /c foo.c

 Note: This example will reproduce the problem correctly only if the
 following conditions are met.

 1. FOO.C exists.
 2. FOO.C contains a line of the form:

       #include <INC_FILE.H>

 3. INC_FILE.H exists in the directory "E:\C\INCLUDE".
 4. INC_FILE.H does not exist in the default include directory.

 Finally, NMK does change the variable for arguments that are in the
 makefile. Therefore, to work around the problem above, you can use the
 following example:

 INCLUDE=E:\C\INCLUDE

 FOO.EXE : FOO.OBJ
    link foo.obj;

 FOO.OBJ : FOO.C
    cl /c /I$(INCLUDE) foo.c






 Microsoft Development Utilities
 =============================================================================


 1. Hyphen in File or Directory Name Causes LIB Error U2155

 Product Version(s): 3.00 3.04 3.07 3.08 3.10 3.11 3.14 3.17 | 3.10 3.11 3.14
 Operating System:   MS-DOS                                  | OS/2
 Flags: ENDUSER | s_lib dash minus sign
 Last Modified: 16-JAN-1991    ArticleIdent: Q67880

 The Microsoft Library Manager utility LIB.EXE does not allow file or
 directory names to contain a hyphen (-) character. If a file or
 directory name containing a hyphen is passed to LIB.EXE, the following
 error will be generated:

    LIB : error U2155: <path> : module not in library; ignored

 Although a hyphen is a valid character for a DOS or OS/2 filename, LIB
 interprets this character as the extraction operator that tells LIB to
 remove an object module from an existing library. Since LIB is
 assuming everything following the hyphen is the name of an object
 module that you want removed, and since this is not an actual module
 name, the U2155 error is generated.

 A common situation where this error may occur is while installing one
 of the Microsoft language products that build combined libraries
 during the installation process. You may receive the U2155 error when
 running a Setup program if you have specified a directory name during
 setup that contains a hyphen. For example, many C users install the C
 compiler in a directory called MS-C, but Setup then fails when LIB is
 called to build the combined libraries in that directory.

 This is expected behavior for LIB.EXE and is the result of the
 established command-line syntax. Unless the command-line syntax is
 changed, the hyphen cannot be recognized as a filespec character
 instead of an operator.


 2. How to Add a Category in QuickHelp

 Product Version(s): 1.70   | 1.40 1.70
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh s_helpmake
 Last Modified: 24-JAN-1991    ArticleIdent: Q66631

 When creating a help database with HELPMAKE, new categories may be
 added to the Microsoft Advisor help system for use in the QuickHelp
 utility. To add selections that will appear under the QuickHelp
 Categories menu, use the topic "List categories." Under the List
 categories topic, list the selections that need to be added to the
 menu.

 The following is a sample help file:

    File CATEGORY.TXT
    -----------------

       .context List categories
       Category1
       Category2

       .context Category1
       This is the information under the first category.

       .context Category2
       This is the information under the second category.

 For the file CATEGORY.TXT shown above, the HELPMAKE command line will
 appear as follows:

    helpmake /E8 /Ocategory.hlp category.txt

 The choice of /E8 for partial compression is strictly arbitrary in
 this case, and is shown for demonstration purposes only. The maximum
 compression can be achieved by using /E15, and no compression is
 denoted by /E0.

 When the above help database is added to the list of databases for the
 Advisor, the topics "Category1" and "Category2" will be added under
 the Categories menu.

 The items that are placed in the List categories topic should be
 topics that are already defined with ".context" strings; otherwise,
 when the item is selected from the Categories menu, a message will be
 displayed stating that the topic could not be found.

 When using HELPMAKE with the "/C" option, which preserves case
 sensitivity, you must use the string "List categories" exactly. The
 case is important. Failure to use the exact case for each letter will
 cause the Advisor to ignore the categories you have added.


 3. Help Files for QuickC Require Special "Backtrace" Declaration

 Product Version(s): 6.00 6.00a | 6.00 6.00a
 Operating System:   MS-DOS     | OS/2
 Flags: ENDUSER | docerr s_quickc s_helpmake
 Last Modified: 11-FEB-1991    ArticleIdent: Q68678

 When creating a help file using the Microsoft Helpmake utility, !B is
 defined to have the effect of backtracing to the previous help screen
 (if available). However, this is true only when using QuickHelp or the
 Programmer's WorkBench (PWB). If an attempt is made to use this help
 file with QuickC, the link will issue a beep and no backtrace will be
 allowed.

 The documentation included with Microsoft C version 6.00 does not
 reference the exclamation (!) character as being a special function.
 However, on pages 20-21, the "Professional Advisor Library Reference"
 lists all the options available for this command. It also states that
 the !CQ.HB command will allow QuickC version 2.00 compatibility.
 However, it should be noted that the compatibility for this function
 is for QuickC version 2.50 as well. The use of this command gives
 complete compatibility through C versions 6.00 and 6.00a, as well as
 QuickC versions 2.50 and 2.00.

 Another error in the documentation is that !CQ.HB must be in all
 lowercase letters (that is, !cq.hb). HelpMake will not issue an error
 message with an uppercase command, but it will also not allow a
 backtrace to be performed.


 4. Omitting .LIB Extension with BIND Gives U1268 Error

 Product Version(s): 1.10 1.30 | 1.10 1.30
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_bind
 Last Modified: 15-JAN-1991    ArticleIdent: Q29135

 Question:

 When I try to bind an application using the BIND utility, I receive
 the following error message:

    BIND : fatal error U1268: duplicate infile given

 This is my BIND command line:

    bind file.exe c:\c\lib\os2 c:\c\lib\api

 What is causing this error?

 Response:

 This error occurs with BIND if you do not specify the .LIB extension
 for the libraries, OS2.LIB and API.LIB. The correct command line is as
 follows:

    bind file.exe c:\c\lib\os2.lib c:\c\lib\api.lib

 Note that BIND version 1.00 displays the same error, but does not
 display an error number.


 5. C 6.00 Utility Support for OS/2 Long Filenames

 Product Version(s): 6.00
 Operating System:   OS/2
 Flags: ENDUSER | s_link s_nmake s_c
 Last Modified: 28-JAN-1991    ArticleIdent: Q58487

 The utilities shipped for Microsoft C version 6.00 provide limited
 support for OS/2 long filenames introduced in OS/2 version 1.20.

 The following is a list of the limitations:

 1. Long filenames with quotation marks are supported via the command
    line. For example:

       "fooo bar"

 2. Embedded quoted long filenames on the command line are not
    supported. For example:

       d:\foo\" bar xyzzy"

 3. Link supports one quoted long filename per argument. For example

       "foo bar"+"bar foo"

    will resemble the following:

       "foo bar+bar foo"

 4. NMAKE provides long filename support inside the makefile with the
    restriction (beyond 1 and 2 above) that target and dependent names
    cannot have a period (.) as the first character (conflicts with
    inference rules). For example:

       ".foo bar.c".".foo bar.exe"


 6. Modifying Existing Help Files with HELPMAKE (QuickC Example)

 Product Version(s): 1.00 1.04 1.05 1.06 | 1.04 1.05 1.06
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_helpmake s_qh
 Last Modified: 24-JAN-1991    ArticleIdent: Q40599

 You can add to or change the information in the online help files that
 are accessible from QuickHelp, PWB, and QuickC. To accomplish this, do
 the following:

 1. Decompress the existing help file using HELPMAKE.EXE.

 2. Edit the resulting source listing of the help file.

 3. Recompress this modified file using HELPMAKE.EXE.

 The example below illustrates this process.

 There is a known coding error in the Font function examples in the
 QuickC 2.00 online help. This error occurs in the following code line:

    strcat (fondir, "\*.fon") ;

 This statement should be corrected to read as follows:

    strcat (fondir, "\\*.fon") ;

 To correct this online example in the GRAPHICS.HLP file, do the
 following:

 1. Decompress GRAPHICS.HLP, as follows:

       HELPMAKE /D /Ographics.src /V Graphics.hlp  > decode.log

    /D  Tells HELPMAKE to decode GRAPHICS.HLP
    /O  Tells HELPMAKE to name the output file GRAPHICS.SRC
    /V  Tells HELPMAKE to be verbose in decoding information

    "> decode.log"  redirects decoding information to DECODE.LOG.
    This DOS redirection is not necessary, but is helpful.

 2. Edit GRAPHICS.SRC

    Using an editor of your choice, search GRAPHICS.SRC for the
    code line that contains "\*.fon". When you locate the strcat()
    instruction mentioned above, you will notice that the line already
    correctly reads as follows:

       strcat (fondir, "\\*.fon") ;

    This is the correct coding for the C language. However,
    HELPMAKE.EXE views the backslash, "\", as a flag for instructions.
    Therefore, the first "\" is interpreted and is subsequently not
    viewable in the online help.

    If you intend a "\" to be viewed from within the online help, you
    must type two backslashes. That is why the strcat() instruction is
    displayed in the online help with only one "\".

    To display two successive backslashes from within online help, you
    must type four backslashes in the source file, which HELPMAKE will
    interpret and compress into a helpfile.

    In this example, you would modify the following statement

       strcat (fondir, "\\*.fon") ;

    to read as follows:

       strcat (fondir, "\\\\*.fon") ;

 3. Recompress GRAPHICS.SRC into a help file, as follows:
    (This process may take up to 10 minutes with this file.)

    HELPMAKE /E15 /A: /W128 /Ographics.hlp graphics.src /V > encode.log

    /E15   Tells HELPMAKE to fully compress GRAPHICS.SRC
    /A:    Tells HELPMAKE to view a ':' as an operator
    /W128  Tells HELPMAKE to truncate lines longer than 128 characters
    /O     Tells HELPMAKE to name the output file GRAPHICS.HLP
    /V     Tells HELPMAKE to output verbose encoding information

    "> encode.log" redirects encoding information to ENCODE.LOG
    This is helpful, but it is not necessary.

 4. Copy the new GRAPHICS.HLP to the directory with your other
    help files.

 For further information, refer to the printed or online documentation
 supplied with your version of HELPMAKE.


 7. HELPMAKE Interprets Backslashes as Formatting Flags

 Product Version(s): 1.00 1.04 1.05 1.06 | 1.04 1.05 1.06
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_helpmake
 Last Modified: 24-JAN-1991    ArticleIdent: Q40598

 The Microsoft HELPMAKE utility interprets a backslash (\) as a
 formatting flag. If you want to display a backslash in the online
 help, you must type two successive backslashes (\\). The first
 backslash is interpreted; the second is displayed.

 For further information on formatting flags, refer to the HELPMAKE
 documentation in the utilities manual, or the online help supplied
 with your particular compiler.


 8. HELPMAKE: "/A:" Must Be Used When Using Colon (:) Commands

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_helpmake s_quickc docerr
 Last Modified: 28-JAN-1991    ArticleIdent: Q42771

 In at least two places in the "Microsoft QuickC Tool Kit" version 2.00
 manual, it is implied that the colon (:) is used as a default for
 HELPMAKE commands. However, it is never explicitly stated that
 HELPMAKE must be invoked with the "/A:" option when encoding the help
 database.

 In fact, for any HELPMAKE colon (:) command to be recognized and
 correctly interpreted during the encoding process, the "/A:" switch
 must be used. For example, to encode the source file HELPTEST.SRC into
 the help database HELPTEST.HLP, the following line should be used
 (where "/A:" specifies the control character; "/E" indicates that the
 file is being encoded, not decoded; and "/O" gives the destination
 filename):

    HELPMAKE /A: /E /OHELPTEST.HLP HELPTEST.SRC

 HELPMAKE options may be in either uppercase or lowercase letters.


 9. Specifying Anchor Blocks in Help Files in RTF

 Product Version(s): 1.05   | 1.05
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 31-JAN-1991    ArticleIdent: Q68688

 Rich Text Format (RTF) is a text format supported by Microsoft Word
 and other word processors. HELPMAKE.EXE can use an RTF file (and the
 RTF symbols) to create help databases for the Microsoft Advisor.
 However, because \a (Anchor text for cross-reference) is not an RTF
 symbol, there is no documented method for creating hyperlinks that
 have more than one word.

 When Helpmake encodes RTF, any text between an RTF code and hidden
 text on a single line becomes a hyperlink. For example, the following

    {\bHyperlink here}{\vhyperlink.dat}

 will cause "Hyperlink here" to be displayed in bold type, and be a
 hyperlink to the topic "hyperlink.dat". To create an anchor block of
 unformatted text, use the \plain code. For example, the following

    {\plainplain hyperlink}{\vhyperlink.dat}

 will cause "plain hyperlink" to be displayed in normal text, and be a
 hyperlink to "hyperlink.dat". If you want to create a hyperlink that
 has only one word, anchor blocks are not needed. Finally, a link must
 fit entirely on one line. You cannot continue invisible or anchored
 text over a line break.

 Sample Code
 -----------

    {\rtf0
    >> open \par
    {\b Include:}   <fcntl.h>, <io.h>, <sys\\types.h>, <sys\\stat.h>

    {\b Prototype:}  int open(char *path, int flag[, int mode]);\par
        flag: O_APPEND  O_BINARY   O_CREAT  O_EXCL  O_RDONLY\par
         O_RDWR    O_TEXT   O_TRUNC  O_WRONLY\par
         (can be joined by |)\par
        mode: S_IWRITE  S_IREAD   S_IREAD | S_IWRITE\par
    \par
    {\b Returns:}    a handle if successful, or -1 if not.\par
      errno:  EACCES, EEXIST, EMFILE, ENOENT\par
    \par
    {\b See also:}   {\plain Example Program}{\v open.ex},\par
    {\ul Template}{\v open.tp}, access, chmod, close,\par
    creat, dup, dup2, fopen, sopen, umask\par
    }

 For more information, see the online help and Chapter 7 in the
 "Microsoft C Advanced Programming Techniques" manual.


 10. RTF Codes \fi<n> and \li<n> Use Twips Instead of Spaces

 Product Version(s): 1.06   | 1.06
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr
 Last Modified: 31-JAN-1991    ArticleIdent: Q68694

 The Rich Text Format codes \fi<n> and \li<n> used for creating help
 files are incorrectly described in the online help. The online help
 states that the code \fi<n> indents the first line of the paragraph
 <n> spaces, and the code \li<n> indents the entire paragraph <n>
 spaces from the left margin.

 However, the value of <n> is the number of twips and not the number of
 spaces. A twip is 1/20 of a point or 1/1440 of an inch; 180 twips
 approximates one space (that is, \li720 will indent the entire
 paragraph four spaces).

 Page 4 of the "Professional Advisor Library Reference" describes the
 RTF codes \fi and \li but does not mention the <n> parameter to indent
 the paragraphs.

 Page 155 of the "Microsoft C Advanced Programming Techniques" manual
 describes the correct syntax for the RTF codes but does not mention the
 format for <n>.


 11. Help Databases Not Properly Decoded by HELPMAKE.EXE

 Product Version(s): 1.03 1.05 1.06 | 1.03 1.05 1.06
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | buglist1.03 buglist1.05 buglist1.06
 Last Modified:  6-FEB-1991    ArticleIdent: Q68989

 When using HELPMAKE.EXE to decode concatenated help databases, you
 must use the "Decode Split" option (/DS). If a concatenated help
 database is decoded with either "Decode" (/D) or "Decode Unformatted"
 (/DU), HELPMAKE may be caught in an infinite loop that will eventually
 fill the hard disk.

 If OS2.HLP is decoded with

    helpmake /D /Ooutfile OS2.HLP

 HELPMAKE will decompress the first database in OS2.HLP over and over
 until either the disk fills up or you stop the program (with a
 CTRL+BREAK, for instance).

 If OS2.HLP is decoded with

    helpmake /DS OS2.HLP

 it is broken into STRUCT.HLP, MACROS.HLP, and TABLES.HLP. These help
 files can then be decoded properly with the /D or /DU option.

 If you don't know how a help file is assembled, the following are the
 steps to take to decompress it:

 1. Save a backup copy of the help file in case of problems.

 2. Rename the help file to "TEMP.HLP".

 3. Split the file as follows:

       HELPMAKE /DS TEMP.HLP

    If the file is not a concatenated database, you will get a single
    file with the name of the help database as it was originally built
    (the internal database name).

    If the file is a concatenated database, you will get individual
    help files with the internal database names. For OS2.HLP, these are
    STRUCT.HLP, MACROS.HLP, and TABLES.HLP.

 4. Decode the resulting files as follows:

       HELPMAKE /D TEMP1.HLP /OTEMP1.SRC
       HELPMAKE /D TEMP2.HLP /OTEMP2.SRC

 Microsoft has confirmed this to be a problem with HELPMAKE.EXE versions
 1.03, 1.05, and 1.06. We are researching this problem and will post new
 information here as it becomes available.


 12. Always Use Latest Version of HIMEM and Other Memory Utilities

 Product Version(s): 2.50 2.60
 Operating System:   MS-DOS
 Flags: ENDUSER | s_codeview s_himem s_ramdrive s_smartdrv
 Last Modified: 15-JAN-1991    ArticleIdent: Q60830

 The newest versions of the memory management utilities (HIMEM.SYS,
 RAMDRIVE.SYS, and SMARTDRV.SYS) should be used at all times. For
 instance, if you use CodeView Version 3.00 (first shipped with
 Microsoft C Version 6.00) and you use a version of HIMEM.SYS earlier
 than what was shipped with the C 6.00 package, you may experience a
 number of problems, including the following:

 1. You may get spurious error messages such as "Not enough extended
    memory available," even if you have more than enough extended
    memory installed.

 2. You may receive the error "CV1319: CodeView initialization error"
    when trying to invoke CodeView.

 3. Your computer may hang or reboot.

 As memory management technology progresses, the Microsoft tools and
 utilities that use the technology are also updated. Therefore, it is
 critical that the latest versions of the memory utilities (HIMEM.SYS,
 RAMDRIVE.SYS, SMARTDRV.SYS, etc.) be installed. Tools such as CodeView
 and the Programmer's WorkBench (PWB) depend on features that are
 available only in the latest versions.


 13. Using LIB to Combine Two Libraries

 Product Version(s): 3.00 3.04 3.07 3.08 3.10 3.11 3.14 3.17 | 3.11 3.14 3.17
 Operating System:   MS-DOS                                  | OS/2
 Flags: ENDUSER | s_lib
 Last Modified: 15-JAN-1991    ArticleIdent: Q25108

 The Microsoft Library Manager utility (LIB.EXE) can be used to combine
 two libraries into one.

 The following is an example of how to add the contents of LIB1.LIB to
 LIB2.LIB in a single LIB command:

    LIB LIB2.LIB+LIB1.LIB;

 You may also have LIB prompt you for input, in which case the input
 and prompts will appear as follows:

 LIB <RETURN>
 Library name: LIB2.LIB <RETURN>
 Operations: +LIB1.LIB <RETURN>

 Note that the .LIB extension is required; otherwise, LIB will assume
 LIB1 is an object module.


 14. Using EXEHDR or EXEMOD to Change the Stack Size of an .EXE

 Product Version(s): 1.00 2.01 | 1.00 2.01
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_exehdr s_exemod
 Last Modified:  6-FEB-1991    ArticleIdent: Q25321

 The EXEHDR and EXEMOD utilities can be used to change the stack size
 of a program. EXEHDR runs in both DOS and OS/2, while EXEMOD is an
 older utility that only runs under DOS.

 To view the current size of the stack, no options are used. Both
 EXEHDR and EXEMOD will produce a table of information with a line such
 as the following:

    Initial SS:SP 0000:0800 0

 The offset portion of this line gives the current stack size in hex.
 In this example, the stack size is set at 2K. If you wanted to change
 it to 4K, you could use the /STACK option of EXEHDR or EXEMOD in the
 following way:

    EXEHDR file /STACK 1000

 -or-

    EXEMOD file /STACK 1000


 15. Replacing Real Mode Family API Functions in Bound Applications

 Product Version(s): 1.00 1.10 1.30 | 1.00 1.10 1.30
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_bind
 Last Modified: 15-JAN-1991    ArticleIdent: Q39812

 Question:

 How do I create a bound application that uses the system calls in
 protected mode and uses my calls in real mode? The real mode call must
 access global data in my program.

 I would like to bind a program so that it will use the system
 VioGetConfig() function in protected mode, but will use my rewritten
 VioGetConfig() function when run in real mode. Everything compiles and
 links correctly, using either my function or the system function.
 However, my VioGetConfig accesses an initialized global int that is
 declared above the main(), which still compiles and links error free.
 But when I link the main with the system VioGetConfig, then bind the
 .EXE giving it the user's version of VioGetConfig, I get an unresolved
 external on the external global variable from the assembly routine.

 Response:

 The original strategy is probably the best method and should work
 correctly in the general case, that is, in the BIND step, specify the
 user version of VioGetConfig(). The problem is the global int
 variable. BIND does a link of the following:

    API stub loader
    API library modules
    protected-mode image with no symbols

 The key point is that BIND has no access to the internal name space of
 the program. Thus any API routine, including one rewritten by the
 user, cannot see any of the program's data. You should rewrite your
 VioGetConfig() so it does not use the global variable, if possible.
 Otherwise you will have to use one of the methods discussed below.

 Rather than using BIND, do it yourself. In the main program, use code
 such as the following:

     /* Under what operating system we are running ? */

     if (_osmode == DOS_MODE)
     {
         /* We are running under DOS - real mode */

         VioGetConfigUser(); /* User version */
     }
     else
     {
         /* We are running under OS/2 - protected mode */

         VioGetConfig();     /* System version */
     }

 Another way to do this is to build a dual-mode .EXE, as follows:

 1. Build your real-mode program using user VioGetConfig.

 2. Write protected-mode main program using OS/2 VioGetConfig.

 3. In the .DEF file for the protected-mode program, add the following
    statement:

       STUB '<name-of-your-real-mode-app>'

 4. Link your protected-mode application. You will get two programs in one
    .EXE file. In protected mode, the system will load only the
    protected-mode version. In real-mode, the system will load only
    real-mode applications.


 16. Page Size May Cause Big Size Increase When Combining Libraries

 Product Version(s): 3.0x 3.11 3.14 3.17 | 3.11 3.14 3.17
 Operating System:   MS-DOS              | OS/2
 Flags: ENDUSER | s_lib
 Last Modified: 15-JAN-1991    ArticleIdent: Q44896

 Question:

 When I use LIB.EXE to combine my libraries with a third-party library,
 the resultant library is much larger than I expected it to be.

 The following is an example:

     LIB1.LIB    5K   bytes
     LIB2.LIB    250K bytes

     LIB1.LIB + LIB2.LIB  = 305K bytes

 Why is the combined file 50K larger?

 Response:

 This size difference may be the result of different page sizes among
 the libraries being combined. The page size of a library affects the
 alignment of modules stored in the library. When libraries with
 different page sizes are combined, the resultant library uses the
 largest page size from the constituent libraries. Thus, the actual
 increase in file size represents wasted space between modules in the
 library. To reduce the amount of wasted space, you should specify a
 smaller page size for the new library. This may be accomplished by
 using the library manager as follows:

    LIB BIG.LIB /PAGESIZE:16;

 This sets the page size for the library BIG.LIB to 16 bytes.

 As indicated in the library manager documentation, the page size must
 be an integer power of 2 from 16 to 32,768 bytes.


 17. Helpmake Binary Format Is Proprietary

 Product Version(s): 1.00 1.05 1.06 | 1.00 1.05 1.06
 Operating System:   MS-DOS         | OS/2
 Flags: ENDUSER | s_helpmake
 Last Modified: 15-JAN-1991    ArticleIdent: Q48292

 The binary format of the help files produced by the Microsoft Helpmake
 utility is proprietary information, and therefore, not available for
 distribution.


 18. CALLTREE Produces Argument Mismatch with Void Parameter List

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | s_calltree buglist1.00 s_editor
 Last Modified: 15-JAN-1991    ArticleIdent: Q46896

 The CALLTREE utility program included with the Microsoft C version
 5.10 produces the following error message if a void parameter list is
 used for the function foo() and the options -a and -b are specified on
 the command line:

    Argument Mismatch Calling        foo  in  main.c(10)

 Microsoft has confirmed this to be a problem in version 1.00. We are
 researching this problem and will post new information here as it
 becomes available.

 The CALLTREE utility program can be used to produce a tree-like
 structure of function usage. Documentation on the options for CALLTREE
 can be found in the C 5.10 CodeView and Utilities manual in the
 "Microsoft Editor for the MS OS/2 and MS-DOS Operating Systems: User's
 Guide," section on pages 112-114.

 The following program demonstrates the problem:

 void foo(void);   /* prototye contains (void) */

 void main(void)
 {
   foo();     /* function call does not contain (void) */
              /* replace with foo(void); to prevent warning message */
 }

 void foo(void)
 {
   printf("Inside foo\n");
 }

 Invoke CALLTREE by issuing the following command:

 calltree -a -b back.out -w warn.out main.c

 The "warn.out" file will now contain the error message:

    Argument Mismatch Calling        foo  in  main.c(5)


 19. Incorrect Response File Used with LIB Causes U1183 Error

 Product Version(s): 3.1x   | 3.1x
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 30-AUG-1989    ArticleIdent: Q47016

 Question:

 I want to use a response file entitled LIB_OPS with the library
 manager just for specifying my library operations. When I invoke LIB
 with the command

    LIB mylib.lib @lib_ops, mylib.lst;<cr>

 it generates the following error:

    LIB : fatal error U1183 : 'cannot open response file'

 However, when I invoke LIB using the command prompts and supply my
 response file for the Operations prompt as follows, everything works
 correctly:

     .
     .
     Operations: @lib_ops<cr>
     .
     .

 What differentiates the two cases?

 Response:

 Using a response file on the command line of the library manager
 requires that the response filename be delimited correctly. This is
 mandated by the command-line parser, which considers trailing argument
 delimiters such as a comma or semicolon to be part of the response
 filename. Consequently, the parsing of the unknown filename prohibits
 DOS from locating and opening the correct response file. When a
 response file is detected on the LIB command line (via the "@"
 character), the command interpreter parses following characters as the
 filename argument until a DOS delimiter, either a space character or a
 carriage return, is encountered. Hence, LIB commands such as

    LIB @response;<cr>
    LIB mylib.lib @response, mylib.lst;<cr>

 generate the U1183 "cannot open response file" because the file
 "response" is actually parsed as "response;" and "response,",
 respectively, neither of which exist in the current working directory
 or those directories searched for by the DOS APPEND command. However,
 correctly delimiting the end of the response file argument with a
 space or carriage return allows the following LIB commands to work
 correctly:

    LIB @response ;<cr>
    LIB @response<cr>
    LIB mylib.lib @response ,mylib.lst;<cr>

 When operating the library manager with a response file containing
 information for one or more of the LIB arguments, it must be invoked
 in one of the following two ways:

 1. With the response file supplied on the LIB command line and the
    file's final character delimited correctly (by a space or carriage
    return).

 2. With no command line arguments and the response file used as a
    reply to the appropriate LIB command prompt.

 The first method is discussed and illustrated in the information
 above. The second method of using the library manager prompts is
 equally effective. However, when supplying a response file to a LIB
 command prompt, the filename must be delimited correctly as in the
 aforementioned, or the U1183 error occurs. The following example
 demonstrates the generation of this error due to incorrect delimiting
 of the response file:

 LIB<cr>

 Microsoft (R) Library Manager  Version 3.14
 Copyright (C) Microsoft Corp 1983-1988. All rights reserved

 Library name: mylib.lib<cr>

 Operations: @response;<cr>

 LIB : Fatal Error U1183:  Cannot open response file

 Correcting the response file argument to the Operations prompt as
 follows eliminates the problem:

 Operations: @response<cr>

 or

 Operations: @response thisisextrajunkbutwillworkcuzofthe<space>delimiter


 20. LIB Version 3.17 Available for Increased Library Capacity

 Product Version(s): 3.17   | 3.17
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | appnote SS0329.ARC s_lib
 Last Modified: 17-DEC-1990    ArticleIdent: Q66569

 The Microsoft Library Utility (LIB.EXE) version 3.17 is available to
 registered users of Microsoft language products who are experiencing
 difficulty creating libraries with older versions of LIB due to
 capacity limits. If you are the registered owner of a Microsoft
 language product, you may obtain LIB 3.17 as an application note from
 Microsoft Product Support Services by calling (206) 637-7096.

 LIB 3.17 can also be found in the Software/Data Library by searching
 on the keyword SS0329, the Q number of this article, or S12776. SS0329
 was archived using the PKware file-compression utility.

 Older versions of the Microsoft Library Manager are somewhat limited
 as far as the size of a library that can be created or the number of
 modules or symbols that a library can contain. These limits are not
 specific because the actual limits for any particular library are the
 result of a combination of factors including the number of modules,
 the number of symbols, the page size used, and the order in which
 items are added to the library.

 One indication of a library capacity problem is if a previously usable
 library suddenly causes the linker to generate the error message
 "L1101: invalid object module" after some additions to the library.

 Newer versions of LIB, such as version 3.17, have improved capacity
 over the earlier versions. Thus, libraries with a greater number of
 object modules, and/or a greater overall size, should be possible,
 even though the exact limits are still specific to each particular
 library.

 No documentation for the Library Manager is supplied with the
 application note because its usage and commands are identical to
 previous versions. Any questions concerning the usage, command syntax,
 or options for this version can be addressed by referring to existing
 LIB documentation.


 21. "Packed File Corrupt" Error

 Product Version(s): 3.x 4.x
 Operating System:   MS-DOS
 Flags: ENDUSER | s_link s_c h_fortran s_pascal s_quickc h_masm b_basic
 Last Modified: 12-FEB-1991    ArticleIdent: Q58225

 Question:

 When I attempt to run my program, I get the error message "Packed File
 Corrupt." What causes this error and how can I run my program?

 Response:

 The error is caused by a problem in the packed EXE loader that is
 incorporated into EXEPACKed files. This causes incorrect loading of
 packed files. The problem only occurs when the program is loaded into
 memory before the first 64K byte boundary.

 CHKDSK reports more than 589,824 bytes of free memory. Typically, this
 problem tends to occur with DOS Version 3.30 when you try to free up
 more memory by setting the files and buffers in your CONFIG.SYS file
 to less than their default values.

 To correct this problem, force DOS to load the program above the first
 64K of memory by increasing the amount of memory DOS uses. One way to
 do this is to fill up the first 64K segment with one or more copies of
 COMMAND.COM.

 You can also use copies of COMMAND.COM to diagnose the problem. Spawn
 a new command interpreter by typing "COMMAND" at the DOS prompt. Then
 try to run the program. Keep spawning copies of COMMAND.COM until the
 program runs. When the program runs, you have successfully filled the
 first 64K.

 If this method works, you may resolve the problem in a more permanent
 manner by increasing the number of files and buffers in the CONFIG.SYS
 file, and rebooting your machine.

 The EXEPACK utility compresses sequences of identical characters from
 a specified executable file. It also optimizes the relocation table,
 whose entries are used to determine where modules are loaded into
 memory when the program is executed. When the program is executed, it
 must first unpack the file into memory. It is the unpacking code that
 unpacks incorrectly and generates the "Packed File Corrupt" error.

 For more information on the EXEPACK utility, refer to Page 321 in the
 "Microsoft CodeView and Utilities" manual shipped with C version 5.10.
 For information on the /EXEPACK linker option, refer to the utilities
 manual or online help shipped with your particular version of the
 compiler or assembler.
 Additional reference words: b_quickbasic o_msdos h_mouse h_mspbrush


 22. CVPACK May Lose Type Information in Large Files

 Product Version(s): 2.01 3.01 | 2.01 3.01
 Operating System:   MS-DOS    | OS/2
 Flags: ENDUSER | s_cvpack s_codeview
 Last Modified:  5-FEB-1991    ArticleIdent: Q58718

 Certain type information such as that required to expand a structure
 using the "?? <structurename>" command in CodeView can be lost in
 large files when using CVPACK.

 Running CVPACK on very large executables may remove such information
 from the file. Before running CVPACK, internal information can be
 viewed and members can be expanded on structures; after CVPACK, only
 the structure's address is viewable.

 The reason this occurs is that CVPACK is stripping out information
 that CodeView needs to correctly display pointers to far data.

 In this case, CodeView attempts to provide information on the pointers
 to far data in the structure, but the information it gives is not
 correct. Observing the change in the structure's segment address
 before and after using CVPACK shows that this address changes while
 the offset address remains the same. Therefore, the correct
 information cannot be displayed, and CodeView emits a warning beep
 instead of showing the expanded structure elements.


 23. BIND Error "Import By Ordinal Not Defined: DOSCALLS.5"

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_bind
 Last Modified: 27-DEC-1990    ArticleIdent: Q58929

 Question:

 When I use BIND version 1.00 to bind my OS/2 program, the following
 error message is returned:

    Import by ordinal not defined: DOSCALLS.5

 I bind my program with the following:

    BIND hello.exe -o hellob.exe

 Why do I get that error when I call FAPI functions by name and not
 their ordinal numbers?

 Response:

 The above error occurs because DOSCALLS.LIB must be listed on the BIND
 command line. Bind automatically searches for API.LIB and OS2.LIB
 (using the LIB environment variable), but not DOSCALLS.LIB.

 When using bind, DOSCALLS.LIB must be explicitly listed on the command
 line and the LIB environment variable must point to API.LIB and
 OS2.LIB. For example:

    BIND hello.exe c:\c510\lib\doscalls.lib -o hellob.exe


 24. LIB.EXE Failure When Trying to Build Large Libraries

 Product Version(s): 3.11   | 3.11
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_lib appnote
 Last Modified: 17-DEC-1990    ArticleIdent: Q59892

 When using versions of the Microsoft Library Manager (LIB.EXE) earlier
 than Version 3.14 to try to build large libraries with many symbols
 and modules, the LIB program may fail due to capacity limits.

 If you encounter various failures or random errors when trying to
 build a large library (for example, the Greenleaf Libraries), you
 should contact Microsoft Product Support at (206) 637-7096 to obtain a
 more recent version of LIB.EXE.

 LIB.EXE is shipped with all Microsoft language products for building
 and maintaining run-time libraries. Earlier versions of LIB run into
 problems when the library size approaches 200K or larger, but the
 point at which LIB may fail varies widely. LIB capacity is
 unpredictable because it is affected by such items as the number of
 symbols, the number of modules, and the length of symbol names.

 Sometimes, just changing the order in which modules are added to a
 large library will resolve the problem (or at least alter the point of
 failure or the particular errors generated). Some of the errors
 reported from capacity failures are U1174, U1188, and U1189.

 Errors such as U1174 and U1189 are documented only as being problems
 for which you should contact Microsoft Product Support. In general,
 these errors indicate major LIB capacity overflow problems and the
 best workaround is to update to a newer version of LIB.EXE.


 25. Bound Program Works Under OS/2, but Hangs Under DOS

 Product Version(s): 1.10   | 1.10
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_bind h_fortran s_link
 Last Modified: 15-JAN-1991    ArticleIdent: Q61469

 If you use BIND version 1.10 and the OS/2 Linker/2 Version 1.20, the
 program will bind error-free and will run correctly under OS/2, but
 will hang the machine if run under DOS.

 BIND version 1.10 creates an executable that hangs under DOS but runs
 correctly in OS/2 if the program is linked with the OS/2 linker
 version 1.20. Using BIND 1.10 with LINK version 5.03 resolves this
 problem, and using BIND 1.20 or later with the OS/2 linker also
 creates a valid executable for DOS and OS/2.


 26. Using /help Option with RM.EXE Displays EXP.EXE Online Help

 Product Version(s): 1.01   | 1.01
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_rm s_pwb s_editor docerr
 Last Modified: 17-DEC-1990    ArticleIdent: Q61967

 The utility program RM.EXE version 1.01 displays the wrong help screen
 when invoked with the /help option. The /help parameter is designed to
 invoke the Quick Help (QH) utility in order to display the online help
 for RM.EXE. Because the wrong utility name was written into the RM.EXE
 file, the help screen displayed for RM with /help is the help
 information for the EXP utility.

 This error is due to a problem in the RM.EXE file, rather than being a
 problem in the help files; thus there is no easy way to correct this
 problem. To access the correct help information for RM, one of the
 following methods may be used:

 1. Invoke Quick Help directly. Use RM as the parameter to indicate RM
    as the item on which to find help (for example, type QH RM at the
    DOS or OS/2 prompt).

 2. Invoke RM with the /help option (for example, type RM /help at the
    prompt) and when the EXP help screen appears, page down to the
    bottom where there is a link labeled "RM Command." Select this link
    and the RM help screen will be displayed.

 3. Help on RM can be accessed from within the Programmer's WorkBench
    (PWB) by selecting "Miscellaneous" on the main Help Contents screen
    (in the box titled Microsoft Utilities), and then selecting "RM
    Command" from the submenu.


 27. Helpmake Version 1.05 May Not Decode All Formatting

 Product Version(s): 1.05   | 1.05
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_helpmake buglist1.05 fixlist1.06
 Last Modified: 23-JAN-1991    ArticleIdent: Q64792

 HELPMAKE version 1.05 (shipped with Microsoft C version 6.00) does not
 decode all formatting information in help files decoded with the /D
 option. HELPMAKE version 1.03 (shipped with the OS/2 1.20 SDK) works
 as expected.

 This lack of decoding will result in no bold, green, italic, or
 underline formatting in help files that are compressed again with
 HELPMAKE.

 Microsoft has confirmed this to be a problem in HELPMAKE version 1.05.
 This problem was corrected in HELPMAKE version 1.06. HELPMAKE 1.06 was
 shipped with the Microsoft Advisor Library.

 Example
 -------

 The "\i" and "\p" options are not decoded in the sample below. This
 excerpt is from PWB 1.00 version of the PWB.HLP file.

 Note: Nonprintable characters are removed from these examples.

 From HELPMAKE version 1.03:

    +------- Browse Menu ---------+
    | \i\a\pGoto Definition...\v@L8001\v\i\p | Finds definition of symbol

 From HELPMAKE version 1.05:

    +------- Browse Menu ---------+
    | \aGoto Definition...\v@L8001\v | Finds definition of symbol


 28. QuickHelp Duplicate Search Brings Up Wrong Help

 Product Version(s): 1.70   | 1.70
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh buglist1.70 SDK
 Last Modified: 17-DEC-1990    ArticleIdent: Q67234

 In QuickHelp, if you select Duplicate Search from the View menu and
 enter a search string containing a wildcard, all the topics that match
 that string should appear. In some cases, however, all of the
 occurrences are NOT displayed, which causes the help topics to be out
 of sync with the information they bring up. When this problem occurs,
 you may select a topic, and help on a different topic will be
 displayed.

 One example of this problem occurs when searching on _dos* with the
 CLANG.HLP help file that comes with Microsoft C version 6.00. Another
 example is found when searching for wm_* in the SDKADV.HLP help file
 that comes with the Windows 3.00 Software Development Kit. In both
 cases, if you go to the end of the list of topics and bring up the
 information, the wrong help will be displayed.

 Microsoft has confirmed this to be a problem in QuickHelp version
 1.70. We are researching this problem and will post new information
 here as it becomes available.


 29. Hyperlink for MakeProcInstance in SDKADV.HLP Incorrect

 Product Version(s): 1.70   | 1.70
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | s_qh docerr
 Last Modified: 17-DEC-1990    ArticleIdent: Q67397

 When accessing the function MakeProcInstance() from the index in
 QuickHelp version 1.70, the help screen for Windows DataTypes is
 presented instead. This behavior may be duplicated by following the
 procedure outlined below:

 Start QuickHelp with an argument to get help on any windows topic, as
 follows:

    qh wndclass

 This will bring up the help screen for the wndclass structure. Now
 click the right button on the QuickHelp index, and then on the
 alphabetical section for M. At this point, if help for
 MakeProcInstance() is chosen, QuickHelp will, instead, bring up the
 help screen for Windows Data Types.

 If the SDKADV.HLP file is decoded using HELPMAKE, as follows

    helpmake /D /Osdk.doc sdkadv.hlp

 it becomes obvious that the reason for this error is that the
 hyperlink for MakeProcInstance() appears as follows in the decoded
 help file:

    \aMakeProcInstance function \vDatatypes\v

 This causes QuickHelp to display the DataTypes help screen instead of
 help for the appropriate function.

 This problem can be corrected by changing the above line to read as
 follows:

    \aMakeProcInstance function \vMakeProcInstance\v

 The SDKADV.HLP file must then be recompressed, as follows:

    helpmake /E0 /T /Osdkadv.hlp sdk.doc

 The choice of /E0 indicates no compression, and is strictly arbitrary
 in this case. If maximum compression is desired, the 0 argument to the
 /E switch may be left off, or /E15 may be specified.


 30. The Syntax for STACK Is Incorrect in EXEHDR Usage Statement

 Product Version(s): 2.01   | 2.01
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | docerr s_exehdr
 Last Modified: 17-DEC-1990    ArticleIdent: Q67793

 When the /? parameter is used for EXEHDR, a listing is displayed
 detailing the various switches accepted by EXEHDR. This list
 incorrectly indicates that the /STACK switch must be followed by a
 hexadecimal number between 0h and ffffh. In reality, the /STACK switch
 must be followed by either a decimal number between 0 and 65535 or a
 hexadecimal number using C notation (0x0 - 0xffff).

 If any other format is used, EXEHDR will return the following error
 messages:

    EXEHDR: error U1110: malformed number xxxx
    EXEHDR: error U1115: option /STACK:xxxx ignored






 Microsoft Mouse
 =============================================================================


 1. Availability of MENU.COM

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-NOV-1988    ArticleIdent: Q28420

 I have obtained a file with the .MNU extension for a third party
 application that requires a file from Microsoft called MENU.COM.

 If you have a mouse with driver Version 6.14, the MENU.COM file will
 be on your Mouse Setup Disk.

 If you have a version between Version 6.00 and Version 6.14, call
 Microsoft Product Support (206) 454-2030 about obtaining MENU.COM.

 If you have a version prior to Version 6.00, you will have the file on
 your System Disk.


 2. Network and Mouse Conflicts

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-DEC-1988    ArticleIdent: Q28421

 The bus mouse is interrupt selectable using the J4 jumper block
 located on the INPORT interface card. Make sure the netcard is not
 using the same interrupt; if your network card is using the same
 interrupt, it will crash when the mouse driver installs.

 The bus mouse uses its own I/O address (23c-23f). On the current
 interface cards this can be changed to the lower four bytes by
 selecting secondary INPORT (address 238-23b) over PRIMARY on the J3
 jumper setting. (note: moving the card to another slot may in
 addition solve the problem).

 If the above does not solve the problem or if you have the serial
 mouse, change the driver loading order or disable the driver (mouse
 off) when using the network.

 Contact the manufacturers of your netcard to see if they know of the
 above problem.


 3. IRQ Settings and Mouse Installation

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q12230

 The jumper on the bus mouse should be checked before the card is
 installed in any computer, especially if the card is moved from one
 machine to another. The board's jumper controls which interrupt
 request (IRQ) line is used. IRQ lines are used to facilitate
 information transfer from such I/O devices as disk controllers and
 serial ports. The jumper avoids IRQ conflicts with other devices
 already installed in the computer. Under each pair of pins on the card
 is a number between 2 and 5 (inclusive). The jumper selects the IRQ
 line. Microsoft ships the boards with the jumper set to IRQ 2, for
 installation in a typical IBM PC or PC XT. Because IBM changed the IRQ
 architecture in the PC AT by using using IRQ 2 for the second IRQ
 controller, the bus mouse jumper is usually set to IRQ 5 on an AT.

 While these jumper settings are correct for most installations, you
 should verify which (if any) IRQ lines are being used by every device
 already installed in the machine. There can be only one active device
 per IRQ line. Refer to the technical manuals for each manufacturer's
 product or contact the manufacturer directly for this information. The
 following is an IRQ allocation table as defined in the IBM PC and AT
 technical reference manuals (other manufacturers' software, hardware
 and add-on boards must follow this convention in order to be IBM
 compatible):

                                         PC-AT
 IRQ Line        PC, PC-XT       CTLR 1          CTLR 2

     0             Timer         Timer     | IRQ8  Clock
     1            Keyboard      Keyboard   | IRQ9  Redirected IRQ2
     2            Reserved       CTLR 2 <--| IRQ10 Reserved
     3              COM2          COM2     | IRQ11 Reserved
     4              COM1          COM1     | IRQ12 Reserved
     5           Hard disk        LPT2     | IRQ13 Coprocessor
     6          Floppy disk   Floppy disk  | IRQ14 Hard disk
     7             LPT1-3         LPT1     | IRQ15 Reserved

 Because the mouse can be jumpered in the IRQ range of 2 through 5 and
 there can be only one active device per IRQ line, the bus mouse can be
 installed only if at least one of these lines is free.

 For example, a bus mouse is to be installed in an IBM PC-AT with an
 IBM PC-AT Serial/Parallel Adapter configured as COM1 and LPT1,
 respectively; a Color Graphics Adapter; and a multi-function card with
 128K of memory and a serial port configured as COM2. On this computer,
 there is only one IRQ line still available on IRQ controller 1: IRQ 5.
 IRQ 2 is used by the AT's second IRQ controller and IRQ lines 4 and 3
 are used by COM1 and COM2. The CGA does not use an IRQ line and the
 parallel port uses IRQ 7, which falls outside of the mouse's range.
 The bus mouse should be jumpered for IRQ 5, thereby using the last IRQ
 line in the normal IRQ range of 0 through 7 of the first IRQ controller.
 The user of this computer should be aware of this for future
 expansion.

 The Enhanced Graphics Adapter (EGA) is now becoming a popular display
 card for PCs and XTs. The EGA includes a hardware feature that allows
 software to enable interrupts on IRQ2 to indicate the start of
 vertical retrace. Therefore, if an EGA and bus mouse are installed in
 a PC or XT, IRQ2 is no longer available for the mouse. In a full XT
 with a hard disk, two serial ports, an EGA, and a bus mouse, there
 will be an IRQ line overlap between two devices. Therefore, one device
 will have to be sacrificed to free up an IRQ line for the bus mouse.
 This is not a design deficiency of the bus mouse; it is a fundamental
 design restriction in the PCs and XTs.

 As discussed above, there are only eight IRQ lines in the PC and XT,
 of which four are used up by the motherboard and other standard
 equipment. The other four lines go quickly. Almost all expansion cards
 require that a free IRQ line be available, such as the following:

 1. Network cards
 2. Bisync communication cards
 3. Tape back-up units
 4. Some clock/calendar hardware
 5. Serial communication cards
 6. EGAs
 7. Emulation boards
 8. Hard disk controllers

 There are more desirable devices to install in a machine than IRQ
 lines to handle them. To help relieve the crowding of IRQ lines, the
 IBM AT includes a second IRQ controller with seven more lines.
 Currently, hardware is evolving to take advantage of the new AT
 architecture.

 Once the hardware is installed, the software must be loaded. When the
 mouse driver loads, using either MOUSE.SYS from CONFIG.SYS or
 MOUSE.COM from a batch file or the keyboard, the file will be loaded
 into memory and the driver will then install itself. This installation
 requires a few seconds. Various operations are undertaken, including
 mouse hardware initialization. This is the primary reason for the
 delay before the mouse installation message appears.

 If the error message "MOUSE: Microsoft mouse not found!" appears,
 there can be a number of hardware-related causes, such as a broken
 mouse; however, the problem more likely is an IRQ contention problem
 either between the mouse and another device or between the serial
 ports.

 Typical bus mouse related problems are between the mouse and the hard
 disk controller, i.e., bus mouse jumpered on IRQ 5 in an XT or IRQ 2
 in an AT. The common symptom for this problem is the inability to
 perform a warm boot (CTRL+ALT+DEL). If the bus mouse is jumpered on
 the same line as a serial port, network card, or emulator card,
 irregular and unreproducible system crashes can occur. In Windows,
 with a bus mouse doubled up on the IRQ line used by a modem, the mouse
 will "go away" when communications software is run.

 The standard isolation procedure is to verify IRQ-line usage and if no
 problems are uncovered, the next step is to remove as much hardware as
 possible. In this way, the conflict should be uncovered between
 particular devices and a resolution of the problem will follow.


 4. Bus Mouse and Cipher Tape Drive Card

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q46793

 Problem:

 When using the Microsoft Bus Mouse in an AST Premium 386/25, I got the
 following error message after I installed a Cipher Tape drive card:

    Bad or missing interrupt jumper

 Response:

 This problem occurred because the interrupt and primary/secondary
 jumper settings were wrong. To correct this problem, change J4 to
 interrupt 2, and J3 to secondary inport.


 5. Types Of Mice Available: Serial, Bus, and InPort

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q28738

    Version 1.00 of the new white-button mouse is available in three
 varieties; there are no noticeable differences in function or speed.
 The type of mouse you want depends on the available resources of your
 system.
    The PS/2 Serial mouse will work in any IBM PS/2 mouse port or in
 any standard IBM 9- or 25-pin serial port. The PS/2 Serial mouse is
 recommended if you own an IBM PS/2 machine or have an available COM1:
 or COM2: serial port on your system.
    The Bus mouse has its own interface card, which includes the
 Microsoft InPort interface. It can be used with any IBM PC, XT, AT, or
 PS/2 model 25/30 with an available 8- or 16-bit slot. The Bus mouse is
 interrupt selectable (2 through 5), and frequently saves your serial
 ports for other uses.
    The InPort mouse is the same as the Bus mouse except that it does
 not come with a Microsoft InPort interface-equipped interface card.
 You must have the Microsoft InPort interface within your system (e.g.
 the MACH 20 has built-in InPort technology).


 6. Programming the Mouse Driver Versus Writing One

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-NOV-1988    ArticleIdent: Q28739

 If you plan to write an application with built-in mouse support,
 obtain the "Microsoft Mouse Programmer's Reference Guide." The manual
 includes a mouse library (for the Microsoft Compilers) and
 documentation on programming the mouse driver.

 Microsoft recommends that you program the mouse driver, rather than
 write your own mouse driver. This will maintain compatibility over any
 changes in future mouse hardware.

 If you need to write your own mouse driver, you can obtain the InPort
 Application Note (which is used with the Bus mouse) by calling
 Microsoft Product Support Services at (206) 454-2030.

 The Serial mouse protocol may be obtained by writing a formal request
 to our Mouse Product Manager (or contacting our Mouse ISV department),
 giving supported reasons for bypassing our mouse driver.


 7. Obtaining Hosiden Connectors Used with the Bus Mouse

 Product Version(s): 6.0 6.02 6.10 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28740

    The Hosiden connectors and sockets, which are used with the Bus
 Mouse with InPort hardware, can be obtained from HB Associates at
 1-800-423-3014.


 8. How to Deallocate or Disable the Mouse Driver

 Product Version(s): 6.0 6.02 6.10 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28741

    If the MOUSE.COM driver is installed, the Mouse Off command will
 deallocate the driver from memory if there were no other
 memory-resident programs loaded after it.
    If the MOUSE.SYS driver was installed, the Mouse Off command will
 only disable the driver and not deallocate.
    Although the mouse driver is deallocated or disabled, the mouse
 hardware will continue to send interrupts.



 9. Keyboard Styles for IBM and IBM Compatibles

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER | non-numeric
 Last Modified: 31-AUG-1989    ArticleIdent: Q46918

 Use of the Microsoft Mouse menus is sometimes affected by the style of
 computer keyboard being used. The following are some major versions
 the IBM and IBM-compatible keyboard:

 1. The "standard" keyboard came with the original IBM PC. This
    keyboard includes a numeric keypad on the right-hand side and 10
    function keys across the top of the keyboard.

 2. The "extended" keyboard adds the F11 and F12 function keys to the
    standard keyboard.

 3. The "expanded" keyboard widens the standard keyboard and reproduces
    the nonnumeric keys and the cursor keys in the additional space.


 10. Leading Edge Model D Error "Unexpected SW Interrupt 33"

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q29466

    The error message "Unexpected SW Interrupt 33" can occur on some
 Leading Edge Model D computers when installing a mouse driver.
    You usually can continue after this error message has appeared by
 typing C to continue. For a patch, call Leading Edge technical support
 at (617) 821-4300.


 11. Serial Mouse: "Driver Not Installed--Mouse Not Found" Message

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-APR-1988    ArticleIdent: Q29201

    A "Driver not installed--Mouse not found" error message usually
 pertains to a possible hardware problem.
    When isolating the source of the problem, first boot from a
 "vanilla" DOS (i.e., no AUTOEXEC.BAT or CONFIG.SYS files), then
 install the mouse driver manually from the Mouse Setup Disk.
    If the error remains, check your hardware set up for possible
 hardware conflicts or incorrect serial port configuration before
 determining if you have a possible faulty mouse.
     Your serial ports must follow an IBM standard and be configured as
 follows:

 COM1 using IRQ4 and configured as DTE (data terminal equipment).
 COM2 using IRQ3 and configured as DTE (data terminal equipment).

    The serial mouse does not work on serial ports configured as COM3
 or COM4. If you have only one serial port and it is configured as
 COM2, the mouse driver usually installs but does not work. Configure
 the port as COM1.
    If you have checked your configuration and the mouse driver does
 not install, checking the mouse on two machines is a good isolation
 test.


 12. Mouse Driver Installs but Mouse Does Not Work

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q29202

    If the mouse driver is installed, but the mouse does not work, the
 problem may be due to one of the following problems:

    1. A hardware conflict
    2. A software conflict
    3. A faulty mouse

    If you have a serial mouse, make sure that your serial ports are
 correctly configured.
    To rule out a software conflict, boot from a "vanilla" DOS (i.e.,
 no AUTOEXEC.BAT or CONFIG.SYS files) and manually install the mouse
 driver from the Mouse Setup disk by typing Mouse.
    Problems can occur if the mouse driver is installed on a device
 other than the mouse. This is true in cases where a noisy bus causes
 the driver to install for a bus mouse, or a device such as a modem
 causes the driver to think a serial mouse is being used.
    If you suspect the driver is not installing on the correct port,
 use the mouse switches to direct the driver to the specific port.
    For example, if your mouse is on COM2, load the mouse driver with
 the following command:

    MOUSE /C2  <- install driver on COM2

    If you have a bus mouse, check the jumper settings for a possible
 interrupt conflict, an I/O address conflict, or expansion slot problems.
   If the problems continue, isolate the problem on another machine
 before determining if you have a faulty mouse.


 13. Serial Mouse Pin-Outs

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q29204

    The serial mouse includes a 9- and 25-pin adapter cable to work with
 a standard 9- or 25-pin IBM serial port. The following are the pin-outs
 of the mouse cables:

                   Connectors

    Function    9 pin      25 pin

    RXD         pin 2      pin 3

    TXD         pin 3      pin 2

    RTS         pin 7      pin 4

    GND         pin 5      pin 7

    DTR         pin 4      pin 20

    The serial mouse is a data communication equipment (DCE) device,
 and is a female device (i.e., it has holes in its connectors). Because
 it is a DCE device, the port's functions should be one to one when
 making a cable for a nonstandard serial port.
    For example, the mouse's RXD should connect to your serial port's
 RXD and the mouse's TXD should connect to the serial port's TXD. This
 is true for other functions as well.


 14. Bus Mouse May Not Work on IRQ 2 on a 386 with OS/2

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-SEP-1988    ArticleIdent: Q29279

 The OS/2 mouse driver MOUSEA04.SYS will not install if you use the IRQ
 2 setting for OS/2 and a Wyse 386. MOUSEA03.SYS will install, but
 will not work in OS/2. The mouse works properly in DOS.

 OS/2 seems to be more sensitive to the IRQ usage. This problem occurs
 with both the old and new bus mice. To work around the problem, use
 another interrupt other than 2 on the 386.

 Although IRQ2 is not recommended for ATs or 386s, the mouse seems to
 work without any problems in the DOS environment (using all other
 interrupts); however, this does not seem to be the case in OS/2.


 15. Serial Mouse May Fail with an Older AT&T 6300

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  1-AUG-1988    ArticleIdent: Q28681

    There have been some reports that the mouse driver may not install
 correctly with a serial mouse connected to an older AT&T 6300. Using
 the "/C1" or "/C2" switch often solves the problem. If the problem
 continues, check the ROM date and upgrade the ROM if you are using an
 older one. AT&T recommends Version 1.43 ROM or later. Contact AT&T at
 (800) 222-7278 for ROM upgrade costs.


 16. Mouse EGA Register Interface

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-NOV-1988    ArticleIdent: Q29467

 An application note concerning the Mouse EGA Register Interface can be
 obtained by contacting the Microsoft Product Support Services Hardware
 Group at (206) 454-2030.

 The Microsoft Mouse EGA Register Interface is a library of nine
 functions. It can be called from assembly language programs or high
 level languages, such as FORTRAN, Pascal, C, and compiled BASIC. Its
 functions allow you to do the following:

 1. Read and write to one or more of the EGA write-only registers.

 2. Define default values for the EGA write-only registers or reset the
    registers to these default values.

 3. Confirm that the EGA Register Interface is present and if so,
    return its version number.

 If your program tries to set the EGA registers directly, rather than
 through the interface, the mouse cursor will draw incorrectly.


 17. No IBM DW4 or TopView Support for Bus Mouse with InPort

 Product Version(s): 6.00 6.02 6.10 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28682

 Problem:
    IBM DisplayWrite 4 does not recognize the Bus mouse with Microsoft
 InPort Device Interface. DisplayWrite 4 supports the serial mouse and
 older Bus mouse (with a 8255 chip), but does not have an upgraded
 mouse driver for the InPort interface Bus mouse.
    This problem also occurs with IBM TopView.

 Response:
    Because DisplayWrite 4 has custom-made pointing device drivers, you
 should contact your IBM dealer or have the IBM dealer contact
 IBM dealer support.



 18. Mouse Compatibility with IBM PCjr

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-SEP-1988    ArticleIdent: Q29469

 The Microsoft Mouse has not been tested with the IBM PCjr. Microsoft's
 PCjr Booster, which was discontinued, was the only official hardware
 that included mouse support (i.e., bus mouse hardware).

 We have received customer reports stating that gray-button serial mice
 work properly on the PCjr if a special serial adapter is obtained to
 make the PCjr serial I/O compatible.

 We have not confirmed that Microsoft's new white-button mouse will
 work properly with the PCjr using the special adapter.

 Solid Rock was a company that provided PCjr accessories, but it has
 since gone out of business.


 19. Mouse MREADME.DOC: Single Drive PCs

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-JUN-1988    ArticleIdent: Q29702

    If you have a single-drive PC without a hard disk, you will not be
 able to use the Mouse Setup program (MSETUP) to set up the mouse
 software.
    MSETUP installs the mouse driver, MOUSE.COM.
    On a single-drive PC, you must install the mouse driver yourself in
 one of the following two ways:

    Manual Installation:      Copy MOUSE.COM onto the disk you use to
                              start your computer. You can then load
                              the mouse driver manually each time you
                              start your system, by typing "MOUSE" at
                              the DOS prompt.

    Automatic Installation:   With MOUSE.COM on the disk you use to
                              start your computer, you can modify your
                              AUTOEXEC.BAT file so that the mouse
                              driver is automatically loaded each time
                              you start your system. Add the line
                              "MOUSE" to the AUTOEXEC.BAT file to
                              automatically load MOUSE.COM when you
                              start your computer.

    For more information on this subject, see the "What the MSETUP
 Program Does" section of the "Microsoft Mouse User's Guide."


 20. Some ASCII Control Characters Incorrect in Programmer's Manual

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | mouse menu
 Last Modified: 31-AUG-1989    ArticleIdent: Q46923

 A documentation error on Page 2-24 of "Microsoft Mouse Programmer's
 Reference Guide" incorrectly states that ASCII value 28 corresponds to
 CTRL+\, not CTRL-. This error was corrected in "Microsoft Mouse
 Programmer's Reference" from Microsoft Press.

 Control characters CTRL+H, CTRL+I, CTRL+J, CTRL+M, and CTRL+[ are not
 listed in the table on Page 2-24 because their ASCII values are the
 same as ASCII codes for backspace, horizontal tab, linefeed, carriage
 return, and escape, respectively.


 21. Mouse MREADME.DOC: Invoking the Control Panel in Word

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q29703

 Microsoft Word recognizes the CTRL+LEFT mouse button and SHIFT+LEFT
 mouse-button key combinations as Word operations.

 To invoke the Control Panel while working in Word, do the following:

 1. Hold down the CTRL key.
 2. Press the ALT or SHIFT keys before pressing the left mouse button.


 22. Mouse Driver Command Line Switches

 Product Version(s): 6.00 6.02 6.10 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28684

    The following are command-line switches for mouse driver 6.00 and above:

    SWITCH       DESCRIPTION

    /B           Look for Bus or InPort mouse at primary address
    /I1          InPort mouse at primary address
    /I2          InPort mouse at secondary address
    /C1          Serial mouse on COM1
    /C2          Serial mouse on COM2
    /S <nnn>     Horizontal and vertical sensitivity <nnn> = 0 to 100
    /H <nnn>     Horizontal sensitivity
    /V <nnn>     Vertical sensitivity
    /R0          InPort interupt rate disabled
    /R1          InPort interupt rate 30Hz (default)
    /R2          InPort interupt rate 50Hz
    /R3          InPort interupt rate 100Hz
    /R4          InPort interupt rate 200Hz

    Example: mouse /s75    <- sets mouse sensitivity to 75 (50 default)



 23. Driver "Removed from Memory" Versus "Disabled"

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q47138

 MOUSE.COM Versions 6.00 and later are removed from memory unless
 connected to a PS/2 mouse port. The message "Existing Mouse Driver
 Disabled" appears if the mouse is connected to a PS/2 mouse port or if
 other terminate-and-stay-resident programs (TSRs) prevent the mouse
 from being removed from memory.

 Earlier versions of the mouse driver do not deallocate.

 Versions 6.11 and 6.12 are the only versions that are removed from
 memory if connected to the PS/2 mouse port.


 24. MREADME.DOC: Using the Default Expert Mouse Menu

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q29705

    The default Expert Mouse menu allows you to use a mouse to emulate
 keys, such as the ESCAPE, ENTER, and cursor keys, with applications
 that normally do not support mice.

    To use this menu, load it into memory before you start your
 application.
    To load the default menu, type the following after the prompt of
 the drive or directory where the DEFAULT.COM file resides:

    default

    Once the default menu is loaded, you can perform the mouse actions
 described in the following tables to emulate certain keys in your
 application:

                  Press                     To Emulate

                  The left mouse button     The F3 key
                  The right mouse button    A carriage return (the ENTER key)
                  Both mouse buttons        The ESCAPE key

                  Move                      To emulate

                  The mouse to the left     The LEFT ARROW key
                  The mouse to the right    The RIGHT ARROW key
                  The mouse up              The UP ARROW key
                  The mouse down            The DOWN ARROW key

    To remove the default menu from memory, type the following after
 the prompt of the drive or directory where the DEFAULT.COM file
 resides:

                  default off



 25. Supplemental Mouse Menus Disk (Expert and Basic Menus)

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-JUL-1989    ArticleIdent: Q35131

 The following Microsoft Mouse menus are available by contacting the
 Microsoft Information Center by calling (800) 426-9400 and requesting
 the Mouse Supplemental Menus disk:

    Filename                 Application
    --------                 -----------

    MSMENU.COM               Most text-based software
    MSDB3.COM                dBASE III PLUS
    MS123.COM                Lotus 1-2-3, Versions 1A and later
    MSSYM.COM                Lotus Symphony, Versions 1.20 and 2.00
    MSMM2.COM                MultiMate Advantage II
    MSPF.COM                 PFS: Professional File, Version 2.00
    MSPLAN.COM               PFS: Professional Plan, Version 1.00
    MSPW1.COM                PFS: Professional Write, Version 1.00
    MSPW2.COM                PFS: Professional Write, Version 2.00
    MSSC4.COM                SuperCalc 4, Version 1.00
    MSWP4.COM                WordPerfect, Version 4.20
    MSWP5.COM                WordPerfect, Version 5.00
    MSWS.COM                 WordStar, Versions 3.30 and 4.00
    MSWS5.COM                WordStar, Version 5.00

 In addition, you will receive an Expert Mouse Menus disk with the
 following menus:

    Filename                  Application

    MS123-1.COM               Lotus 1-2-3 Version 1A
    MS123-2.COM               Lotus 1-2-3 Version 2
    MSDW.COM                  DisplayWrite 3 Version 1.10
    MSMM.COM                  MultiMate Version 3.31

 The expert menus have more functionality than the basic menus. The
 menus are sold for a small fee.


 26. Ventura Publisher 2.0 and Mouse Driver 6.24b

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-JUL-1990    ArticleIdent: Q63224

 When mouse driver version 6.24b for the Microsoft Mouse is installed,
 Ventura Publisher version 2.0 is limited to black and white regardless
 of the screen colors selected.

 To correct this behavior, replace mouse driver 6.24b with mouse driver
 7.04.



 27. Mouse Versions Prior to New Mouse 1.00 Used MOUSE.SYS

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-SEP-1988    ArticleIdent: Q35082

 Although there is no difference in functionality between the MOUSE.SYS
 and MOUSE.COM drivers, versions prior to the new white-button Version
 1.00 mice used MOUSE.SYS loaded from the CONFIG.SYS rather than the
 MOUSE.COM used via the AUTOEXEC.BAT file.

 The MOUSE.COM driver provides greater flexibility in that it is able
 to deallocate from memory and is executable from DOS.


 28. Mouse Menu May Have Up to 32 Menus

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q29882

    There are 32 Menu statements allowed for each Mouse Menu. A
 combination of Popup and Menu statements can exceed 32.


 29. 123.MNU Worked on Floppy But Not on Hard Drive

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q31045

 The Lotus 1-2-3 menu that was included with the original mouse (Word
 2.00 bundle) will not work if Lotus 1-2-3 was loaded from the hard
 disk and you have the bus mouse set for interrupt 5 on your IBM PC.
 The menu runs properly from a floppy.

 Change the interrupt setting to 2 on the bus card to resolve this
 problem.


 30. Windows Versions 1.01 and 1.02 and the Bus Mouse

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR59473
 Last Modified:  4-NOV-1988    ArticleIdent: Q19915

 Windows Versions 1.01 and 1.02 will hang or will not recognize bus
 mouse Version 5.03 (InPort hardware) or later.

 Windows Versions 1.01 and 1.02 contain an initial release of
 MOUSE.DRV. Beginning with Version 5.03 of the bus mouse, new InPort
 hardware was incorporated in the bus mouse design. An update to the
 MOUSE.DRV software is required for Windows to correctly recognize the
 mouse.

 The updated MOUSE.DRV is included in Windows Version 1.03 and later.
 In addition, it is included in the mouse Version 5.03 System disk and
 the current mouse Version 1.00 Setup disk.

 If you have Version 6.x of the mouse, you can obtain the updated
 MOUSE.DRV by calling Microsoft Product Support hardware group at (206)
 454-2030 and requesting for the "Mouse Drivers Update Disk."

 The above problem may also affect ISVs and OEMs that have developed
 stand-alone Windows applications or have licensed and adapted Windows
 using the initial Windows development software.


 31. Mouse-Cursor State and EGA Memory

 Product Version(s): 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-JUN-1988    ArticleIdent: Q31149

    The Microsoft Mouse driver EGA interface maintains the mouse-cursor
 state in the unused 8K of video memory available at the top of the
 four 64K buffers that comprise the 256K of total video memory
 available on a loaded EGA adapter. Normally this is of little
 consequence in programming such systems; however, if you resize the
 video buffer by reprogramming the CRT Controller's Offset register,
 problems may occur.
    You will know there is a problem if garbage appears on the display
 after panning through an enlarged virtual screen.
    To work around this problem, do not use Mouse Function 1 to show
 the mouse cursor. Instead, use an alternative method of monitoring the
 mouse's screen location (e.g. XOR some graphical object to the
 screen).


 32. CPANEL May Crash if /S Switch Used Previously

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35229

 If a value such as /s33 is passed to the mouse driver before invoking
 CPANEL, CPANEL may crash if you keep decrementing while in the CPANEL
 screen. The CPANEL will not be invoked and a divide overflow may
 occur, but the mouse driver remains intact.


 33. Using Mouse Menus with WordPerfect Version 5.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 28-JUN-1988    ArticleIdent: Q31293

    When using a Mouse menu with WordPerfect Version 5.00, the menu
 opens; however, no text appears at the current cursor location when a
 selection is made. Upon exiting WordPerfect, the characters from the
 menu appear at the DOS command prompt.
    WordPerfect Version 5.00 has keyboard macros that disable the Mouse
 menu while in WordPerfect. To use a Mouse menu with WordPerfect
 Version 5.00, you must start WordPerfect with the /nk switch. This
 will disable the keyboard macros and allow the Mouse menu to function
 normally.


 34. Mouse Driver Conflict with Fixed-Disk Organizer

 Product Version(s): 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-JUL-1988    ArticleIdent: Q31330

    The mouse driver may not install due to a possible conflict between
 the Microsoft Mouse driver and the IBM fixed-disk organizer (FDO).
    This problem can be avoided by altering the load order of the two
 programs. If the mouse driver is loading first and being destroyed by
 the FDO, edit your AUTOEXEC.BAT file so the FDO loads first. If the
 FDO is loading first, load it after the mouse driver.
    Please note that this workaround is not guaranteed to avert all
 conflicts, but it has yielded positive results in many instances.


 35. "Microsoft Mouse Driver Not Found" Error Message

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32263

    The MOUSE.COM or MOUSE.SYS driver must be loaded before attempting
 to load a mouse menu. The "Microsoft Mouse driver not found" error
 message is generated when a mouse expert menu tries to load without
 the mouse driver already loaded.
    This error message should not be confused with the message "Driver
 not installed-- Microsoft Mouse not found", which is a mouse driver
 not loading message.


 36. CPANEL Defaults to Display Page 0

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35230

 CPANEL may not display in a graphics application that uses graphics
 pages greater than 0. CPANEL defaults to display on Page 0 of the
 graphics page.

 To work around this problem, use the /S switch to the mouse driver.


 37. /S1 or /S2 Yields Same Result as /S0

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35231

 If a sensitivity switch of value 1 or 2 is passed to the mouse driver,
 you may not recognize any mouse cursor change for mouse movement. A
 sensitivity value of 3 seems to be the minimum sensitivity that the
 mouse driver moves the cursor.


 38. Internal Processing Error and OS2MOUSE.V12 with Mouse

 Product Version(s): 1.20
 Operating System:   OS/2
 Flags: ENDUSER |
 Last Modified:  6-JUL-1990    ArticleIdent: Q63226

 When OS2MOUSE.V12 is installed and the communications manager is
 selected, an internal processing error is detected and the system will
 hang.

 To correct this problem, reinstall the mouse driver using the drivers
 that were supplied with the OS/2 package and the system will not hang
 when the communications package is selected.

 We are researching this problem and will post new information here as
 it becomes available.


 39. Symphony Mouse Menu Works in Text Mode Only

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28425

    When using the Symphony mouse menu, please make sure Symphony is
 set up for "text and graphics separate".

    If you are running Symphony with an EGA, Symphony comes up in green
 for "text and graphics separate" configurations. Combined
 configuration will display in red when Symphony is running.


 40. Standard Mouse Menus Do Not Deallocate

 Product Version(s): 4.x 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q23827

 You cannot deallocate a standard mouse menu (a menu that loads with
 MENU.COM) from memory. Entering "menu off" will disable the keyboard
 emulation; however, it will not deallocate from memory.


 41. Available Mouse Menus

 Product Version(s): 4.x 5.x 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-AUG-1988    ArticleIdent: Q23836

    Version 6.00 of the Microsoft Mouse contains "Expert Mouse Menus"
 for Lotus 1-2-3 Versions 1A and 2.00, MultiMate Version 3.31, and
 DisplayWrite 3 Version 1.10. The "Mouse Programmer's Reference Guide"
 contains "Standard Mouse Menus" for previous versions (date mid-1985)
 of Symphony, WordStar, Multiplan, and VisiCalc.


 42. Expert and Standard Mouse Menus

 Product Version(s): 4.x 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-AUG-1988    ArticleIdent: Q23837

 Question:
    What is the difference between an Expert and a Standard mouse menu?

 Response:
    Standard mouse menus are loaded with MENU.COM, while an Expert
 mouse menu is an executable .COM file.


 43. CPANEL Does Not Display in the OS/2 DOS 3.x Box

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35232

 CPANEL will not work in the OS/2 DOS 3.x box unless you load the DOS
 mouse driver rather than the OS/2 mouse driver.


 44. MSETUP Installs on Drive Specified

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35250

 If you have more than one hard-disk partition, MSETUP has the
 capability of installing the mouse software on a partition that may
 not be your C: drive. If you select to do this, you must manually edit your
 AUTOEXEC.BAT file to invoke the mouse driver and optionally CPANEL.
 For example, to install the mouse software on your D: drive, you must
 edit your AUTOEXEC.BAT on your boot drive C: to the following:

 D:\mouse1\mouse
 D:\mouse1\cpanel



 45. Standard Mouse Menus Are Not in .COM Format

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-AUG-1988    ArticleIdent: Q23829

    You cannot write menus in .COM format with the "Mouse
 Programmer's Reference Guide." The reference guide allows you to
 create standard mouse menus, which are installed with the MENU.COM
 file.
    If you are a developer interested in creating menus in .COM format,
 an Expert Menus Toolkit is available that allows you to create expert
 mouse menus. For more information, call Microsoft Hardware Development
 at (206) 882-8080, and ask for information on Expert Menus Development
 software.


 46. Earlier Versions with Mouse Menu Software

 Product Version(s): 4.x 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-AUG-1988    ArticleIdent: Q24163

    The content of the "Microsoft Mouse Programmer's Reference Guide"
 is similar to earlier versions of the mouse containing the mouse
 programming.
    If you are writing standard mouse menus, the commands in the
 "Microsoft Mouse Programmer's Reference Guide" are the same as they
 were with versions prior to Version 6.00. The major changes include
 better documentation, examples, and updated mouse libraries. If you
 have a version prior to Version 5.03, we recommend that you obtain the
 "Microsoft Mouse Programmer's Reference Guide" if you are having any
 problems with MENU.COM or MAKEMENU.EXE.


 47. Applications That Do Not Use the Mouse

 Product Version(s): 4.x 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q24164

 The "Microsoft Mouse Programmer's Reference Guide" allows you to write
 your own mouse menus for programs without mouse support. The reference
 guide includes the necessary software and documentation to provide
 keyboard emulation using mouse menus. Mouse menus will run in text
 mode with most programs that do not grab the keyboard interrupts.


 48. MENU.COM Needed to Load .MNU Files

 Product Version(s): 4.x 5.x 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-AUG-1988    ArticleIdent: Q24178

 With the release of Version 6.00 of the mouse, we decided to separate
 the programming aspects of the mouse and place them in the "Microsoft
 Mouse Programmer's Reference Guide." The guide contains the menu
 installer MENU.COM and the menu compiler MAKEMENU.EXE. If you have the
 software prior to Version 6.00, you will find MENU.COM and
 MAKEMENU.EXE on your system diskette.



 49. Mouse Menus May Hang in the OS/2 DOS 3.x Box

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35251

 Mouse menus may hang in the OS/2 DOS 3.x box if you are using the OS/2
 mouse drivers. To work around this problem, use the DOS mouse drivers
 that were included with your mouse and do not load the OS/2 mouse
 driver.


 50. Menu Problems with Leading Edge D2 in 43-Line Mode

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28428

    The characters on the screen get trashed if you load a mouse menu
 in 43-line text mode using a Leading Edge D2 with monochrome display.
 The characters are readable, but the top two or three lines of pixels
 composing the characters are repeated beneath the characters (similar
 to a vertical ghost effect).

    Resetting the EGA into the 43-line mode corrects the problem
 temporarily. Run EGA.EXE with the argument EGA, or set switch 5 on the
 display adapter to the open position to disable the auto-mode
 selection feature (this process produces the same effect as the EGA
 EGA command).


 51. Erratic Cursor Movement Using 123 Mouse Menu

 Product Version(s): 4.x 5.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-NOV-1988    ArticleIdent: Q24710

 If the cursor moves erratically when using the 123.MNU mouse menu
 provided with Version 5.00 of the mouse, make sure no other
 memory-resident programs are interfering. If the problems persist,
 contact Microsoft Product Support at (206) 454-2030 for the 123 Menu
 disk, which includes an updated 123.MNU file.

 If you own Mouse Version 6.00, use the MS123-2.COM found on your
 Expert Mouse Menus disk. This supersedes the 123.MNU file.


 52. Operation of InPort Chip Versions 1.00 and 1.10 Versus 1.20

 Product Version(s): 1.00 1.10 1.20
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-MAR-1990    ArticleIdent: Q49003

 Versions 1.00 and 1.10 of the Microsoft Mouse InPort Chip operates in
 the timer interrupt mode (mouse service routine interrupt occurs at a
 fixed rate).

 Version 1.20 of the InPort Chip operates in the data interrupt mode
 (mouse service routine interrupt occurs whenever mouse data is
 present).


 53. Bus Mouse with InPort Not Supported in IBM PC-DOS 4.00

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q35364

 IBM PC-DOS Version 4.00 has three special mouse drivers that only work
 with the DOS Shell: PS/2, serial, and bus mouse (non-InPort).

 For bus mice with InPort, we recommend that you load the mouse driver
 that was included with your mouse (MOUSE.COM) and delete the following
 command line in the DOSSHELL.BAT that loads the IBM DOS shell mouse
 driver:

 /MOS:PCMSPDRV.MOS


 54. Unable to Activate the Mouse in Chart

 Product Version(s): 6.00
 Operating System:   MS-DOS
 Flags: ENDUSER | TAR64094
 Last Modified: 19-SEP-1988    ArticleIdent: Q25053

 You may be unable to activate the mouse in Chart; the mouse arrow may
 appear to be frozen.

 Chart defaults serial printer drivers to COM1:. Therefore, when using
 a serial mouse, it is necessary to start Chart and then change the
 Print Setup adapter in the Chart screen to something other than the
 COM port to which the mouse is connected. You must do the following to
 activate the mouse:

 1. Change the Print Setup adapter in the Chart screen from COM1: to
    LPT1:.

 2. Exit.

 3. Restart Chart.


 55. End User Made Mouse Menus Don't Run Under MS-DOS 4.00 or 4.01

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-JUN-1990    ArticleIdent: Q61105

 Mouse menus compiled with MAKEMENU.EXE and run with the MENU.COM that
 came with Mouse driver versions 6.24b and earlier will not work under
 MS-DOS version 4.00 or 4.01. The menu will install into memory, but
 will not be visible and will not interface correctly with the
 application.

 Currently, the only workaround is to load the ANSI.SYS driver with the
 /k option. This disables the extended keys on the keyboard, which
 allows your Mouse menus to work.

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


 56. Using PS/2 Serial Mice with Laptop Computers

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-JUL-1989    ArticleIdent: Q28492

    Microsoft PS/2 serial mice are not guaranteed to work correctly
 with laptops due to the low power specification on serial ports
 usually found on the laptops.

    PS/2 serial mice with the SSMA adapters (cigarette box shaped
 adapters) may not work properly with the Zenith laptop models 181 and
 183.
    The current mice with the UMA adapters (cigar-shaped adapters) with
 the Version 6.14 mouse driver have been tested informally and seem to
 work properly with the Zenith laptops.


 57. Restricted Mouse Cursor Movement in Pro Design II

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28493

    When using Pro Design II, the mouse cursor is restricted to a 1
 inch box in the top left-hand corner.

    This problem has been reported with the mouse driver Version 6.02 through
 mouse driver Version 6.11. Currently the problem cannot be isolated to a
 mouse driver problem since the cursor movement restriction seems to occur
 only with the Pro Design II application.
    Please contact American Small Business Computers, developers of Pro
 Design II, at (918) 825-4844. An update may resolve the problem.
    Microsoft is researching this problem and will post new information
 as it becomes available.


 58. NEC Multispeed Laptop Continues to Access Drive

 Product Version(s): 6.0 6.02 6.10 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28494

    When using the NEC Multispeed laptop with the mouse driver
 installed, the disk light stays on as if the disk is being accessed.

    NEC produced a patch INIT059.COM or ROM upgrade that resolves the
 problem.
    Please contact NEC's technical support at (800) 632-7368.


 59. Tests with the Compaq 386/20

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28495

    The new Bus and PS/2 serial mice work properly with the Compaq
 386/20 computer.

    The Version 1.0 mouse and revision G of the Bus interface board
 worked properly with the Compaq 386/20 with the Version 6.11 of the
 mouse driver.
    The white button and gray button serial mice tested successfully
 with the Compaq 386/20's serial port.


 60. FCC Class B Approval

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28496

    The new Version 1.0 mice have Class B FCC approvals.

    The InPort mouse and the InPort interface card of the new white
 button Version 1.0 mice have FCC Class B approvals (ID C3K7PN9937 for
 the mouse and C3K6P8 for the interface card respectively).


 61. Interrupt Setting for the IBM PS/2 Model 30

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28497

    When setting the J4 interrupt setting on the mouse InPort interface
 card, Microsoft recommends jumper 2 or 3.

    Please check that other peripheral boards are not using the same
 interrupt setting as the mouse. Do not use pair 5 for the setting.


 62. Installing Windows when Using the PS/2 Mouse Port

 Product Version(s): 6.10 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28498

    If you are using the IBM PS/2 mouse port for your mouse, please be
 sure to select IBM PS/2 when selecting a pointing device during the
 Windows Version 1.04 installation.

    Selecting the Microsoft mouse when using the IBM PS/2 mouse port
 will not give you mouse control in Windows Version 1.04.


 63. DOS 2.xx Does Not Recognize \Mouse1\Mouse

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 26-APR-1988    ArticleIdent: Q28499

 Problem:
    After running the mouse setup routine and rebooting my machine, the
 mouse driver will not install.

 Response:
    Because DOS Version 2.xx does not recognize the path statement in
 command lines, such as /mouse1/mouse in the AUTOEXEC.BAT file, the
 mouse driver never installs.
    To work around this, edit your AUTOEXEC.BAT file to change the
 directory to your MOUSE1 subdirectory. Then, directly call the MOUSE
 and CPANEL as follows:

   CD \MOUSE1
   MOUSE
   CPANEL
   CD\


 64. Use MOUSE.SYS with Flight Simulator

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28500

    If you have Flight Simulator and a mouse, you should use the
 MOUSE.SYS file in the CONFIG.SYS file rather than the MOUSE.COM in the
 AUTOEXEC.BAT file that is installed by the mouse setup.

    The Version 6.11 of the mouse driver that uses the MOUSE.COM file,
 may cause Flight Simulator to continuously ask if you have a mouse.
 Using the MOUSE.SYS file solved the problem.


 65. Windows 1.01 MOUSE.DRV File Included with Mouse 1.0

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28502

    The current Mouse Setup disk contained in the EasyCad and MS
 Paintbrush software includes the mouse driver for Windows Version 1.01
 owners.

    Because the Windows Version 1.01 mouse driver does not recognize
 mice with InPort hardware, Microsoft has included an updated MOUSE.DRV
 file to resolve the problem.
    Copy the MOUSE.DRV file to your Windows Install disk and reinstall
 the Windows software. If you have Windows Version 1.03 or a newer
 version, you will not have this problem.


 66. Compaq Portable 3 Compatibility

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-SEP-1988    ArticleIdent: Q28503

 The Compaq Portable 3 has built-in hardware that includes a serial
 port and an expansion chassis slot. The serial mouse should work
 properly in the standard serial port. The bus mouse will not fit in
 the only slot available for the expansion chassis, but should fit in
 the expansion chassis slot (this has not been tested).


 67. STB VGA Extra Using Mouse

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q28504

 STB requests that callers having problems with the mouse and VGA Extra
 (unspecified symptoms) contact STB at (214) 234-8750.


 68. Mouse Installation with OS/2

 Product Version(s): 1.0
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 21-APR-1988    ArticleIdent: Q28505

    OS/2 does not use the mouse driver contained with the Microsoft
 mouse.

    The DOS mouse driver MOUSE.COM or MOUSE.SYS does not load if you
 install OS/2 on a machine unless you have a dual boot option where
 standard DOS is loaded. OS/2 has a custom driver MOUSExxx.SYS which
 will run in the OS/2 protected mode or DOS compatibility box. In
 addition to the OS/2 mouse driver, you should load the POINTDD.SYS and
 EGA.SYS as well. Refer to your OS/2 documentation for further OS/2
 mouse driver details.


 69. Cipher Data Tape Drive Conflicts with Bus Mouse

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-SEP-1988    ArticleIdent: Q28515

    The Cipher Data Tape Drive can be set to use I/O address 220-23F;
 however, this setting causes the drive to forward and reverse every
 time the Bus mouse moves.
    The Tape Drive can reportedly use another I/O address to resolve
 the conflict. This is not a problem with the serial mouse.


 70. Choice of Three Software Bundles for New Mouse 1.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q28517

 The new white-button mice are available in three software bundles. You
 can purchase a PS/2 serial or bus mouse with one of the following
 products:

 1. EasyCAD

 2. Microsoft Paintbrush with Mouse Menus

 3. Windows with Paintbrush for Windows


 71. Bus Mouse Jumper Settings J2, J3, and J4

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  5-JUN-1988    ArticleIdent: Q28538

    The new white-button Bus Mouse Version 1.00 interface card
 (Revision G) is an InPort interface half-size card. When installing
 the interface card, the jumper settings J2, J3, and J4 must be
 correctly set for the mouse to function properly.

    The J2 jumper setting allows you to use your Bus mouse from slot 8
 if you have an IBM PC XT. Set the top two pins to the "XT SLOT 8"
 configuration. If you have an IBM PC, AT, or some other non-IBM PC XT,
 you can leave the jumper setting on the "Normal" position (the lower
 two settings).
    The J3 jumper setting allows you to set another I/O address space
 other than the default 23C-23F. The "Primary" settings are the top two
 settings, while the "Secondary," which has the I/O address 238-23C, is
 the bottom two settings.
    Microsoft recommends that you only change this setting if another
 InPort interface hardware item is used in your system or if another
 system peripheral card is using the same I/O addresses.
    The J4 jumper setting allows you to select an IRQ or machine
 interrupt. Microsoft recommends that you select an interrupt from two
 through five that is not used in your system. In most instances,
 although you should confirm that another card is not using the same
 interrupt, an IBM PC or XT has interrupt two available for you to use
 and an IBM PC AT usually has interrupt five available.
    Refer to Page 6 of your "Microsoft Mouse User's Guide" for more
 information.


 72. Mouse and Flight Simulator 3

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-JUL-1988    ArticleIdent: Q32028

    Mouse driver Versions 6.02, 6.11, 6.14, and 6.23 have been tested
 with Flight Simulator 3 and all work normally.


 73. Mouse, Windows, Desqview, and HP Drawing Gallery

 Product Version(s): 6.00 6.10 6.14
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 25-JUL-1988    ArticleIdent: Q32064

    If you run Hewlett-Packard Drawing Gallery from either Windows or
 Desqview and exit the program normally, the mouse still works
 correctly; however, there is no cursor.
    To correct this problem, modify the PIF file included with the
 program. Under the Directly Modifies section, select Memory in
 addition to Screen.


 74. Earlier Versions of Generic Cad May Not Work with InPort

 Product Version(s): 1.00 5.03 6.00 6.02 6.10
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-AUG-1988    ArticleIdent: Q32129

    Generic Cad recommends Interrupt 3 for the J4 setting of the bus
 mouse.
    Be aware that older versions (possibly releases 1 and 2) of Generic
 Cad may not work correctly with versions of the bus mice that include
 the InPort Interface. Because Generic Cad goes directly to the
 hardware (i.e., it uses its own mouse driver), you must obtain an
 update to release 1 or 2. To obtain an update, contact Generic Cad by
 calling (206) 487-2934.


 75. Mouse Must be Removed to Run PS/2 Diagnostics

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-FEB-1989    ArticleIdent: Q33570

    When running the PS/2 diagnostics program with a Microsoft Mouse on
 the mouse port, the mouse must be disconnected. If the mouse is not
 disconnected the machine will hang.


 76. Sensitivity May Reset if a /R Switch Passed to the Driver

 Product Version(s): 6.24
 Operating System:   MS-DOS
 Flags: ENDUSER |  buglist6.24
 Last Modified: 11-OCT-1988    ArticleIdent: Q35974

 If an /R switch is passed to the MOUSE.COM, the sensitivity may reset.
 Note: the /R switch is only used with the Bus Mouse with InPort
 hardware.

 Microsoft has confirmed this to be a problem in Version 6.24. We are
 researching this problem and will post new information as it becomes
 available.


 77. Extension Cables for Microsoft Mice

 Product Version(s): 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-JUL-1989    ArticleIdent: Q32128

 Microsoft retails a 1.5-meter InPort extension cable. Although the
 cable was designed for the gray-button mouse, we have found, under
 informal testing, that the extension cable works with the new
 white-button mice (serial and bus).

 If you decide to make a longer cable, special wire is not needed. The
 Microsoft extension cable uses shielded, 7-conductor, 30-gauge wire. A
 heavier gauge wire might be considered for strength.

 If an extension is added to the serial mouse, the cable needs to pass
 the following pins straight through as follows:

    pins 2,3,4,7,20 and shield for the 25-pin D version, or
    pins 2,3,4,5,7 and shield if using the 9-pin version.

 Microsoft is not aware of any special considerations for special
 installation, such as alignment to compensate for cable
 characteristics, special cable termination (R, RC, etc.), needed for
 line drivers, or noise-immunity considerations.

 If you do anything to change the mouse cabling, the machine is likely
 to violate FCC Electromagnetic Interference regulations. The computer
 may interfere with nearby television or radio reception. Operation in
 a residential environment is especially ill-advised, and such a
 configuration certainly cannot be offered for sale without extensive
 testing and FCC certification.

 Microsoft takes no responsibility for the performance of its products
 when modified or used in a manner other than that intended and advised
 in the manual. Microsoft assumes the customer will comply with all
 applicable laws and regulations, and offers the above advice only on
 that basis.


 78. AT&T 6300 Plus and Bus Mouse

 Product Version(s): 5.00 5.30 6.00 6.10 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32682

    When using the bus mouse with the AT&T 6300 Plus, the J4 jumper
 must be set to either 3 or 4.
    There have been problems reported while using interrupt 5 with this
 computer; this should be a free interrupt on an AT machine. This
 problem may occur with any program that uses the mouse; however, the
 problem has not occurred with Paintbrush, CPANEL.COM, and DEFAULT.COM.


 79. DEFAULT.COM Included with Mouse

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-JUL-1988    ArticleIdent: Q32714

    If you have the new white-button mouse Version 1.00, the
 DEFAULT.COM file, which provides cursor emulation, is located on the
 Mouse Setup Disk. Version 6.00 through 6.10 owners have the
 DEFAULT.COM file located on their Mouse Expert Menus Disk. Mouse
 owners with versions prior to Version 6.00 can write their own menus
 using the mouse menu programming tools (MAKEMENU.EXE and MENU.COM)
 included with their mouse software.


 80. Resolution, Mickeys, or Points Per Inch of the Mouse

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-AUG-1988    ArticleIdent: Q33066

    The resolution (or mickeys) of Versions 5.x and 6.x of the mouse
 (gray buttons), and the new Version 1.00 of the mouse (white buttons)
 is 200 ppi. For example, the mouse driver can recognize 1/200th of an
 inch movement of the mouse. The resolution of Versions 1.x, 2.x, 3.x,
 and 4.x of the mouse (green buttons) is 100 ppi.


 81. PS/2 Mouse on Mouse Port Initializes Slowly

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-AUG-1988    ArticleIdent: Q33106

    If you load a program when using a serial PS/2 mouse on the PS/2
 mouse port, it will take longer to load than a serial or bus connect
 because the mouse initialization is performed through the PS/2 BIOS.


 82. Mouse and IBM Page Printer Hang System

 Product Version(s): 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  4-AUG-1988    ArticleIdent: Q33117

    When using the Microsoft Mouse with an IBM Page Printer, the mouse
 driver must use MOUSE.SYS rather than MOUSE.COM. To use the mouse with
 an IBM Page Printer, do the following:

    1. Copy MOUSE.SYS from the Setup/Basic Menus disk to the MOUSE1
       subdirectory of your hard drive.
    2. Edit your AUTOEXEC.BAT file (found in the root directory) and
       remove the following line:

       /MOUSE1/MOUSE

    3. Edit your CONFIG.SYS file (also found in the root directory) and
       insert the following line prior to the line that loads the Page
       Printer driver:

       DEVICE=C:\MOUSE1\MOUSE.SYS

    4. Reboot the machine. The mouse now can be used in conjunction
       with the Page Printer.


 83. Tempest-Approved Mouse

 Product Version(s): 6.00   | 6.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q47676

 Tempest versions of the Microsoft Mouse are available from Quality
 Tempest Products (QTP) of Herndon, Va.

 A Tempest "approved" mouse is one that has been modified so that there
 are no RF emissions. This modification is needed so the mouse can be
 used in sensitive or classified areas

 For more information, contact Steve Rice of QTP at (703) 834-5200.


 84. Jumper Settings for Bus Mouse Used in an XT 286

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 23-AUG-1988    ArticleIdent: Q34009

    For the purpose of setting the jumpers on the bus mouse card, the
 IBM XT 286 is equivalent to an IBM AT. The hard disk in the IBM XT 286
 uses IRQ 2. The typical settings are as follows:

    Jumper    Setting
      J2      normal
      J3      primary
      J4      IRQ 5

    As always, be sure that IRQ 5 is not being used for other hardware
 devices, such as a Bernoulli box, network card, or tape backup.


 85. Mouse and AutoCAD

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-SEP-1988    ArticleIdent: Q33476

 AutoCAD contains its own mouse driver; therefore, it does not need to
 have the Microsoft Mouse Driver installed to take advantage of the
 Microsoft Mouse. If the Microsoft Mouse Driver is installed, it may
 cause a TSR-type error when AutoCAD is run.

 AutoCAD problems can be directed to Autodesk by calling (415)
 332-2344.


 86. Cursor Freezes when Using Old Mouse Driver on AT-Type Machine

 Product Version(s): 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-AUG-1988    ArticleIdent: Q33553

    The mouse cursor may freeze or leave contrails in application
 programs running on 80286 or 80386-based machines if the mouse driver
 is Version 5.03 or earlier.
    The keyboard ordinarily will still work correctly. You should
 update to the current version of the driver.


 87. Mouse Menu for Quattro

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q34086

 The Lotus 1-2-3 mouse menus on the Mouse Expert Menus disk do not
 enable the pop-up menus in Quattro. To use the mouse with Quattro,
 install DEFAULT.COM or MSMENU.COM.

 MSMENU.COM allows you to scroll through the spreadsheet and select
 menu items with the mouse. The menus do, however, need to be activated
 with the SLASH (/) key. The menus function the same whether or not
 Quattro is loaded with the Lotus 1-2-3 menu tree.

 Note: DEFAULT.COM is now called MSMENU.COM.


 88. Selecting Communications Ports, Interrupts in COMPAQ SLT/286

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | mouse
 Last Modified: 19-MAR-1990    ArticleIdent: Q48414

 On a COMPAQ SLT/286, the communications port and its associated
 interrupt can be set by using the Setup/Diagnostic program included
 with the computer. The following is the procedure:

 1. Place the Setup disk in your floppy drive.

 2. Run the Setup program.

 3. At the menu screen, press F4 to select "change configuration."

 4. From the next menu screen, select "Modem async-device."

 5. From the next screen, select "system async device."

 6. From the next screen, select "com1."

 7. From the next screen, select "interrupt 4."

 8. Back up through the screens until you return to the DOS prompt.


 89. Text Mode Problem with Mouse Version 3.00

 Product Version(s): 3.00
 Operating System:   MS-DOS
 Flags: ENDUSER | buglist3.00 fixlist4.00
 Last Modified: 11-OCT-1988    ArticleIdent: Q11085

 Question:

 Were there any known problems with Hercules graphics support with the
 mouse Version 3.00? When we use the routine reccommended by Hercules
 to get the mouse into graphics mode, we still get a text mouse when we
 use function 0 of the mouse library.

 Response:

 There is a problem in the mouse driver that is defaulting the text
 cursor to the hardware text cursor, instead of to the software text
 cursor. Microsoft has confirmed this to be a problem in Version 3.00.
 This problem was corrected in Version 4.00.

 There are two possible solutions for the problem: use only driver
 Version 4.00 or later, or insert a mouse function 10 call (Set Text
 Cursor) into the beginning of the application program, with the second
 parameter (M2%) set to 0 (select software text cursor).


 90. Losing Data When Mouse and Data Transfer Are Involved

 Product Version(s): 6.00 6.11 6.14 6.24 6.24b
 Operating System:   DOS
 Flags: ENDUSER |
 Last Modified: 22-MAR-1990    ArticleIdent: Q49285

 Several customers report lost data or a system lock up when
 transferring high speed data from a modem or mainframe through a
 serial port. The mouse was resident in memory when the problem
 occurred.

 With communications going through COM2:, the interrupt 3 is in use.
 This interrupt has a higher priority than either interrupt 4 (for a
 mouse in COM1:) or interrupt 5 (bus mouse with interrupt 5 set on the
 J4 jumper).

 You should ensure that the communications equipment is loaded onto
 COM2: so that it can take advantage of the higher priority interrupt.
 The phenomenon is inherent with interrupt handling and established
 priorities.


 91. Intermittent Installation on the Packard-Bell PS/2 Port

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-MAY-1990    ArticleIdent: Q61591

 When the 400 dpi Microsoft Mouse is attached to the PS/2 port of the
 Packard-Bell PackMate 2, the Excel 5, and the Legend 5 computers, the
 mouse sometimes does not install correctly.

 When the mouse is attached to the serial port there are no
 installation problems.

 If you are experiencing this problem, contact Packard-Bell at
 (818) 773-4400.


 92. Sluggish or Jerky Mouse Motion in PC DOS Version 4.00 Shell

 Product Version(s): 4.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 11-OCT-1988    ArticleIdent: Q35975

 When using the IBM PC DOS Version 4.00 shell mouse drivers with an IBM
 PS/2, the mouse motion may appear sluggish or jerky.

 To work around this problem, do not load the PC DOS Version 4.00 mouse
 drivers /MOS:PC??DRV.COM (where ?? is PC or MS) and load the Microsoft
 mouse driver MOUSE.COM before running the DOSSHELL.BAT file.


 93. Deallocating Memory When Using Compaq and IBM Mouse Ports

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q43344

 When using a PS/2 style mouse port, you cannot deallocate the memory
 the mouse driver is using. The Mouse Off switch disables only the
 mouse. However, the memory will be deallocated if a bus or serial
 mouse is used.

 The following machines have PS/2 style mouse ports:

 1. COMPAQ 286e, 386s, 386e, and 386 20e

 2. IBM (all PS/2's)


 94. Mouse Will Not Work with PC Tools Deluxe 5.5 and 6.0

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 14-MAY-1990    ArticleIdent: Q61264

 If PC Tools Deluxe versions 5.5 and 6.0 are loaded as memory resident,
 the mouse cursor may or may not be displayed on the screen. If the
 mouse cursor is displayed, it will not move.

 This problem has been corrected in a later version of PC Tools.

 For information about this update, contact Central Point Software at
 (503) 690-8080.


 95. "Mouse Off" Hangs System: Samsung AT Compatible with J4 on 2

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  1-NOV-1988    ArticleIdent: Q37252

 On the Samsung S-500 AT compatible, typing "Mouse Off" may hang the
 system if the Bus mouse J4 jumper is set on interrupt 2. Moving the
 jumper to interrupt 5 eliminates the problem.


 96. Excellerator Requires Ms-DOS Version 3.30 with AT&T 6312

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-JAN-1989    ArticleIdent: Q37254

 When using the Excellerator (a code generation program) with an AT&T
 6312, MS-DOS Version 3.30 must be used.

 When any version of DOS earlier than Version 3.30 is used with the
 AT&T 6312 machine and the Excellerator, one of the following symptoms
 may occur:

 1. More than one cursor may appear.

 2. The mouse pointer may skip pixels as it is moved across the screen.

 3. Hieroglyphics may appear.

 According to Leading Index, the problem can be corrected by upgrading
 to MS-DOS Version 3.30.


 97. Mouse Command-Line Switches for Mouse Driver Version 7.04

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | Video 7 Video-7
 Last Modified: 29-AUG-1990    ArticleIdent: Q61592

 The following are the current command-line options (switches) for
 Microsoft Mouse Driver version 7.04:

    Option  Description
    ------  -----------

    /B      Using bus mouse

    /Cn     Using serial mouse on port COMn
            (where:  0 <= n <= 1)

    /Dn     Enabling double-speed threshold
            (where:  0 <= n <= 100)

            0 => No threshold speed (always double speed)
            100 => Maximum threshold speed (rarely double speed)

    /Hn     Setting horizontal sensitivity
            (where:  0 <= n <= 100)

            0 => 0 horizontal mickeys per pixel scaling factor
               (i.e., no horizontal movement returned)
            100 => 100 horizontal mickeys per pixel scaling factor

    /In     Using Microsoft InPort Mouse on primary or secondary InPort
            (where:  n = 1  or  n = 2)

    /L(c)   Selecting language c
            Languages are defined as follows:

               c         Language             Ordinal Value
               -         --------             -------------

           (default)     English                    0
               F         French                     1
               NL        Netherlands (Dutch)        2
               D         German                     3
               S         Swedish                    4
               SF        Finnish                    5
               E         Spanish                    6
               P         Portuguese                 7
               I         Italian                    8
               K         Korean                     9
               J         Japanese                   10

    /Mn     Cursor mask override
            (where:  0 <= n <= 255, n = 0 => mask off)

            0 => Mask off
            Not 0 => Mask on

            (If software cursor is specified in function 10, then set
            cursor to default software cursor. It tells the mouse
            driver to determine which bit pattern to use to make
            the cursor visible.)

    /Nn     Using dampened cursor motion to fix LCD laptop display
            problems
            (where:  0 <= n <= 255)
            (This slows down the screen update rate.)

            0 =>    Skip 0 interrupts (this is, same as normal mouse)
            255 =>  Skip 255 mouse hardware interrupts before
                    processing data

    /Pn     Selecting ballistic curve number n
            (where:  1 <= n <= 4)

            (Note that this may change if the specification changes.)

    /R(n)   Setting interrupt rate
            (where:  1 <= n <= 4, default n = 1)

            1 => 30Hz
            2 => 50Hz
            3 => 100Hz
            4 => 200Hz

    /Sn     Setting both horizontal and vertical sensitivity
            (where:  0 <= n <= 100)

            0 => 0 mickeys per pixel scaling factor
                 (that is, no movement returned)
            100 => 100 mickeys per pixel scaling factor

    /Vn     Setting vertical sensitivity
            (where:  0 <= n <= 100)

            0 => 0 vertical mickeys per pixel scaling factor
                 (that is, no vertical movement returned)
            100 => 100 vertical mickeys per pixel scaling factor

    /Y      Disabling sprite and Video Seven code

            (To disable mouse driver hardware cursor support on
            certain Video Seven and C&T VGA controllers.)

    /Z      Using PS/2 mouse

            (This is added for PS/2 only. It directs the driver to look
            for the mouse at the mouse port.)


 98. Hot Spot Not Displaced Along Horizontal Axis with Driver 7.04

 Product Version(s): 7.04
 Operating System:   MS-DOS
 Flags: ENDUSER |  h_menupr menu programming INT33 MF9
 Last Modified: 27-JUL-1990    ArticleIdent: Q64177

 If mouse driver version 7.04 for the Microsoft Mouse is installed
 without the /Y switch, the hot spot will not be displaced along the
 horizontal axis.

 This problem will occur only in programs that use mouse function 9 to
 set the hot spot. Including a /Y switch when installing the mouse
 driver will eliminate this problem.


 99. Problem with Mouse and PS/2 Model 70A21

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 18-APR-1990    ArticleIdent: Q38654

 Older models of the PS/2 Model 70A21 will not boot with the mouse in
 the mouse port.

 The machine hangs and gives an 8603 error, indicating something is
 wrong with the mouse. The mouse functions properly in the serial
 ports, and an IBM mouse will work in the mouse port with the drivers
 provided by Microosft.

 There is a patch that will correct this problem. Contact Microsoft
 Product Support Services at (206) 454-2030 for this patch.


 100. "Interrupt Jumper Missing" Error Message

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  6-DEC-1988    ArticleIdent: Q38754

 The "Interrupt jumper missing" message can appear when installing the
 driver on a bus mouse. This can be caused by several things.

 It frequently appears because the interrupt selected on the
 J4 jumper is conflicting with existing hardware. If the
 IRQ vector is being used by anything else this message will
 appear.

 The message also can appear because the J2 jumper is set on slot 8 and
 not to normal as it should be.

 It also is possible that the interface card is defective. This can
 only be verified by installing the mouse and software onto another
 machine and testing the mouse.


 101. How to Define, Display Graphics Mouse Cursor in FORTRAN 5.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | H_fortran
 Last Modified: 10-JUL-1990    ArticleIdent: Q51225

 The following code shows how to define and display a graphics mouse
 cursor in Microsoft FORTRAN version 5.00:

 c This program displays mouse cursor in a shape of a cross.
 c The program terminates when the user presses the ENTER
 c key.

       include 'fgraph.fi'
       include 'fgraph.fd'
       integer*2 m1,m2,m3,m4
       integer*2 mcursor(32)
       integer*2 arrloc(2)
       integer*4 arradds
       equivalence (arrloc(1),arradds)

       do 50 i=1,16                   !define the screen mask
  50      mcursor(i) = #ffff
          mcursor(17) = #0000         !define the cursor mask
          mcursor(18) = #0180
          mcursor(19) = #0180
          mcursor(20) = #0180
          mcursor(21) = #7ffe
          mcursor(22) = #0180
          mcursor(23) = #0180
          mcursor(24) = #0180
          mcursor(25) = #0000
          mcursor(26) = #0000
          mcursor(27) = #0000
          mcursor(28) = #0000
          mcursor(29) = #0000
          mcursor(30) = #0000
          mcursor(31) = #0000
          mcursor(32) = #0000

       m1 = 0
       call mousel(m1,m2,m3,m4)         !reset mouse driver
       dummy = setvideomode($erescolor) !set video mode (EGA)
       m1 = 9
       m2 = 1
       m3 = 1
       arradds = locfar(mcursor) !get address of cursor array
       call mousel(m1,m2,m3,arrloc(1))  !set graphics cursor
       m1 = 1
       call mousel(m1,m2,m3,m4)         !show cursor
       read(*,*)                        !press enter to quit
       m1 = 2
       call  mousel(m1,m2,m3,m4)        !hide cursor
       dummy = setvideomode($defaultmode) !set video mode
       end


 102. Serial Mouse May Hang on ATT 6300

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-MAR-1989    ArticleIdent: Q40162

 When either MOUSE.COM or MOUSE.SYS is loaded using a serial mouse on
 some of the ATT 6300's, the machine will hang.

 You can correct this problem by specifying the COM port the mouse is
 attached to by using the /C1 or /C2 command-line switches. You can do
 this either in a manual start up or by including the information in
 the AUTOEXEC.BAT or CONFIG.SYS files.


 103. Mouse and Lotus 1-2-3 Mouse Menu Under Windows/286

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-MAR-1989    ArticleIdent: Q41087

 To run Lotus 1-2-3 and the Mouse Menu for Lotus under Windows, the
 123.PIF file included with Windows must be edited. The key point to
 note is that under the "Directly Modifies" option of the PIF file the
 check boxes for both Screen and Memory must be turned on. Add any
 parameters or set the initial directory if necessary. Save these
 changes so you will not have to repeat them again.

 After the 123.PIF file is correctly configured, load the Mouse and
 Menu in memory as you normally would before going into Lotus 1-2-3.
 Bring up Lotus 1-2-3 within Windows and the Menu should function
 correctly. If not, reboot the system from the original floppy DOS disk
 to make sure nothing else in memory is interfering, then load the
 mouse and menu into memory.


 104. ATI Wondercard Graphics Adapter

 Product Version(s): 1.00 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-FEB-1989    ArticleIdent: Q31338

 Certain BIOS versions of the ATI Wondercard Graphics Adapter and
 Microsoft Mouse Driver Versions 6.02, 6.10, 6.11, and 6.14 are
 incompatible. ATI has solved this problem by offering a BIOS upgrade.

 The BIOS version is displayed when booting your computer. If you do
 not know the BIOS version of the Wondercard, reboot the machine. The
 board and BIOS versions that do work together are as follows:

 Board Version                      BIOS Version

    1                             1.16 (or higher)
    2                             2.07 (or higher)
    3                             3.07 (or higher)
    4                             4.07 (or higher)

 It is also possible to disable the VGA emulatoin on the ATI card
 by running SMS (ATI's configuration program) with the following
 paramiters:

             sms egabios   (to disable VGA)
             sms vgabios   (to enable VGA)

 For more information about the BIOS upgrade, contact ATI at the
 following phone number and address:

 (416) 576-0711
 ATI 3761 Victoria Park Ave.
 Unit #2
 Scarborough, Ontario, Canada
 M1W352


 105. BOA Demo Program Does Not Work on AT&T 6300 Computer

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | att
 Last Modified: 20-MAR-1990    ArticleIdent: Q51227

 BOA, the Microsoft Mouse Demo Program, does not work on an AT&T 6300
 computer: it begins to draw a border and then hangs. Otherwise, the
 mouse appears to function correctly.


 106. PC Tools Version 5.00 Needs Mouse Driver Version 6.14 or Later

 Product Version(s): 1.x 2.x 3.x 4.00 4.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 17-MAY-1989    ArticleIdent: Q42317

 PC Tools Version 5.00 documentation recommends Version 6.14 or later
 of the mouse driver.


 107. Mouse and Renaissance Legacy II Switch Graphics Adapter

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-MAR-1990    ArticleIdent: Q51240

 Problem:

 A serial mouse is installed on a computer with a Renaissance video
 card and the mouse driver reports that it is installed. However, the
 mouse does not respond in programs.

 Response:

 The Renaissance card has an InPort-type mouse adapter, which the mouse
 driver finds before it checks for a serial mouse.

 To correct this problem, include the /C1 or /C2 option on the mouse
 command line to specify where the mouse driver should look for the
 mouse. For example, do the following for COM1:

    mouse /C1


 108. Error in SIMPLE Mouse Menu in Programmer's Reference

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | docerr
 Last Modified: 22-MAR-1990    ArticleIdent: Q51489

 There is an error in the code for SIMPLE Mouse Menu on Page 74 of the
 "Microsoft Mouse Programmer's Reference Guide." The erroneous code
 reads as follows:

    dn:  TYPE 0,801       ;Down-arrow key

 It should read as follows:

    dn:  TYPE 0,80        ;Down-arrow key


 109. cegal() Function in EGA.LIB May Not Work Properly

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 16-APR-1990    ArticleIdent: Q43335

 When using cegal() in the EGA.LIB with Function f1, cegal() doesn't
 perform correctly. An example is shown below.

 Perform the following function in C

    outp(CRTC_INDEX,INDEX);

 where CRTC_INDEX is the port address and INDEX is the register.

 The mouse will not see the change in the EGA register; therefore, the
 above C call may cause the mouse to not perform properly because the
 call bypasses the BIOS routines.

 The following are two ways to perform this call so that the mouse will
 see the change in the EGA register:

 1. Use the EGA.LIB (this does not work):

          e1=0xf1;
          e2=0xd;
          e4=0;
          cegal(&e1,&e2,&e3,&e4,&e5);

 2. Use the equivalent BIOS call (this works):

          inregs.x.ax=0xf1;
          inregs.x.bx=0xd;
          inregs.x.dx=0;
          int86(0x10,&inregs,&outregs);


 110. NOTEPAD.COM Doesn't Work with Extended Keyboard

 Product Version(s): 1.00 1.01 2.00 2.01 2.50 3.00 4.00 5.00 5.02 5.03
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-JUN-1989    ArticleIdent: Q43336

 NOTEPAD.COM does not work with keyboards that have the extended
 function keys F11 and F12.

 No resolution to this limitation is expected because NOTEPAD.COM is
 no longer included with the mouse.


 111. Mouse and Token Ring Conflict

 Product Version(s): 7.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-MAR-1990    ArticleIdent: Q57606

 With the mouse driver installed first, Token Ring does not install
 properly.

 It has been reported that if the mouse driver was loaded after the
 three drivers that are needed for Token Ring, both will work properly.


 112. MS123.COM May Not Work in Lotus 1-2-3 with Look & Link Add-On

 Product Version(s): 1.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-JUN-1989    ArticleIdent: Q43600

 MS123.COM may not work properly in Lotus 1-2-3 if Look & Link (a Lotus
 1-2-3 add-on by Personics) is being used.

 The workaround is to load MOUSE.SYS in the CONFIG.SYS file instead of
 loading MOUSE.COM in the AUTOEXEC.BAT file.


 113. Microsoft Mouse and the NEC Powermate

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-JUN-1989    ArticleIdent: Q43720

 When using the NEC Powermate and the Microsoft Mouse with the Bus
 Interface, you must place the J3 jumper to the secondary setting. The
 Powermate can use the primary addressing for its screen I/O.


 114. MOUSE.COM Solves PS/2 Serial Problems with Ventura Publishing

 Product Version(s): 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 20-MAR-1990    ArticleIdent: Q43781

 Ventura Publisher uses its own mouse driver for the PS/2 - Serial
 mouse. For the bus mouse, Ventura requires the Microsoft Mouse driver
 (MOUSE.COM) to be loaded.

 If you are experiencing problems using a PS/2 - Serial mouse,
 reinstall Ventura and select the Bus Mouse option.  This will load
 the Microsoft Mouse Driver rather than the driver supplied by Ventura.
 The problems that your experienced with your PS/2-Serial mouse will
 no longer be present.  You DO NOT need to replace your PS/2-Serial
 mouse to choose the bus mouse option.  Selecting the Bus mouse option
 bypasses Ventura's own mouse drivers.



 115. Using the 400 PPI Mouse with GEM

 Product Version(s): 7.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 19-MAR-1990    ArticleIdent: Q59313

 When using the 400 PPI Serial Mouse with GEM, the mouse cursor jumps
 all over the screen.

 When installing GEM, select the Microsoft Bus Mouse option, even
 though you are using a serial mouse. When the bus mouse is selected
 during the installation process, GEM will use the Microsoft Mouse
 Driver that is supplied with the mouse.


 116. MS123 Mouse Menu Not Correctly Positioning Cursor

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 29-JUN-1989    ArticleIdent: Q44057

 If you position the Lotus cursor in 1-2-3 with the mouse cursor on an
 "unprotected cell," the Lotus cursor does not stay positioned on the
 cell selected by the mouse. The cursor jumps to the left or right,
 depending on which part of the cell the mouse cursor is located.

 If you position the Lotus cursor with the mouse cursor on "protected"
 cells, the cursor appears to stay positioned.

 One workaround in positioning the Lotus cursor with the mouse is to
 place the mouse cursor on the appropriate arrow keys that appear on
 the right side of the screen, or resort to using the keyboard cursor
 keys.


 117. Finding the COM1: Serial Port on a PC/XT/AT Machine

 Product Version(s): 1.00   | 1.00
 Operating System:   MS-DOS | OS/2
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q44126

 When connecting the Microsoft Mouse serial interface cable to your
 computer, you must first determine the location of the serial port.

 On a PC- or XT-class computer, the serial port is normally the male,
 25-pin, D-shaped connection in the back of the machine.

 On an AT-class computer, the serial connection is normally the male,
 9-pin, D-shaped connection on the back of the computer.

 There are exceptions, but these descriptions are a good rule of thumb.

 Note: If the machine has only one serial port, it should be set up as
 COM1: using IRQ4. If the serial port is set up as COM2: and it is the
 only serial port in the machine, the Microsoft Mouse driver might
 install, but the mouse might not function properly.

 COM3: and COM4: is not supported by the mouse driver.


 118. InPort/Bus Mouse Comparison and Overview

 Product Version(s): 1.00
 Operating System:   OS/2
 Flags: ENDUSER | SR# G890626-21385
 Last Modified: 31-AUG-1989    ArticleIdent: Q46369

 Question:

 Could you clarify the difference between the Microsoft Bus Mouse and
 the InPort Mouse?

 Response:

 The Microsoft InPort device interface is a low-cost graphic device
 interface consisting of a 40-pin custom LSI IC and a compact 9-pin
 circular connector, which supports a variety of graphic input devices,
 especially mice.

 The following is a comparison between old Bus Mouse and new InPort
 Mouse:

 1. The InPort Mouse uses a custom Microsoft designed 40-pin LSI
    interface chip manufactured by OKI Inc. of Japan.

    The Bus Mouse uses a generic Intel 8255A parallel interface chip.

 2. The InPort Mouse allows the CPU interrupt rate to be programmable
    from 0 (no interrupt) to 200 Hz.

     The Bus Mouse CPU interrupt rate is fixed at 30 Hz.

 3. The InPort Mouse interrupts the CPU only when the mouse position
    or button status has changed.

     The Bus Mouse interrupts the CPU constantly regardless of mouse
     (in)activity.

 4. The InPort Mouse requires only two I/O operations to read the mouse
    XY position.

    The Bus Mouse requires four I/O operations to read mouse XY
    position.

 5. The InPort Mouse uses the compact Hosiden 9-pin circular connector.

    The Bus Mouse uses the bulky DB-9 connector.

 When used stand-alone with an IBM XT/AT PC, both mice use an interface
 board that plugs into the standard IBM XT/AT bus. In addition, since
 the InPort custom IC is essentially an enhanced, single-chip version
 of the Microsoft Bus Mouse interface board, other manufacturers can
 easily add the InPort interface to their PC plug-in cards. The
 following are examples:

 1. The Microsoft MACH 10 enhancement board

 2. Renaissance GRX graphics add-in boards

 3. Selected Verticom graphics controllers/adapters come with an InPort
    interface.

 The InPort Mouse can also connect to an RS-232 serial port, or the
 IBM PS/2 mouse port through an external adapter box.


 119. Mouse Driver Conflicts with Novell Network Software

 Product Version(s): 7.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 22-MAR-1990    ArticleIdent: Q59314

 Using MOUSE.COM Version 7.00 may cause problems with Novell network
 software.

 Using MOUSE.SYS or loading MOUSE.COM before the network software will
 resolve the conflict.

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


 120. Mouse Performance between Serial and Bus Mouse

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00 1.01
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 31-AUG-1989    ArticleIdent: Q46461

 Summary

 Although there are no differences in functionality between the bus and
 serial mouse, you should be aware that there are differences in the
 way the mouse interrupts the CPU (i.e., the mouse driver must be
 installed).

 The serial mouse is event driven. This means when you neither move the
 mouse nor press a button (i.e., the mouse is not in use), there is no
 degradation to the CPU processing. When the mouse is being used, an
 approximately 5-percent degradation to the CPU performance can occur.

 The bus mouse is not event driven. When you neither move the mouse nor
 press a button, the mouse interrupts the CPU at either the default (30
 Hz) or at the user-defined rate (50, 100, or 200 Hz).


 121. Cadkey and Mouse Driver 7.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59859

 If Mouse Driver Version 7.00 is installed when Cadkey is used, the
 mouse is limited to a 1-inch x 1-inch area in the upper left-hand
 corner of the screen.

 Microsoft has confirmed this to be a problem in Mouse Driver Version
 7.00. This problem was corrected in Mouse Driver Version 7.04.


 122. Intermittent Installation on NEC 386 Machines

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59860

 Mouse Driver Version 7.00 causes intermittent installation of the
 mouse on the NEC 386 computers.

 Microsoft has confirmed this to be a problem with the Mouse Driver
 Version 7.00. This problem was corrected in Version 7.04.


 123. 400 DPI Serial Mouse and Northgate Computers

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  2-MAY-1990    ArticleIdent: Q59861

 When the 400 PPI PS/2/Serial Mouse is installed on the 9-pin serial
 port of some Northgate Computer, the mouse may not install.

 When the 400 PPI PS/2/Serial Mouse is installed on the 9-pin serial
 port as a serial mouse, it uses pins 2, 3, 4, 5, and 7 to communicate
 with the serial port.

 The other pins in the 9-pin connector are used when the PS/2 adapter
 is connected to the mouse. Pin 8 of the built-in serial port, when set
 to a logic zero, is 1 to 2 volts higher than the voltage that would be
 present on an IBM compatible serial port. When a logic 1 is present on
 pin 8 and the mouse is connected to a 9-pin serial port, the mouse
 cannot reset. This prevents the mouse from installing.

 To work around this problem, do either of the following:

 1. Contact Northgate Technical Services at (800) 445-5037. They have
    found the cause of the problem and will work with you to make the
    necessary corrections to the motherboard.

 2. Use a 9- to 25-pin serial adapter to eliminate the signal from pin
    8. To do this, you need to purchase the adapter from a local
    electronics store. This adapter has a 9-pin female connector on one
    end and a 25-pin male connector on the other end. Once you have the
    adapter perform the following steps:

    a. Attach the adapter you purchased to the built-in serial port of
       your computer.

    b. Attach the mouse to the 25- to 9-pin serial adapter that was
       supplied with your mouse.

    c. Attach this adapter to the 9- to 25-pin adapter that you have
       already attached to your computer.


 124. Mouse Function 9 and Mouse Driver 7.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59877

 Mouse Function 9 does not function correctly when Mouse Driver Version
 7.00 is installed. Vertical movement of the hot spot is blocked. The
 symptoms of this are as follows:

 1. The wrong menu item is selected when the mouse buttons are clicked.

 2. The line is drawn above the cursor in a graphics application

 Microsoft has confirmed this to be a problem in Mouse Driver Version
 7.00. This problem was corrected in Version 7.04.

 Major Products: First Publisher
                 Ultravision


 125. MSETUP Deletes Reference to MOUSE.SYS in CONFIG.SYS

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59929

 The MSETUP program that is supplied with the 400 PPI Mouse (Mouse
 Driver Version 7.00 or later) deletes any reference to MOUSE.SYS in
 the CONFIG.SYS file.

 If you are operating under OS/2, do NOT run MSETUP.

 MSETUP deletes the MOUSE.SYS reference in CONFIG.SYS to prevent the
 loading of a older version of the mouse driver when the machine is
 booted.

 Do not run MSETUP on an OS/2 system, and do not load the DOS mouse
 driver to make the mouse work in the DOS box.


 126. Which Mouse Menus Work with Which Version of Lotus

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59932

 Testing of the various versions of Lotus 1-2-3 with each of the
 available MS123 mouse menus and with either the Version 6.24b or
 Version 7.00 mouse driver yield the following results:

    Lotus     |  MS123       MS123-1     MS123-2     MS123-3
    Version   |  6.24b/7.00  6.24b/7.00  6.24b/7.00  6.24b/7.00
    ----------|-----------------------------------------------
      1A      |   yes/yes     yes/yes     yes/yes     yes/yes
              |     */*                                  /**
              |
      2.01    |   yes/yes     yes/yes     yes/yes     yes/yes
              |     */                       /**       **/**
              |
      2.2     |   yes/yes     yes/yes     yes/yes     yes/yes
              |     */*                                 */*
              |
      3.0     |    no/no       no/no       no/no      yes/yes
              |               ***/***     ***/***      **/**

 Notes: *   No mouse action on Master screen.
        **  No side bar menu.
        *** Cursor moves with mouse but no menu action.

 Summary of Normal Mouse Action (Yes in Above Chart)
 ---------------------------------------------------

 Usually, the mouse works in one of two ways: either the selected block
 moves around with the mouse movements, or a separate mouse cursor is
 on the screen and the selected block moves to the mouse cursor
 position upon clicking the left mouse button.

 In most cases, clicking the left mouse button activates a side bar
 menu with options such as page up, page down, page left, page right,
 home, end, and arrow key functions, and sometimes more (depends on the
 version of the menu).

 Also, in most cases, clicking the right mouse menu does the same as
 pressing the "/" (slash) key to bring up the standard Lotus menu.
 Moving the mouse changes the highlighted command. The right mouse
 button acts as an ENTER key. Clicking both buttons will return the
 mouse to the spreadsheet.


 127. Multimate Menu Will Work with Multimate Advantage 4.0

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  3-APR-1990    ArticleIdent: Q59934

 Informal testing with the Multimate Advantage II mouse menu has shown
 that it also works with Multimate Advantage Version 4.0.


 128. Pin-Outs of the 9-Pin Hosiden Socket

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified:  8-MAY-1990    ArticleIdent: Q61593

 The following is the signal configuration of the 9-pin Hosiden socket
 on the bus adapter of the Microsoft Mouse:

    Pin          Signal
    ---        ------

    1          +5v
    2           XA
    3           XB
    4           YA
    5           YB
    6           SW1
    7           SW2
    8           SW3
    9           Signal ground
    E           Shield ground


 129. Bus Mouse Port on Leading Edge 386 SX

 Product Version(s): 2.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 27-JUL-1990    ArticleIdent: Q64178

 The Leading Edge 386 SX computer has what appears to be a PS/2-style
 mouse port near the keyboard connector. This is actually an inport
 mouse connector designed for a Microsoft-compatible bus mouse,
 according to Page 6-13 of the "Leading Edge 386 SX User's Guide." The
 connection is a standard hosedin connector for an inport mouse.

 There is one switch that may or may not be in the correct position to
 install the mouse. This is Switch 3 on the motherboard. This must be
 in the ON position or the mouse will not install.


 130. Practical Peripherals and Serial Mouse Configuration

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | mouse modem practical peripherals
 Last Modified: 15-NOV-1990    ArticleIdent: Q66536

 If the Microsoft serial mouse is connected to COM 1, then a Practical
 Peripherals 2400 baud rate modem cannot be configured as COM 2.  This
 modem/mouse combination may work for a while, but eventually it
 will fail to an I/O address conflict between the mouse and the modem.

 Practical Peripherals technical support ([818] 991-8200)
 confirms this to be a problem.  They recommend that the modem be
 configured as COM 3 or COM 4.  The mouse should then remain on COM 1
 to separate the I/O addresses as much as possible.


 131. Serial Mouse with Timeline

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 13-JAN-1991    ArticleIdent: Q67339

 To use the Microsoft Serial Mouse with Timeline, a Symantec
 Corporation project management application, load the mouse driver by
 invoking MOUSE.SYS in the CONFIG.SYS file. Symantec Corporation
 technical support confirms that the Microsoft Mouse will not work
 correctly with Timeline if you use the MOUSE.COM driver file.


 132. 386MAX.SYS with MOUSE.COM 7.0 Can Hang Sprite Video Cards

 Product Version(s): 7.00 7.03 7.04
 Operating System:   MS-DOS
 Flags: ENDUSER | SR# S901024-6 B_BasicCom
 Last Modified: 15-NOV-1990    ArticleIdent: Q66561

 When used with 386MAX.SYS version 4.05 (an expanded memory driver by
 Qualitas Software), Microsoft Mouse driver versions 7.00, 7.03, and
 7.04 can hang computers equipped with video cards that have sprite
 capabilities (the ability to have a graphic cursor in text mode).

 This problem only occurs with the above mentioned versions. Earlier
 versions of the Microsoft Mouse driver will not cause this problem.

 Using Mouse driver version 7.04 with the "/y" line option will fix
 this problem.
 e.g.
     in DOS:

       mouse /y

  or in the AUTOEXEC.BAT:

       C:\MOUSE1\MOUSE /Y



 133. Correct Mouse Drivers for Express Publisher

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | driver mouse express publisher
 Last Modified: 13-JAN-1991    ArticleIdent: Q67340

 The application Express Publisher requires the 7.04 mouse
 driver to run correctly. Other mouse driver versions will not work
 according to the manufacturers, Power Up Software Corporation
 of San Mateo, CA.



 134. Trail of Multiple Cursors in Desqview 386

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | cursors trail mouse port setup
 Last Modified: 13-JAN-1991    ArticleIdent: Q67341

 If the Microsoft Serial Mouse is connected to a mouse port in a PS/2
 style machine, you may see a trail of red cursors inside the windows
 of Desqview 386 when you use QEMM 5.0.

 This is not a problem with the mouse. This problem occurs if you have
 selected "serial" in the port selection for the mouse when you set up
 Desqview. If you select "add-on board" for the mouse port selection in
 the Desqview Setup program, the mouse cursor will display normally.
 Note: This problem will not occur if the mouse is connected to the
 serial port.


 135. Mouse Menu Key Sequences: Corrections and Additions

 Product Version(s): 1.x 2.x 3.x 4.x 5.x 6.x 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | key sequence mouse menu docerr
 Last Modified: 10-FEB-1991    ArticleIdent: Q67854

 Page 71 of the "Microsoft Mouse Programmer's Reference Guide" lists
 "Key Sequences That Can't Be Simulated" using the menu programming
 TYPE statement. These keys cannot be simulated in a mouse menu because
 the key or key sequence is suppressed in the ROM BIOS. The list that
 is presented in the guide is incomplete, and in certain instances it
 is in need of revision.

 Each suppressed key mentioned is the lowercase character on the key.
 It is understood, but not explicitly stated, that the uppercase
 character on these keys will also be suppressed. A number of keys and
 key combinations that are suppressed and cannot be emulated are not
 mentioned in the guide. Some of the additions and corrections that can
 be made to the published list are given below.

 KEY COMBINATIONS FOR 83-KEY KEYBOARD
 ------------------------------------

 For the IBM PC and compatibles with a standard 83-key keyboard,
 the following keys and key combinations are suppressed.

 NOTE: Where applicable the uppercase character is given in
 parentheses.

 In Combination With the ALT Key
 -------------------------------

 RIGHT TAB
 ` (~)
 \ (|)
 ALT
 HOME
 PG UP
 NUMPAD 5
 NUMPAD
 +
 END
 PG DN
 INS
 DEL

 In Combination with the CTRL Key
 --------------------------------

 CTRL
 ` (~)
 NUMPAD 5
 NUMPAD
 +

 KEY COMBINATIONS FOR 84-KEY KEYBOARD
 ------------------------------------

 For the IBM AT and compatibles with a 84-key keyboard, the following
 keys and key combinations are suppressed:

 In Combination with the ALT Key
 -------------------------------

 ` (~)
 \ (|)
 TAB (right and left)
 ALT

 With ALT and on the Numeric Keypad
 ----------------------------------

 7 (HOME)
 1 (END)
 5
 0 (INS)
 9 (PG UP)
 3 (PG DN)
 - (SYS RQ)
 +

 In combination with the CTRL Key
 --------------------------------

 ENTER
 CTRL

 With CTRL and on the Numeric Keypad
 -----------------------------------

 5
 - (SYS RQ)
 +

 For the IBM PS/2 and compatibles with a 101- and 102-key keyboard, the
 following keys and key combinations are suppressed:

 In combination with the ALT key and on the Numeric Keypad
 ---------------------------------------------------------

 7 (HOME)
 1 (END)
 5
 0 (INS)
 9 (PG UP)
 3 (PG DN)
 - (SYS RQ)
 +

 In combination with the CTRL Key
 --------------------------------

 ` (~)
 CTRL
 ALT
 SCROLL LOCK

 With CTRL and on the Numeric Keypad
 -----------------------------------
 +

 EXCEPTIONS AND CORRECTIONS
 --------------------------

 The exceptions and corrections to the list of suppressed key and key
 combinations given on pages 71-72 of the "Microsoft Mouse Programmer's
 Reference" (Copyright 1989) are noted below.

 The followings key combinations can be represented using
 extended-keyboard-scan codes with the IBM PS/2 and compatibles with a
 101- and 102-key keyboard:

    ALT+BACKSPACE
    ALT+ESC
    CTRL+INS
    CTRL+TAB

 The ALT key used in combination with any one of the following keys can
 also be represented using extended-keyboard-scan codes for the IBM
 PS/2 and compatibles with a 101- and 102-key keyboard:

    [    ]
    ;
    '
    -
    ,
    .
    /
    *

 The CTRL key used in combination with the RIGHT ARROW and LEFT ARROW
 key can be represented on the PC, AT, and PS/2 keyboards.

 For more information about this topic, see "The Programmer's PC
 Sourcebook," pages 400-406; the "IBM PC/AT Technical Reference," pages
 4-21 and 5-14 to 5-23; and the "IBM PS/2 Hardware Technical
 Reference," pages 41-49.


 136. The Microsoft Mouse with Lotus 1-2-3 Release 3.1

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q67860

 You can use the Microsoft Mouse with Lotus 1-2-3 version 3.1. The
 mouse will work correctly with both the COM and SYS versions of the
 drivers. Correct mouse use in 1.2.3 release 3.1 depends on whether or
 not the memory resident formatting and printing utility WYSIWYG is
 properly installed and loaded into memory. Without installation and
 loading of WYSIWYG, no mouse cursor will appear on the normal Lotus
 1-2-3 screen. If you try use a previous Lotus 1-2-3 Microsoft Mouse
 menu or the generic MSMENU, Lotus will not work correctly (for
 example, you will get erratic highlights and no cursor).

 It appears that in some instances there is a problem with earlier
 versions of the mouse driver even when WYSIWYG is correctly installed
 and loaded. A possible solution is to update the mouse driver to
 MOUSE.COM version 7.04. Another possible solution is to load MOUSE.SYS
 version 7.04 with the CONFIG.SYS file.

 Correct use of the mouse in Lotus 1-2-3 version 3.1 depends on proper
 installation of WYSIWYG, correct hardware configuration, and the right
 operating environment.

 Installation
 ------------

 The following steps are necessary to ensure that the Microsoft Mouse
 will work with Lotus 1-2-3 version 3.1:

  1. Complete installation of the mouse hardware and software. Be sure
     the mouse driver is loaded into memory.

  2. Complete the first-time installation of Lotus 1-2-3 3.1. If you did
     not choose to have the WYSIWYG files transferred to the hard disk
     the first time, you must rerun the installation program from the
     hard disk and choose the option to transfer the WYSIWYG files to
     the hard disk.

  3. After completing the first installation of Lotus 3.1, put the
     Add-In Support Disk into drive A and type "install" (without the
     quotation marks) at the A:> prompt. The installation program will
     place the WYSIWYG files into the default directory C:\123R3\ADDINS.

  4. When this second "install" is complete, go to the C:\123R3
     subdirectory and type "123". This takes you into the normal Lotus
     screen.

  5. Press the ALT+F10 key combination. You will see the Addin menu in
     the Lotus menu bar area.

  6. From the Addin menu, choose Load.

  7. Specify WYSIWYG.PLC as the add-in to read into memory.

  8. Select No-Key.

  9. WYSIWYG is now in memory, and you have a mouse cursor.

 10. You can get the regular Lotus menus by selecting Quit or using the
     key combination CTRL+BREAK. You also may toggle between the Addin
     menu and the main Lotus menu by clicking the right mouse button.

 Hardware
 --------

 You must have a mouse and mouse driver as well as a graphics
 display monitor and a graphics display card. Lotus 1-2-3 3.1
 also requires at least a 286 microprocessor.

 Operating Environment
 ---------------------

 Lotus 1-2-3 3.1 requires MS-DOS version 3.00 or later. It will not run
 in the DOS compatibility box of OS/2; however, it will run after you
 choose the DOS dual-boot option from OS/2. Lotus 1-2-3 3.1 will run
 under the DOS option of Windows 3.00 or it can be installed as a
 Windows 3.00 application.

 Additional Tips
 ---------------

 Microsoft Mouse Driver versions 7.03 and 7.05 will return a white
 arrow graphics cursor in Lotus 1-2-3 3.11 while all other mouse driver
 versions will return a blue graphics cursor.

 To select an item from a menu you must point to the menu item desired
 and hold the left mouse button down. Then move the highlight to the
 sub-menu choice. When you release the mouse button, the item will be
 selected.

 In addition to normal mouse cursor movement, you may also move the
 mouse cursor by selecting the arrow icons on the right hand side of
 the 1-2-3 screen.


 137. Running MSETUP from Drive B

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | driver mouse install b: msetup
 Last Modified: 10-FEB-1991    ArticleIdent: Q67862

 When you run the Setup program from drive B, the message "please
 insert disk into drive A" may occur. You can temporarily force drive B
 to emulate drive A. Using the DOS ASSIGN command, type

    ASSIGN A=B

 at the C:\DOS> prompt. Then, run MSETUP from drive B. After rebooting
 the system, the drives will return to their normal configuration.



 138. 400 DPI Serial Mouse and Epson Equity LT 386/SX

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-FEB-1991    ArticleIdent: Q67863

 The 400 DPI serial mouse may not install on the 9-pin serial port of
 an Epson Equity LT 386/SX. Epson America has confirmed this and offers
 a patch for this problem. You can obtain this patch from your Epson
 dealer.

 Note: Not all Epson dealers may be aware of this problem, but they
 should be able to get the patch from their main Epson supplier.



 139. Quattro Pro 2.0 Graphics Mode Needs /Y Switch

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q68106

 Borland's Quattro Pro 2.0 requires mouse switch /Y when you run the
 7.04 mouse driver in graphics mode. This information is contained in
 the readme file that accompanies Quattro Pro 2.0.

 The graphics mode in Quattro Pro 2.0 is known as the "Annotate" mode.
 Owners of the Microsoft Mouse and Quattro Pro 2.0 also report that the
 earlier version 6.24b mouse driver will work in any mode of Quattro
 Pro 2.0. Borland recommends that you should not use a Microsoft Mouse
 driver earlier than version 6.10.


 140. I/O Addresses for the Microsoft Mouse

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q68110

 The following are the ranges in which an I/O (Input/Output) port
 assignment may occur for the Microsoft Mouse. The ranges are given in
 hexadecimal numbers, and the serial communications port assignments
 conform to the IBM standard I/O address range assignments for PCs and
 PS/2s.

 SERIAL MOUSE
 ------------

 Port Assignments    Address Ranges
 ----------------    --------------

 COM1                3F8H-3FFH

 COM2                2F8H-2FFH

 BUS MOUSE (BUS INTERFACE BOARD SETTINGS)
 ----------------------------------------

 Primary Inport Range
 --------------------

 23CH-23FH

 Secondary Inport Range
 ----------------------

 238H-23BH

 An I/O port acts as a doorway through which information travels.
 Information may originate from the CPU, travel over data and address
 buses, pass through the I/O port, and finally reach a peripheral
 device such as the mouse. Although the CPU recognizes various ports
 through 16-bit port numbers that range from 00H through FFFFH, the
 port address is not actually an address found in main memory. A port
 assignment is a memory location separate from a (main) memory address
 that is associated with that particular I/O port.

 No other peripheral device, such as a modem or printer, may share the
 same I/O address with the mouse or the mouse may not function
 correctly.


 141. Pascal Example in Programmer's Guide Won't Compile

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | Pascal Mouse Programming Borland Turbo
 Last Modified: 11-FEB-1991    ArticleIdent: Q68881

 The "Making Calls from Borland Turbo Pascal Programs" sample in
 Appendix E of the "Microsoft Mouse Programmer's Reference" does not
 compile with Turbo Pascal versions 5.0 and 6.0.

 The CpuReg data structure needs to be defined as "Registers"
 variables. The semicolons need to be removed from the END lines that
 immediately precede ELSE. Finally, finding the segment and offset of
 the pointer of the address of the user array or subroutine (functions
 9,12,20,22,23,and 24) needs to be done outside of this procedure.
 Passing the first element of the array or the start point of the
 subroutine into the procedure, then calling the "ofs" and "seg"
 functions in the procedure doesn't seem to work. This is due to how
 the variables get dereferenced when passed into a procedure.

 The following example compiles in both Turbo Pascal version
 6.0 and Quick Pascal version 1.00:

 Procedure Mouse (Var m1, m2, m3, m4, m5 : integer );

 Var
    CpuReg: Registers;

 begin {mouse}

    if m1 >= 0 then
       begin
      CpuReg.AX := m1;        { Load Parameters       }
      CpuReg.BX := m2;        { into appropriate      }
      CpuReg.CX := m3;        { registers             }

      if (m1 = 9) or (m1 = 12) or (m1 = 20)
         or (m1 = 22) or (m1 = 23) or (m1 = 24) then
         begin
           CpuReg.DX  :=  m4;    {m4 = offset,         }
           CpuReg.ES  :=  m5;    { and m5 = segment    }
         end                       { of the user array }
                          { or subroutine     }

       else
       if  m1 = 16  then
        begin
          CpuReg.CX  := m2;           {Left  x coordinate }
          CpuReg.DX  := m3;           {Upper y coordinate }
          CpuReg.SI  := m4;           {Right x coordinate }
          CpuReg.DI  := m5;           {Lower y coordinate }
        end
      else
          CpuReg.DX  := m4;

      Intr($33, CpuReg);              {Call mouse driver  }
                             { at Interrupt 33H  }

      m1 := CpuReg.AX;                {Return values back }
      m2 := CpuReg.BX;                { to parameters     }
      m3 := CpuReg.CX;
      m4 := CpuReg.DX;

      if (m1 = 20) then               {special returns    }
         m2 := CpuReg.ES              { from subroutines  }
    end;
 end; {mouse}


 142. CADKEY Requires Microsoft Mouse Driver Version 7.04

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | AutoCAD EasyCAD FastCAD VersaCAD
 Last Modified: 10-FEB-1991    ArticleIdent: Q68930

 The CAD software package CADKEY requires that the Microsoft Mouse
 driver be updated to version 7.04 to run properly. Earlier
 versions of the driver, such as version 7.00, will not allow you to
 operate the mouse correctly in this software. In one instance, the
 cursor is confined to a small area of the upper-left-hand corner of
 the screen.

 CADKEY is produced and marketed by CADKEY Inc. The technical support
 number is (203) 647-9235. The CADKEY Inc. product referenced here is
 manufactured by vendors independent of Microsoft; we make no warranty,
 implied or otherwise, regarding the product's performance or
 reliability.


 143. Using the Microsoft Mouse with Open Access III

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q68931

 The Microsoft Mouse can be successfully used with the application Open
 Access III by performing the following steps:

 1. Copy the Open Access III files MMENU.DEF and MMENU.MNU to the
    MOUSE1 subdirectory.

 2. Copy the file MENU.COM to the MOUSE1 subdirectory.

 3. Load the Microsoft Mouse driver.

 4. Go to the MOUSE1 subdirectory and type:

       MENU MMENU

    You should get a "Menu Installed" message.

 5. Go to the Open Access III subdirectory and start the Open Access
    III program.

 If this sequence does not work, you may have problems with memory
 resident software. In which case, perform the above steps after doing a
 "clean boot" with a copy of the original DOS floppy disk.

 You may obtain the MENU.COM program by calling Microsoft Product
 Support (Hardware).

 Open Access III is an integrated function application that combines a
 database, a word processor, and a spreadsheet into one application.
 The product is developed and marketed by Software Products
 International. The technical support number is (800) 937-4774.

 The Software Products International product referenced here is
 manufactured by a vendor independent of Microsoft; we make no
 warranty, implied or otherwise, regarding the product's performance or
 reliability.


 144. False Cursor Trail in SimEarth with Mouse Driver 7.00

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q68932

 Microsoft Mouse Driver version 7.00 displays a false cursor trail in
 the planet simulation program SimEarth. You may temporarily correct
 this problem by using a /B switch when loading SimEarth (that is
 SimEarth /B).

 For a permanent fix you can obtain an updated mouse driver from Microsoft
 Product Support or Microsoft Customer Service.

 More info:

 SimEarth is developed and marketed by Maxis. The technical support
 number is (415) 376-6434. The Maxis product referenced here is
 manufactured by a vendor independent of Microsoft; we make no
 warranty, implied or otherwise, regarding the product's performance or
 reliability.


 145. Microsoft Mouse Incompatible with Commodore PC 40-III

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 10-FEB-1991    ArticleIdent: Q68953

 The Commodore PC 40-III and PC 10-III may not work with the Microsoft
 Serial Mouse. The mouse port for these machines is not designed to
 function with the Microsoft Mouse.

 You may obtain further information and assistance by calling Commodore
 technical support at (703) 644-4170. The Commodore product referenced
 here is manufactured by a vendor independent of Microsoft; we make no
 warranty, implied or otherwise, regarding this product's performance
 or reliability.


 146. Using a Bus Mouse on a Tandy 1000

 Product Version(s): 1.x 6.x 7.x
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 12-FEB-1991    ArticleIdent: Q68955

 When using a bus mouse on a Tandy 1000 computer, you may not be able
 to run the mouse on IRQ2. A better choice may be IRQ5, even though the
 computer may have a hard drive.

 The early models of the Tandy 1000 used IRQ2 for a hard card, which
 may have been optionally installed. These models included the Tandy
 1000, Tandy 1000A, Tandy 1000SX, and Tandy 1000TX.

 Later models used IRQ5 for hard cards. These models included the
 Tandy 1000SL, Tandy 1000SL/2, Tandy 1000TL, and Tandy 1000TL/2.


 147. WordPerfect 5.1 and WordStar 6.0 Mouse Support

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | word processor
 Last Modified: 10-FEB-1991    ArticleIdent: Q68956

 WordPerfect version 5.1 incorporates Microsoft Mouse support; however,
 WordStar versions 5.5 and 6.0 do not. The following information
 identifies whether or not a menu is needed to use the Microsoft Mouse
 with WordStar or WordPerfect.

 Product                  Description
 -------                  -----------

 WordStar version 6.0     Not Microsoft Mouse aware: see below note
 WordStar version 5.5     Not Microsoft Mouse aware: uses MSWS5.COM
 WordPerfect version 5.1  Microsoft Mouse aware: no menu needed
 WordPerfect version 5.0  Not Microsoft Mouse aware: uses MSWP5.COM

 Note:
 WordStar 6.0 sometimes works with MSWS5.  But we do not gurantee this
 version to work with WS 6.0.

 It is important to learn how the built-in mouse menus in WordPerfect
 version 5.1 work. In color modes, the normal cursor is a rectangular
 red text cursor. A right-button click causes a menu line to appear at
 the top of the screen. Then, by clicking and holding the left mouse
 button, you may drag the highlight down the chosen drop-down menu to
 make the desired menu selection.

 The products referenced here are manufactured by vendors independent
 of Microsoft; we make no warranty, implied or otherwise, regarding
 these products' performance or reliability.


 148. Using MSMENU.COM with ACT! version 2.0

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER |
 Last Modified: 11-FEB-1991    ArticleIdent: Q68958

 You can use the Microsoft Mouse with ACT! version 2.0. In order to use
 the mouse correctly, you must first load the generic menu DEFAULT.COM
 or MSMENU.COM. Appendix H-1 of the ACT! "Reference Manual" specifies
 DEFAULT.COM, but the more current MSMENU.COM or MENU.COM work as well.

 Copy one of these files to the ACT! subdirectory. The directions for
 ACT! specify that you:

 1. Load the mouse.

 2. In the subdirectory in which ACT! is installed, type "MSMENU MSACT"
    (without the quotation marks).

 3. After the menu is loaded in this way, type "ACT!" (without the
    quotation marks). You will now have the use of the mouse in ACT!

 The file MSACT.MSE is a menu file that comes with ACT!. If the mouse
 and menu are loaded properly, then the mouse should give basic cursor
 movement with the buttons serving the following functions:

    Button                   Function
    ------                   --------

    Left Button Click        Same as ENTER
    Right Button Click       Same as F2 (edit mode)
    Both Buttons Click       Same as ESC

 Note: These button assignments may not work properly in DOS 4.00.

 If you do not have a copy of MSMENU.COM, you may obtain a copy by
 calling Microsoft Customer Service or Product Support and ordering
  "The Microsoft Mouse Supplemental Menus Disk."

 ACT! is a database software program that helps keep track of business
 contacts. ACT! is developed and marketed by Contact Software
 International. The technical support number is (214) 418-4885. The
 Contact Software International product referenced here is
 manufactured by a vendor independent of Microsoft; we make no
 warranty, implied or otherwise, regarding this product's performance
 or reliability.


 149. NEC Mouse Port, Lotus 3.1, and Microsoft Serial Mouse

 Product Version(s): 1.00
 Operating System:   MS-DOS
 Flags: ENDUSER | NCR
 Last Modified: 10-FEB-1991    ArticleIdent: Q68959

 The mouse cursor may freeze when you use the Microsoft Mouse in the
 PS/2 mouse port of some of the NEC 286 and 386 machines while running
 the WYSIWYG mode of Lotus 1-2-3 version 3.1. Contact NEC technical
 support at (508) 264-4300 for more information.

 The products included here are manufactured by vendors independent of
 Microsoft; we make no warranty, implied or otherwise, regarding the
 products' performance or reliability.


