
From jeffrey@carlyle.com Mon May  3 19:22:29 1999
From: jeffrey@carlyle.com (Jeffrey Carlyle)
Newsgroups: comp.os.msdos.programmer,alt.msdos.programmer,comp.answers,alt.answers,news.answers
Subject: comp.os.msdos.programmer FAQ part 3/5
Supersedes: <msdos-programmer-faq/part3_919862829@rtfm.mit.edu>
Followup-To: comp.os.msdos.programmer
Date: 23 Apr 1999 13:34:25 GMT
Organization: Jeffrey Carlyle World Domination
Lines: 956
Sender: jeffrey@carlyle.com (Jeffrey Carlyle)
Approved: news-answers-request@MIT.Edu
Expires: 27 May 1999 13:32:46 GMT
Message-ID: <msdos-programmer-faq/part3_924874366@rtfm.mit.edu>
References: <msdos-programmer-faq/part1_924874366@rtfm.mit.edu>
Reply-To: jeffrey@carlyle.com (Jeffrey Carlyle)
NNTP-Posting-Host: penguin-lust.mit.edu
Summary: Frequently asked questions by DOS programmers with tested answers.
X-Last-Updated: 1999/01/05
Originator: faqserv@penguin-lust.MIT.EDU
Path: news.nic.utwente.nl!news.cs.utwente.nl!newshunter!cosy.sbg.ac.at!newsmaster-01.vbs.at!news.datacomm.ch!newsfeed-zh.ip-plus.net!news.ip-plus.net!news-zh.switch.ch!news-ge.switch.ch!newsfeed.berkeley.edu!nntp.primenet.com!newsfeed.enteract.com!cde.net!sipb-server-1.mit.edu!sipb-server-2.mit.edu!senator-bedfellow.mit.edu!faqserv
Xref: news.nic.utwente.nl comp.os.msdos.programmer:80558 alt.msdos.programmer:38293 comp.answers:32021 alt.answers:37089 news.answers:72409

Archive-name: msdos-programmer-faq/part3
Comp-os-msdos-programmer-archive-name: dos-faq-pt3.txt
Posting-frequency: 56 days
Last-modified: 05 Jan 99


------------------------------

Subject: comp.os.msdos.programmer FAQ
Date: Sun, 03 Jan 99 17:46:33 CST
 
 comp.os.msdos.programmer FAQ Version 1999.01

 This is the Frequently Asked Questions list for the newsgroup
 comp.os.msdos.programmer. This message is part 3 of 5 parts.
 
 Copyright  1999  by  Jeffrey Carlyle. All rights  reserved.  This
 article  is not in the public domain, but it may be redistributed
 so  long as this notice, the acknowledgments, and the information
 on obtaining the latest copy of this list are retained and no fee
 is  charged. The code fragments may be used freely; credit to the
 FAQ would be polite. This FAQ is not to be included in any static
 archive (e.g. CD-ROM or book); however, a pointer to the FAQ  may
 be included.
 

------------------------------

Subject: Table of Contents
Date: Sun, 03 Jan 99 17:46:33 CST
 
=============================
TABLE OF CONTENTS
=============================
 
Part 1: <first file>
  Section 1.  General FAQ and Newsgroup Information
    <Q:01.01> - Is MS-DOS dead?
    <Q:01.02> - What is this article for?
    <Q:01.03> - Who has contributed to this article?
    <Q:01.04> - How can I search this article for a particular topic?
    <Q:01.05> - Are the answers guaranteed to be correct and complete?
    <Q:01.06> - What is comp.os.msdos.programmer about?
    <Q:01.07> - Is comp.os.msdos.programmer just for C programmers?
    <Q:01.08> - What is comp.sys.ibm.pc.programmer?
    <Q:01.09> - Is  comp.os.msdos.programmer available as a  mailing list?
    <Q:01.10> - What's this "netiquette"?
    <Q:01.11> - How can I learn more about Usenet?
    <Q:01.12> - What other technical newsgroups should I know about?
    <Q:01.13> - Where are FAQ lists archived?
    <Q:01.14> - Where can I get the latest copy of this FAQ list?
  Section 2.  General Reference
    <Q:02.01> - Are there any good on-line references for PC hardware
                components?
    <Q:02.02> - Are there any good on-line references for PC interrupts?
    <Q:02.03> - What and where is "Ralf Brown's interrupt list"?
    <Q:02.04> - Where can I find lex, yacc, and language grammars?
    <Q:02.05> - What's the best book to learn programming?
    <Q:02.06> - Why won't my code work?
    <Q:02.07> - Are there any good sources of example code?
    <Q:02.08> - What and where is "SNIPPETS"?
    <Q:02.09> - Is the source code MS-DOS available?
    <Q:02.10> - What are my alternatives for MS-DOS compatible OSes?
    <Q:02.11> - What and where is "FreeDOS?"
    <Q:02.12> - What and where is "Caldera DR-DOS"?
Part 2: <second file>
  Section 3.  Compile and Link
    <Q:03.01> - What the heck is "DGROUP > 64K"?
    <Q:03.02> - How  do I fix "automatic data segment exceeds 64K" or "stack
                plus data exceed 64K"?
    <Q:03.03> - Will Borland C code and Microsoft C code link together?
    <Q:03.04> - Why  did  my program bomb  at run time with "floating point
                formats not linked" or "floating point not loaded"?
    <Q:03.05> - How can I change the stack size in Borland's C compilers?
    <Q:03.06> - What's the format of an .OBJ file?
    <Q:03.07> - What's the format of an .EXE header?
    <Q:03.08> - What's  the difference between .COM and .EXE formats?
    <Q:03.09> - How do I create a .COM file?
    <Q:03.10> - Where is EXE2BIN located?
    <Q:03.11> - What does this message mean: "A20 already enabled so test
                is meaning less?"
  Section 4.  Keyboard
    <Q:04.01> - How can I read a character without echoing it to the screen,
                and without waiting for the user to press the Enter key?
    <Q:04.02> - How can I find out whether a character has been typed, without
                waiting for one?
    <Q:04.03> - How can I disable Ctrl-C/Ctrl-Break and/or Ctrl-Alt-Del?
    <Q:04.04> - How can I disable the print screen function?
    <Q:04.05> - How  can  my  program turn NumLock (CapsLock, ScrollLock)
                on or off?
    <Q:04.06> - How can I speed up the keyboard's auto-repeat?
    <Q:04.07> - What is the SysRq key for?
    <Q:04.08> - How can my program tell what kind of keyboard is on the
                system?
    <Q:04.09> - How can I tell if input, output, or stderr has been redirected?
    <Q:04.10> - How can I increase the size of the keyboard buffer?
    <Q:04.11> - How can I stuff characters into the keyboard buffer?
Part 3: <this file>
  Section 5.  Disks and files
    <Q:05.01> - What drive was the PC booted from?
    <Q:05.02> - How can I boot from drive B:?
    <Q:05.03> - Which real and virtual disk drives are valid?
    <Q:05.04> - How can I make my single floppy drive both A: and B:?
    <Q:05.05> - How can I disable access to a drive?
    <Q:05.06> - How can a batch file test existence of a directory?
    <Q:05.07> - Why won't my C program open a file with a path?
    <Q:05.08> - How can I redirect printer output to a file?
    <Q:05.09> - How can I redirect the output of a batch file?
    <Q:05.10> - How can I redirect stderr?
    <Q:05.11> - How can my program open more files than DOS's limit of 20?
    <Q:05.12> - How can I read, create, change, or delete the volume label?
    <Q:05.13> - How can I get the disk serial number?
    <Q:05.14> - What's the format of .OBJ, .EXE, .COM files?
    <Q:05.15> - How can I flush the software disk cache?
    <Q:05.16> - How can I see if a drive is a RAM drive?
  Section 6.  Serial ports (COM ports)
    <Q:06.01> - How do I set my machine up to use COM3 and COM4?
    <Q:06.02> - How do I find the I/O address of a COM port?
    <Q:06.03> - But aren't the COM ports always at I/O addresses 3F8, 2F8,
                3E8, and 2E8?
    <Q:06.04> - How do I configure a COM port and  use  it  to transmit data?
Part 4: <fourth file>
  Section 7.  Other hardware questions and problems
    <Q:07.01> - Which 80x86 CPU is running my program?
    <Q:07.02> - How can a C program send control codes  to  my printer?
    <Q:07.03> - How can I redirect printer output to a file?
    <Q:07.04> - Which video adapter is installed?
    <Q:07.05> - How do I switch to 43- or 50-line mode?
    <Q:07.06> - How can I find the Microsoft mouse position and button status?
    <Q:07.07> - How can I access a specific address in the PC's memory?
    <Q:07.08> - How can I read or write my PC's CMOS memory?
    <Q:07.09> - How can I access memory beyond 640K?
    <Q:07.10> - How can I use the protected mode?
    <Q:07.11> - How can I tell if my program is running on a
                PS/2-style machine.
    <Q:07.12> - Is there a 80x87 math unit installed?
  Section 8.  Other software questions and problems
    <Q:08.01> - How can a program reboot my PC?
    <Q:08.02> - How can I time events with finer resolution than the system
                clock's 55 ms (about 18 ticks a second)?
    <Q:08.03> - How can I find the error level of the previous program?
    <Q:08.04> - How can a program set DOS environment variables?
    <Q:08.05> - How can I change the switch character to - from /?
    <Q:08.06> - How can I write a TSR (terminate-stay-resident utility)?
    <Q:08.07> - Why does my interrupt function behave strangely?
    <Q:08.08> - How can I write a device driver?
    <Q:08.09> - What can I use to manage versions of software?
    <Q:08.10> - What's this "null pointer assignment" after my C
                program executes?
    <Q:08.11> - How can a batch file tell whether it's being run in a DOS box
                under Windows?
    <Q:08.12> - How can my program tell if it's running under Windows?
    <Q:08.13> - How can a program tell whether ANSI.SYS is installed?
    <Q:08.14> - How do I copyright software that I write?
Part 5: <fifth file>
  Section 9.  Downloading
    <Q:09.01> - What are SimTel, Garbo, and Wustl?
    <Q:09.02> - Can I get archives on CD-ROM?
    <Q:09.03> - Where do I find program <mumble>?
  Section 10. Vendors and products
    <Q:10.01> - How can I contact Borland?
    <Q:10.02> - How can I contact Microsoft?
    <Q:10.03> - What's the current version of UNZIP?
    <Q:10.04> - What is the phone number for a vendor's BBS?
    <Q:10.05> - What is the current version of DJGPP?
    <Q:10.06> - What and where is DJGPP?
    <Q:10.07> - Are there any good shareware/freeware compilers?
    <Q:10.08> - Is the source code to MS-DOS available?
    <Q:10.09> - What is a vendor's web site address?


------------------------------

Subject: Section 5.  Disks and files
Date: Mon, 04 Jan 99 10:49:58 CST

 Information about accessing disks and files from MS-DOS.
 

------------------------------

Subject: <Q:05.01> - What drive was the PC booted from?

 Under DOS 4.0 or later, use INT 21 AX=3305.  DL is returned
 with an integer indicating the boot drive (1=A:, etc.).
 

------------------------------

Subject: <Q:05.02> - How can I boot from drive B:?
Date: Sun, 03 Aug 97 20:07:24 CST

 Downloadable shareware:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/diskutil/boot_b.zip>
   <ftp://garbo.uwasa.fi/pc/bootutil/boot_b.zip>
 
 The  included documentation says it works by writing a  new
 boot  sector on a disk in your a: drive that redirects  the
 boot to your B: drive.  (A similar utility is bboot.zip  in
 the same directory at Garbo only.)
 
 If  that  doesn't work, you can always interchange your  A:
 and  B: drives by switching ribbon cables and changing  the
 setup in your BIOS.  From an article posted 27 Jan 1993  on
 another newsgroup:
 
 [begin quotation]
   Take  the  "ribbon" connector, as you call it, and  switch
   them.  To double-check, start at the end of the cable that
   connects to the motherboard or floppy controller.   Follow
   the  cable until you get to the first connector.   Connect
   this to the drive you want to be B:.
  
   After this, there should be a few lines on the cable  that
   get flipped left to right.  (On most cables, they just cut
   the lines and physically reverse them.  It should be quite
   obvious from looking at the cable.)  Anyway, the connector
   after  the pins get flipped right to left is the connector
   for your a: drive.
 [end quotation]


------------------------------

Subject: <Q:05.03> - Which real and virtual disk drives are  valid?
Date: Wed, 11 Jan 95 15:34:00 CDT
 
 Use  INT 21 AH=29 (parse filename).  Point DS:SI at a null-
 terminated ASCII string that contains the drive letter  and
 a  colon,  point ES:DI at a 37-byte dummy FCB  buffer,  and
 call  INT 21 AX=2900.  On return, AL is FF if the drive  is
 invalid,  something else if the drive is valid.  RAM  disks
 and SUBSTed drives are considered valid.
 
 You  can detect whether the drive is ASSIGNed by using  INT
 2F AX=0601.  To check whether the drive is SUBSTed, use INT
 21  AX=4409;  or use INT 21 AH=52 to test for both JOIN and
 SUBST.  See Ralf Brown's interrupt list <Q: 2.03>.
 
 Unfortunately, the b: drive is considered valid even  on  a
 single-diskette system.  You can check that special case by
 interrogating the BIOS equipment byte at 0040:0010.  Bits 7-
 6  contain the one less than the number of diskette drives,
 so  if  those bits are zero you know that b: is an  invalid
 drive even though function 29 says it's valid.
 
 Following  is some code originally posted by Doug Dougherty
 to test valid drives (treating SUBSTed and JOINed drives as
 valid),  with  my  fix for the b: special case,  tested  in
 Borland C++ 4.5 (in the large model):
 
   #include <dos.h>
   #include <stdio.h>
   
   void drvlist(void)
   {
     char s[3] = "A:", fcb_buff[37];
     int valid;

     for( ;  *s<='Z';  (*s)++)
     {
       _SI = (unsigned) s;
       _DI = (unsigned) fcb_buff;
       _ES = _DS;
       _AX = 0x2900;

       geninterrupt(0x21);
       valid = _AL != 0xFF;

       if (*s == 'B'  &&  valid)
       {
         char far *equipbyte = (char far *)0x00400010UL;
         valid = (*equipbyte & (3 << 6)) != 0;
       }

       printf("Drive '%s' is %sa valid drive.\n", s, valid ? "" : "not ");
     }
   }
 
 This  code was translated to MSC 7.0 and tested it in small model:

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

   void drvlist(void)
   {
     char s[3] = "A:", fcb_buff[37], *buff=fcb_buff;
     int valid;

     for (   ;  *s<='Z';  (*s)++)
     {
       __asm mov si,s      __asm mov di,buff
       __asm mov ax,ds     __asm mov es,ax
       __asm mov ax,0x2900 __asm int 21h
       __asm xor ah,ah     __asm mov valid,ax

       valid = (valid != 0xFF);

       if (*s == 'B'  &&  valid)
       {
         char far *equipbyte = (char far *)0x00400010UL;
         valid = (*equipbyte & (3 << 6)) != 0;
       }

       printf("Drive '%s' is %sa valid drive.\n", s, valid ? "" : "not");
     }
   }


------------------------------

Subject: <Q:05.04> - How can I make my single floppy drive both a: and b:?
 
 Under  any  DOS  since DOS 2.0, you can put  the  following
 command into your AUTOEXEC.BAT file:
 
   assign b=a
 
 Then,  when  you  type "dir b:" you'll no  longer  get  the
 annoying  prompt to insert diskette B (and  the  even  more
 annoying  prompt to insert A the next time  you  type  "dir
 a:").
 
 You  may  be wondering why anybody would want to  do  this.
 Suppose  you use two different machines, maybe one at  home
 and  one  at  work.  One of them has only a  3.5"  diskette
 drive; the other machine has two drives, and b: is the 3.5"
 one.   You're bound to type "dir b:" on the first one,  and
 get the nuisance message:
 
   Insert diskette for drive B: and press any key when ready.
 
 But  if you assign drive b: to point to a:, you avoid  this
 problem.
 
 Caution:  there are a few commands, such as DISKCOPY,  that
 will not work right on ASSIGNed or SUBSTed drives.  See the
 DOS  manual for the full list.  Before typing one of  those
 commands,  be  sure  to  turn off  the  mapping  by  typing
 "assign" without arguments.
 
 The  DOS  5.0  manual  says that ASSIGN  is  obsolete,  and
 recommends  the equivalent form of SUBST: "subst  b:  a:\".
 Unfortunately, if this command is executed when a:  doesn't
 hold  a  diskette, the command fails.  ASSIGN doesn't  have
 this  problem,  so under DOS 5.0 you should disregard  that
 particular bit of advice in the manual.
 

------------------------------

Subject: <Q:05.05> - How can I disable access to a drive?
Date: Sun, 03 Aug 97 20:08:47 CST
 
 Reader  Eric  DeVolder writes that he has made available  a
 program  to  do  this.   I  haven't  tried  it,  but   it's
 downloadable as
 
 <ftp://ftp.simtel.net/pub/simtelnet/msdos/diskutil/rmdriv30.zip>
 
 Reader  Igor  Karp  reports that  MS-DOS  version  5.0  and
 greater provides two interrupts to do this.
 
   --------D-215F07-----------------------------
   INT 21 - DOS 5+ - ENABLE DRIVE
      AX = 5F07h
      DL = drive number (0=A:)
   Return: CF clear if successful
      CF set on error
      AX = error code (0Fh) (see #0885 at AH=59h)
   Notes:   simply  sets the "valid" bit in the  drive's  CDS
   this function is not supported by Novell DOS 7
   See Also: AH=52h,AX=5F08h"DOS"

   --------D-215F08-----------------------------
   INT 21 - DOS 5+ - DISABLE DRIVE
      AX = 5F08h
      DL = drive number (0=A:)
   Return: CF clear if successful
      CF set on error
      AX = error code (0Fh) (see #0885 at AH=59h)
   Notes:   simply clears the "valid" bit in the drive's  CDS
   this function is not supported by Novell DOS 7


------------------------------

Subject: <Q:05.06> - How can a batch file test existence of a directory?
Date: Tue, 7 Mar 95 12:00:00 CDT
 
 The  standard way, which in fact is documented in  the  DOS  manual, is:
   if exist d:\path\nul goto found
 
 Unfortunately, this is not entirely reliable.  I  found  it
 failed  in  Pathworks  (a/k/a  PCSA,  DEC's  network   that
 connects PCs and VAXes), or on a MARS box that uses an  OEM
 version  of MS-DOS 5.0. Readers have reported that it  gave
 the  wrong answer on Novell networks, on DR-DOS, and  in  a
 DOS  window under OS/2.  By "failed" I mean that it "found"
 a  directory that didn't exist, or failed to find one  that
 did  exist, or both.  (It has been reported that IBM fixed
 the OS/2 bug in version 2.11 of OS/2.) As a legacy from
 earlier versions of DOS it always succeeds if the path is DEV.
 
 There  appears  to be no foolproof way to  use  pure  batch
 commands  to test for existence of a directory.   The  real
 solution is to write a program, which returns a value  that
 your  batch  program can then test with an "if errorlevel".
 Reader  Duncan  Murdoch kindly posted the  following  Turbo
 Pascal version:
 
   program existdir;
   { Confirms  the  existence of a directory  given  on  the
     command  line.  Returns errorlevel 2 on error,  1  if  not
     found, 0 if found. }
  
   uses dos;
  
   var
     s : searchrec;
  
   begin
     if paramcount <> 1 then
       begin
         writeln('Syntax:  EXISTDIR directory');
         halt(2);
       end
     else
       begin
         findfirst(paramstr(1),Directory,S);
         while (Doserror = 0) and ((Directory and S.Attr) =  0) do
           findnext(S);
  
        if Doserror <> 0 then
          begin
            Writeln('Directory not found.');
            halt(1);
          end
        else
          begin
            Writeln('Directory found.');
            halt(0);
          end;
       end;
   end.
 
 Timo  Salmi  also has a Turbo Pascal version in  his  Turbo
 Pascal FAQ, which is downloadable as (Where ?? is the current
 version of the file.):
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/info/tsfaqp**.zip>
   <ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip>


------------------------------

Subject: <Q:05.07> - Why won't my C program open a file with a path?
 
 You've probably got something like the following code:
   
   char *filename = "c:\foo\bar\mumble.dat";
   FILE *fptr;
   /*.*/
   fptr = fopen(filename, "r");
 
 The  problem is that \f is a form feed, \b is a  backspace,
 and  \m  is m.  Whenever you want a backslash in  a  string
 constant in C, you must use two backslashes:
   char *filename = "c:\\foo\\bar\\mumble.dat";
 
 This  is  a  feature  of every C compiler,  because  Dennis
 Ritchie designed C this way.  It's a problem only on MS-DOS
 systems,  because  only DOS (and Atari ST/TT  running  TOS)
 uses  the  backslash in directory paths.  But even  in  DOS
 this   backslash  convention  applies  _only_   to   string
 constants in your source code.  For file and keyboard input
 at run time, \ is just a normal character, so users running
 your  program would type in file specs the same way  as  in
 DOS commands, with single \ characters.
 
 Another possibility is to code all paths in source programs
 with / rather than \ characters:
   char *filename = "c:/foo/bar/mumble.dat";
 
 Ralf  Brown writes, "All versions of the DOS kernel  accept
 either  forward or backslashes as directory separators.   I
 tend  to  use  this  form more frequently than  backslashes
 since it is easier to type and read."  This applies to  DOS
 function calls (and therefore to calls to the file  library
 of every programming language), but not to DOS commands.


------------------------------

Subject: <Q:05.08> - How can I redirect printer output to a file?
Date: Sun, 03 Aug 97 20:16:07 CST
 
 Recommended: PRN2FILE from PC Magazine, downloadable as:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/printer/prn2fil3.zip>
 
 PRN2FILE  contains ASM source code. PC Magazine  has  given
 copies  away  as part of its utilities disks,  so  you  may
 already have a copy.
 
 The   directories  mentioned  above  have  lots  of   other
 utilities to redirect printer output.
 

------------------------------

Subject: <Q:05.09> - How can I redirect the output of a batch file?
Date: Sun, 03 Aug 97 20:18:26 CST
 
 Assuming  the batch file is called batch.bat, to  send  its
 output (stdout) to another file, just invoke COMMAND.COM as
 a secondary command processor:
   command /c batch parameters_if_any >outfile
 
 Timo  Salmi's  notes  on this and other  batch  tricks  are
 downloadable (where ?? is the current version):
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/batchutil/tsbat??.zip>
   <ftp://garbo.uwasa.fi/pc/ts/tsbat??.zip>
   
 Reader Tim Kannel (kann0018@tc.umn.edu) has created a utilitiy that
 can capture batch file output. It can be found at:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/tcap30.zip>


------------------------------

Subject: <Q:05.10> - How can I redirect stderr?
Date: Sun, 03 Aug 97 20:20:33 CST
 
 Use  freopen(...,  stderr)  and then  execute  the  desired
 command  via system().  There are downloadable versions  of
 programs to do this.
 
 I  recommend  this  file,  which includes  TP4  source  and executable:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/rdstderr.zip>
 
 A C example is downloadable as:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/c/redirect.c>
 
 I  compiled  it  with MSC 7.0, and it works fine  with  one
 exception:  Contrary  to the included comments,  redirected
 output  starts writing at the beginning of the output  file
 rather  than  appending.  That is easily solved  by  adding
 "fseek(stderr, 0L, SEEK_END);" after the freopen() call for
 stderr.
 
 Reader Tim Kannel (kann0018@tc.umn.edu) has created a utilitiy that
 can capture console output. It can be found at:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/tcap30.zip>


------------------------------

Subject: <Q:05.11> - How can my program open more files than DOS's
      limit of 20?
 
 This  is  a  summary of an article Ralf Brown posted  on  8
 August 1992, with some additions from a Microsoft tech note
 and information from Chin Huang.)
 
 DOS imposes some limits.  Once you overcome those, which is
 pretty  easy, you may have to take additional  measures  to
 overcome  the  limitations built into your compiler's  run-
 time library.
 
 1) Limitations imposed by DOS: 
   There  are separate limits on files and file handles.   For
   example, DOS opens three files but five file handles:   CON
   (stdin,   stdout,  and  stderr),  AUX  (stdaux),  and   PRN
   (stdprn).
 
   The limit in FILES= in CONFIG.SYS is a system-wide limit on
   files opened by all programs (including the three that  DOS
   opens and any opened by TSRs); each process has a limit  of
   20  handles (including the five that DOS opens).   Example:
   CONFIG.SYS has FILES=40.  Then program #1 will be  able  to
   open  15  file handles.  Assuming that the program actually
   does  open 15 handles pointing to 15 different files, other
   programs  could still open a total of 22 files  (40-3-15  =
   22),  though  no one program could open more than  15  file
   handles.  If  you're  running DOS 3.3  or  later,  you  can
   increase the per-process limit of 20 file handles by a call
   to  INT 21 AH=67, Set Handle Count.  Your program is  still
   limited by the system-wide limit on open files, so you  may
   also  need  to increase the FILES= value in your CONFIG.SYS
   file  (and reboot).  The run-time library that you're using
   may  have  a fixed-size table of file handles, so  you  may
   also  need to get source code for the module that  contains
   the table, increase the table size, and recompile it.
 
 2) Limitations in Microsoft C run-time library:
   In  Microsoft C the run-time library limits you to 20  file
   handles. To change this, you must be aware of two limits:
 
   File handles used with _open(), _read(), etc.: Edit _NFILE_
   in CRT0DAT.ASM.
 
   Stream files used with fopen(), fread(), etc.: Edit _NFILE_
   in  _FILE.C for DOS or FILE.ASM for Windows/QuickWin.  This
   must  not  exceed  the  value of  _NFILE_  in  CRT0DAT.ASM.
   (QuickWin  uses  the  constant _WFILE_ in  CRT0DAT.ASM  and
   WFILE.ASM for the maximum number of child text windows.)
 
   After  changing  the limits, recompile using  CSTARTUP.BAT.
   Microsoft recommends that you first read README.TXT in  the
   same directory.
 
 3) Limitations in Borland C++ run-time library:
   (Reader  Chin  Huang provided this information on 12 Sep 1993.)
   To  increase the open file limit for a program you  compile
   with Borland C++ 3.1, edit the file _NFILE.H in the include
   directory and change the _NFILE_ value.  Compile  and  link
   the  modules  FILES.C and FILES2.C from the  lib  directory
   into your program.


------------------------------

Subject: <Q:05.12> - How can I read, create, change, or delete the
      volume label?
 
 In  DOS  5.0  (and  possibly in 4.0  as  well),  there  are
 actually two volume labels: the LABEL command reports  only
 the first but changes both of them.

 - The traditional volume label is an entry with "volume
   label" attribute in the root directory of the disk.   The
   DIR, VOL, and LABEL commands report this volume label, and
   LABEL sets it.
 
 - There is a second volume label, which may be different,
   in the boot record along with the serial number. In DOS 4.0
   and  later,  INT 21 AH=69 gets or sets the boot  record's
   serial number and  volume label together; see "<Q: 5.13> -
   How can I get the disk serial number?"  DIR and VOL ignore
   this volume label; the LABEL command doesn't report it but
   does set it.
 
 The  rest of this answer assumes that by "volume label" you
 mean the traditional one, the one that DIR and VOL display.
 Though  it's  a directory entry in the root directory,  you
 can't  change it using the newer DOS file-access  functions
 (INT  21  AH=3C, 41, 43); instead, use the old FCB-oriented
 directory functions.  Specifically, you need to allocate  a
 64-byte  buffer and a 41- byte extended FCB  (file  control
 block).  Call INT 21 AH=1A to find out whether there  is  a
 volume label.  If there is, AL returns 0 and you can change
 the  label  using DOS function 17 or delete  it  using  DOS
 function 13.  If there's no volume label, function 1A  will
 return  FF  and  you can create a label  via  function  16.
 Important points to notice are that ? wildcards are allowed
 but  *  are not; the volume label must be space filled  not
 null terminated.
 
 The  following MSC 7.0 code worked for me in DOS  5.0;  the
 functions  it  uses have been around since  DOS  2.0.   The
 function parameter is 0 for the current disk, 1 for  a:,  2
 for b:, etc.  It doesn't matter what your current directory
 is;  these  functions always search the root directory  for
 volume labels.  (I didn't try to change the volume label of
 any networked drives.)
 
   // Requires DOS.H, STDIO.H, STRING.H

   void vollabel(unsigned char drivenum)
   {
     static  unsigned  char  extfcb[41],  dta[64],  status,  *newlabel;
     int chars_got = 0;

     #define DOS(buff,func) __asm { __asm mov dx,offset buff  \
       __asm mov ax,seg buff  __asm push ds  __asm mov ds,ax  \
       __asm  mov  ah,func   __asm int  21h   __asm  pop  ds  \
       __asm mov status,al }

     #define getlabel(buff,prompt) newlabel = buff;  \
       memset(newlabel,' ',11);  printf(prompt);   \
       scanf("%11[^\n]%n", newlabel, &chars_got);  \
       if (chars_got < 11) newlabel[chars_got] = ' ';

     // Set up the 64-byte transfer area used by function 1A.
     DOS(dta, 1Ah)
  
     //  Set  up  an extended FCB and search for the  volume label.
     memset(extfcb, 0, sizeof extfcb);
     extfcb[0] = 0xFF;           // denotes extended FCB
     extfcb[6] = 8;              // volume-label attribute  bit
     extfcb[7] = drivenum;       // 1=A,2=B,...; 0=current drive
  
     memset(&extfcb[8], '?', 11);// wildcard *.*
     DOS(extfcb,11h)
     if(status == 0)
     {                           // DTA has volume  label's FCB
       printf("volume label is %11.11s\n", &dta[8]);
       getlabel(&dta[0x18], "new label (\"delete\" to delete): ");
      
       if(chars_got==0)
         printf("label not changed\n");
       else if (strncmp(newlabel,"delete  ",11) == 0)
       {
         DOS(dta,13h)
         printf(status ? "label failed\n":"label deleted\n");
       }
       else
       {                  // user wants to change label
         DOS(dta,17h)
         printf(status ? "label failed\n" : "label changed\n");
       }
     }
     else
     {                      // no volume label was found
       printf("disk has no volume label.\n");
       getlabel(&extfcb[8], "new label (<Enter>  for  none): ");

       if (chars_got > 0)
       {
         DOS(extfcb,16h)
         printf(status ? "label failed\n" : "label created\n");
       }
     }
   } // end function vollabel
   

------------------------------

Subject: <Q:05.13> - How can I get the disk serial number?
 
 If  the disk was formatted by DOS 4.0 or later, use INT 21:
 AX=6900 gets the serial number; AX=6901 sets it.  (The disk
 serial number doesn't exist if the disk was formatted  with
 an  earlier  version  of  DOS,  or  with  some  third-party
 formatters.)  See Ralf Brown's interrupt list <Q:02.03>, or
 PC Magazine July 1992 (xi:13) page 496, for details.
 
 
 INT  21  AH=69 also gets and sets the volume label  in  the
 boot  record,  which is not necessarily the same  as  "the"
 volume label displayed by the DIR, VOL, and LABEL commands.
 For  that  volume label, see <Q:05.12> - "How can  I  read,
 create, change, or delete the volume label?"
 

------------------------------

Subject: <Q:05.14> - What's the format of .OBJ, .EXE., .COM files?

 Please  see <Q:03.06> "What's the format of an .OBJ file?";
 <Q:03.07> "What's the format of an .EXE header?"; and <Q:03.08>
 "What's  the  difference  between .COM and .EXE formats?"
 

------------------------------

Subject: <Q:05.15> - How can I flush the software disk cache?

 
 Please see "<Q:08.01> - How can a program reboot  my  PC?"
 (Trust me.)
 

------------------------------

Subject: <Q: 5.16> - How can I see if a drive is a RAM drive?
Date: Tue, 7 Mar 95 12:00:00 CDT

 Use  INT 21 AX=4409h. See Ralph Brown's interrupt list <Q:2.03>
 for more information.
 

------------------------------

Subject: Section 6.  Serial ports (COM ports)
Date: Mon, 04 Jan 99 10:50:44 CST

 This section provides information about how to access the serial
 ports. In the future I will be working on adding information about
 using MS-DOS for networking and internet access.


------------------------------

Subject: <Q:06.01> - How do I set my machine up to use COM3 and COM4?
 
 Unless  your  machine is fairly old, it's probably  already
 set  up. After installing the board that contains the extra
 COM  port(s), check the I/O addresses in word 0040:0004  or
 0040:0006.   (In DEBUG, type "D 40:4 L4" and remember  that
 every  word is displayed low byte first, so if you see  "03
 56"  the  word  is 5603.)  If those addresses are  nonzero,
 your  PC  is ready to use the ports and you don't need  the
 rest of this answer.
 
 If the I/O address words in the 0040 segment are zero after
 you've installed the I/O board, you need some code to store
 these values into the BIOS data segment:
   0040:0004  word  I/O address of COM3
   0040:0006  word  I/O address of COM4
   0040:0011   byte  (bits  3-1):  number  of  serial   ports installed
 
 The  documentation with your I/O board should tell you  the
 port  addresses.  When you know the proper port  addresses,
 you  can  add  code to your program to store them  and  the
 number  of serial ports into the BIOS data area before  you
 open  communications.  Or you can use  DEBUG  to  create  a
 little program to include in your AUTOEXEC.BAT file,  using
 this script:
   n  SET_ADDR.COM     <--- or a different name  ending in .COM
   a 100
   mov  AX,0040
   mov  DS,AX
   mov  wo [0004],aaaa <--- replace aaaa with COM3 address or 0
   mov  wo [0006],ffff <--- replace ffff with COM4 address or 0
   and  by [0011],f1
   or    by [0011],8   <--- use number of serial ports times 2
   mov  AH,0
   int  21
                         <--- this line must be blank
   rCX
   1f
   rBX
   0
   w
   q


------------------------------

Subject: <Q:06.02> - How do I find the I/O address of a COM port?
Date: Sun, 03 Aug 97 20:27:12 CST

 Look  in  the  four words beginning at 0040:0000  for  COM1
 through COM4. (The DEBUG command "D 40:0 L8" will do  this.
 Remember  that  words  are stored and  displayed  low  byte
 first, so a word value of 03F8 will be displayed as F8 03.)
 If  the  value is zero, that COM port is not installed  (or
 you've  got  an  old BIOS; see "<Q:06.01> - How  do  I  set  my
 machine  up  to  use COM3 and COM4?").   If  the  value  is
 nonzero,  it  is  the  I/O address of the  transmit/receive
 register for the COM port.
 
 Each  COM  port  occupies eight consecutive  I/O  addresses
 (though many chips use only the first seven).
 
 Here's some C code to find the I/O address:
 
   unsigned ptSel(unsigned comport)
   {
     unsigned io_addr;
  
     if (comport >= 1  &&  comport <= 4)
     {
       unsigned far *com_addr = (unsigned far *)0x00400000UL;
       io_addr = com_addr[comport-1];
     }
     else
       io_addr = 0;
  
     return io_addr;
   }
 
 You might also want to explore Port Finder, downloadable as: 
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/io_utils/pf271.zip>
 
 I haven't tried it myself, but a posted article reviewed it
 very favorably and said it also lets you swap ports around.
 

------------------------------

Subject: <Q:06.03> - But aren't the COM ports always at I/O addresses 3F8,
      2F8, 3E8, and 2E8?
 
 The  first  two are usually right (though not always);  the
 last two are different on many machines.
 

------------------------------

Subject: <Q:06.04> - How do I configure a COM port and use it to transmit data?
Date: Sun, 03 Jan 99 22:32:06 CST
 
 Do  you want actual code, or do you want books that explain
 what's going on?
 
 
 1) Source code
 
 First,  check  your  compiler's  run-time  library.    Many
 compilers   offer  functions  similar  to   Microsoft   C's
 _bios_serialcom() or Borland's bioscom(),  which  may  meet
 your needs.
 
 Second,  check  for downloadable resources  at  SimTel  and
 Garbo. At SimTel, <ftp://ftp.simtel.net/pub/simtelnet/msdos/c/pcl4c34.zip>
 (March 1993) is described as "Asynchronous communications library
 for  C";  Garbo  has a whole <ftp://garbo.uwasa.fi/pc/comm>
 directory.   Also,  an  extended example  is  in  Borland's
 TechFax TI445, downloadable as part of:
   <ftp://ftp.simtel.net/pub/simtelnet/msdos/turbo_c/bchelp10.zip>
   <ftp://garbo.uwasa.fi/pc/c-lang/bchelp10.zip>
 
 Though  written  by Borland, much of it  is  applicable  to
 other  forms of C, and it should give you ideas  for  other
 programming languages.
 
 Third, SNIPPETS (see <Q:02.08>) contains a sample interrupt-driven
 serial communications library.
 
 2) Reference books
 
 Highly recommended: Joe Campbell's {C Programmer's Guide to
 Serial  Communications},  ISBN  0-672-22584-0.   He   gives
 complete  details  on  how serial ports  work,  along  with
 complete programs for doing polled or interrupt-driver I/O.
 The book is quite thick, and none of it looks like filler.
 
 If  Campbell's book is overkill for you, you'll find a good
 short  description of serial I/O in {DOS 5:  A  Developer's
 Guide}, ISBN 1-55851-177-6, by Al Williams.
 
 Finally,  a  reader has recommended {Serial  Communications
 Programming in C/C++} by Mark Goodwin (ISBN 1-55828-198-3),
 with  source code in the book and on disk.  Topics  include
 the basics, various methods of serial communications on the
 PC  (with consideration of high-speed modems), ANSI  screen
 interface,  file  transfer protocols (Xmodem  and  Ymodem),
 etc.  There is code in C, and that code is extended into  a
 C++   class  for  those  who  use  C++.   There  are   also
 subroutines in Assembly.
 
 3) Downloadable information files
 
 A   "Serial  Port  FAQ"  is  occasionally  posted  to  this
 newsgroup, and is downloadable as multiple files:
 
 <ftp://ftp.phil.uni-sb.de/pub/people/chris/>
 
 This directory contains a series of files beginning with Serial_Port.


------------------------------

Subject: End of Part 3

 This is the end of part 3 of The comp.os.msdos.programmer FAQ Version 1999.01.
 
 This text is copyright 1999 by Jeffrey Carlyle. All rights reserved. Please
 see the top of this article for additional copyright information.

// Jeffrey Coleman Carlyle <jeffrey@carlyle.com> <www.jeffrey.carlyle.com>
// Computer Engineering major at the University of Evansville in Indiana.
// Bowling Green, Kentucky, USA; Creator of Windows Restart 98 and
// StratoSetup; comp.os.msdos.programmer FAQ maintainer; Ruler or Earth!


