home *** CD-ROM | disk | FTP | other *** search
- Path: senator-bedfellow.mit.edu!dreaderd!not-for-mail
- Message-ID: <msdos-programmer-faq/part4_1084010824@rtfm.mit.edu>
- Supersedes: <msdos-programmer-faq/part4_1081511793@rtfm.mit.edu>
- Expires: 11 Jun 2004 10:07:04 GMT
- References: <msdos-programmer-faq/part1_1084010824@rtfm.mit.edu>
- X-Last-Updated: 2003/08/14
- From: jeffrey@carlyle.org (Jeffrey Carlyle)
- Sender: jeffrey@carlyle.org (Jeffrey Carlyle)
- Reply-To: jeffrey@carlyle.org (Jeffrey Carlyle)
- Approved: news-answers-request@MIT.edu
- Organization: JeffC.org
- Subject: comp.os.msdos.programmer FAQ part 4/5
- Newsgroups: comp.os.msdos.programmer,alt.msdos.programmer,comp.answers,alt.answers,news.answers
- Followup-To: poster
- Summary: Frequently asked questions from DOS programmers with tested answers.
- Originator: faqserv@penguin-lust.MIT.EDU
- Date: 08 May 2004 10:08:03 GMT
- Lines: 1000
- NNTP-Posting-Host: penguin-lust.mit.edu
- X-Trace: 1084010883 senator-bedfellow.mit.edu 580 18.181.0.29
- Xref: senator-bedfellow.mit.edu comp.os.msdos.programmer:127445 alt.msdos.programmer:54823 comp.answers:57101 alt.answers:72788 news.answers:270992
-
- Archive-name: msdos-programmer-faq/part4
- Comp-os-msdos-programmer-archive-name: dos-faq-pt4.txt
- Posting-frequency: 28 days
- Last-modified: 14 Aug 2003
-
- comp.os.msdos.programmer FAQ Version 2003.08.14
-
- This is the Frequently Asked Questions list for the newsgroup
- comp.os.msdos.programmer.
-
- COPYRIGHT
-
- Copyright 2003 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. See <Q:01.14> [Where can I get the
- latest copy of this FAQ list?] for a link to the latest version of the
- FAQ.)
-
- This is part 4 of 5 parts.
-
- TABLE OF CONTENTS
-
- PART 1:
- 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> - Where can I find out about batch files?
-
- PART 2:
- 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:
- 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?
- <Q:05.17> - How can I determine a hard drive's manufacturer?
- <Q:05.18> - Where can I find information about the ATA/ATAPI
- specification?
- <Q:05.19> - How can I copy files to or from filenames containing date
- information?
-
- 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: (this part)
- 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?
- <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?
- <Q:07.13> - How can I power off the computer from a batch file?
-
- 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?
- <Q:08.15> - How can I place date and time information into environment
- variables?
-
- PART 5:
- Section 9. Downloading
- <Q:09.01> - What are SimTel and Garbo?
- <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 is the current version of DJGPP?
- <Q:10.04> - What and where is DJGPP?
- <Q:10.05> - Are there any good shareware/freeware compilers?
- <Q:10.06> - Where is QBASIC?
- <Q:10.07> - What is a vendor's web site address?
-
- ------------------------------
-
- Subject: Section 7. Other hardware questions and problems
- Date: 5 Feb 2002 22:03:03 -0400
-
- The subject says it all. Bv)
-
- ------------------------------
-
- Subject: <Q:07.01> - Which 80x86 CPU is running my program?
- Date: 5 Feb 2002 22:03:03 -0400
-
- SNIPPETS (see <Q:02.08> [What and where is SNIPPETS?]) contains
- C-callable x86 assembly language code for determining the type of CPU in
- CPUCHECK.ASM.
-
- ------------------------------
-
- Subject: <Q:07.02> - How can a C program send control codes to my
- printer?
- Date: 5 Feb 2002 22:03:03 -0400
-
- If you just fprintf(stdprn, ...), C will translate some of your control
- codes. The way around this is to reopen the printer in binary mode: prn
- = fopen("PRN", "wb");
-
- You must use a different file handle because stdprn isn't an lvalue. By
- the way, in DOS 5.0 a colon must not follow PRN or LPT1.
-
- There's one special case, Ctrl-Z (ASCII 26), the DOS end-of- file
- character. If you try to send an ASCII 26 to your printer, DOS simply
- ignores it. To get around this, you need to reset the printer from
- "cooked" to "raw" mode. Microsoft C users must use INT 21 AH=44,
- "get/set device information". Turbo C and Borland C++ users can use
- ioctl to accomplish the same thing: ioctl(fileno(prn), 1,
- ioctl(fileno(prn),0) & 0xFF | 0x20, 0);
-
- An alternative approach is simply to write the printer output into a
- disk file, then copy the file to the printer with the /B switch.
-
- A third approach is to bypass DOS functions entirely and use the BIOS
- printer functions at INT 17. If you also fprintf(stdprn,...) in the same
- program, you'll need to use fflush() to synchronize fprintf()'s buffered
- output with the BIOS's unbuffered.
-
- By the way, if you've opened the printer in binary mode from a C
- program, remember that outgoing \n won't be translated to carriage
- return/line feed. Depending on your printer, you may need to send
- explicit \n\r sequences.
-
- ------------------------------
-
- Subject: <Q:07.03> - How can I redirect printer output?
- Date: 5 Feb 2002 22:03:03 -0400
-
- Please see <Q:05.08> [How can I redirect printer output to a file?]
-
- ------------------------------
-
- Subject: <Q:07.04> - Which video adapter is installed?
- Date: 5 Feb 2002 22:03:03 -0400
-
- The technique below should work if your BIOS is not too old. It uses
- three functions from INT 10, the BIOS video interrupt. (If you're using
- a Borland language, you may not have to do this the hard way. Look for a
- function called DetectGraph or something similar.)
-
- Set AX=1200, BL=32 and call INT 10. If AL returns 12, you have a VGA. If
- not, set AH=12, BL=10 and call INT 10 again. If BL returns 0,1,2,3, you
- have an EGA with 64,128,192,256K memory. If not, set AH=0F and call INT
- 10 a third time. If AL is 7, you have an MDA (original monochrome
- adapter) or Hercules; if not, you have a CGA.
-
- This worked when tested with a VGA, but I had no other adapter types to
- test it with.
-
- ------------------------------
-
- Subject: <Q:07.05> - How do I switch to 43- or 50-line mode?
- Date: 8 Feb 2002 20:05:49 -0400
-
- The following file contains .COM utilities and .ASM source code:
- <http://www.simtel.net/pub/pd/49657.html>
-
- ------------------------------
-
- Subject: <Q:07.06> - How can I find the Microsoft mouse position and
- button status?
- Date: 8 Feb 2002 20:07:14 -0400
-
- Use INT 33 AX=3, described in Ralf Brown's interrupt list (<Q:02.03>
- [What and where is Ralf Brown's interrupt list?]).
-
- The Windows manual says that the Logitech mouse is compatible with the
- Microsoft one, so the interrupt will probably work the same.
-
- Also, many files are downloadable from:
- <http://www.simtel.net/pub/msdos/mouse/>
-
- ------------------------------
-
- Subject: <Q:07.07> - How can I access a specific address in the PC's
- memory?
- Date: 7 Feb 2002 14:50:10 -0400
-
- First check the library that came with your compiler. Many vendors have
- some variant of peek and poke functions. For example:
-
- * In Turbo Pascal, use the pseudo-arrays Mem, MemW, and MemL. Be sure
- you use the correct array for the size of data you want to access:
- byte, word, or double word. Alternatively, use pointers.
-
- * In Turbo C/Borland C, and in recent versions of Microsoft C, use
- MK_FP; in older versions of Microsoft C, use FP_OFF and FP_SEG.
- (Caution: Turbo C and Turbo C++ also have FP_OFF and FP_SEG macros,
- but they can't be used to construct a pointer.) Be sure to pick the
- right data type: probably "unsigned char far *" if you're planning to
- access bytes and "unsigned short far *" for words. (The "far" isn't
- needed if your memory model uses 32-bit data pointers, but including
- it does no harm.)
-
- By the way, it's not useful to talk about "portable" ways to do this.
- Any operation that is tied to a specific memory address is not likely to
- work on another kind of machine.
-
- ------------------------------
-
- Subject: <Q:07.08> - How can I read or write my PC's CMOS memory?
- Date: 8 Feb 2002 20:11:37 -0400
-
- There are a great many public-domain utilities that do this. The
- following files can be downloaded from
- <http://www.simtel.net/pub/msdos/sysutl/>:
-
- cmos14.zip 5965 920817 Saves/restores CMOS to/from file
- cmoser11.zip 28323 910721 386/286 enhanced CMOS setup program
- cmosram.zip 76096 920214 Save AT/386/486 CMOS data to file and restore
- rom2.zip 15692 900131 Save AT and 386 CMOS data to file and restore
- setup21.zip 18172 880613 Setup program which modifies CMOS RAM
- viewcmos.zip 11068 900225 Display contents of AT CMOS RAM, w/C source
-
- A program to check and display CMOS memory (but not write to it) is
- downloadable as part of: <http://www.simtel.net/pub/pd/50522.html>
- <ftp://garbo.uwasa.fi/pc/ts/tsutle23.zip>
-
- Good reports of CMOS299.ZIP have been posted, but it no longer appears
- to be online.
-
- Stan Brown, the former list maintainer, reports that he personally
- tested CMOSRAM and that it worked fine. It contains an excellent (and
- witty) .DOC file that explains the hardware involved and gives specific
- recommendations for preventing disaster or recovering from it. It's $5
- shareware.
-
- Robert Jourdain's {Programmer's Problem Solver for the IBM PC, XT, and
- AT} has code for accessing the CMOS RAM, according to an article posted
- in this newsgroup.
-
- ------------------------------
-
- Subject: <Q:07.09> - How can I access memory beyond 640K?
- Date: 8 Feb 2002 20:50:34 -0400
-
- Part of this involves switching into protected mode.
-
- An article entitled "How DOS Programs Can Use Over 1MB of RAM" appeared
- in PC Magazine 29 June 1993 (xii: 12) pages 302-304.
-
- I also suggest John English's XMS classes for C++:
- <ftp://ftp.brighton.ac.uk/pub/je/xms200je.zip>.
-
- See also <Q:07.10> [How can I use the protected mode?]
-
- ------------------------------
-
- Subject: <Q:07.10> - How can I use the protected mode?
- Date: 8 Feb 2002 20:15:02 -0400
-
- DJ Delorie has produced DJGPP, a protected mode programming environment
- which supports a port of the GNU C/C++/Ada. For more informat see
- <Q:10.04> [What and where is DJGPP?]
-
- Users of Borland C++ Version 4.xx could once purchase the Borland
- PowerPack for DOS Version 1.00; however, it appears that its sell has
- been discontinued. This package includes Borland C++ 4.02 Service
- Update, 16-bit DPMI libraries and extenders, 32-bit DPMI libraries and
- extenders, TurboVision 2.0 (16-bit DOS, 16-bit DPMI, 32-bit DPMI),
- SuperVGA BGI Drivers (16-bit DOS, 16-bit DPMI, 32- bit DPMI).
-
- A reader of comp.os.msdos.programmer has the following updateu about the
- PowerPack and additional information about DPMI programming:
-
- [begin quote]
- About protected-mode programming (Question 7.10), Borland no longer
- supports the PowerPack (from what I've read in this newsgroup), so
- I doubt that it can still be purchased. However, the FAQ could
- mention that the extender is integrated into Borland C++ version 5.x
- (and probably the Builder product as well).
-
- Borland doesn't fully support that either, since the documentation
- isn't very clear about compiling DPMI programs and a stub for the
- executable has to be extracted from one of Borland's executables. The
- necessary steps were posted a long time ago (by someone else), and I
- can provide the information if necessary. Even if the FAQ didn't
- describe those steps, it could at least indicate that version 5.x can
- compile DPMI programs (as well as clarifying the PowerPack info).
- [end quote]
-
- There are more extenders out there. One notable DOS extender is Adam
- Seychell's DOS32 Version 3.5 beta. It can be found at
- <http://www.programmersheaven.com/zone5/cat19/1363.htm> Also check out
- Adam's page at <http://www.geocities.com/SiliconValley/2151/pmode.html>
-
- ------------------------------
-
- Subject: <Q:07.11> - How can I tell if my program is running on a
- PS/2-style machine.
- Date: 5 Feb 2002 22:03:03 -0400
-
- Use INT 15 AX=C0, described in Ralf Brown's interrupt list (<Q:02.03>
- [What and where is Ralf Brown's interrupt list?]).
-
- ------------------------------
-
- Subject: <Q:07.12> - Is there a 80x87 math unit installed?
- Date: 5 Feb 2002 22:03:03 -0400
-
- SNIPPETS (see <Q:02.08> [What and where is SNIPPETS?]) contains
- C-callable assembly code to determine presence of coprocessor in
- NDPCHECK.ASM.
-
- ------------------------------
-
- Subject: <Q:07.13> - How can I power off the computer from a batch file?
- Date: 6 Feb 2002 20:36:38 -0400
-
- A utility known as ATXOFF.COM is available at
- <http://www.informatik.fh-muenchen.de/~ifw98223/dostools.htm>. It uses
- APM 1.2 to power off the system but doesn't attempt to flush the disk
- cache.
-
- ------------------------------
-
- Subject: Section 8. Other software questions and problems
- Date: 5 Feb 2002 22:03:03 -0400
-
- This section is noteworthy for having the longest code snippets.
-
- ------------------------------
-
- Subject: <Q:08.01> - How can a program reboot my PC?
- Date: 8 Feb 2002 20:16:09 -0400
-
- You can generate a "cold" boot or a "warm" boot. A cold boot is the same
- as turning the power off and on; a warm boot is the same as Ctrl-Alt-Del
- and skips the power-on self 'test.
-
- For a warm boot, store the hex value 1234 in the word at 0040:0072. For
- a cold boot, store 0 in that word. Then, if you want to live
- dangerously, jump to address FFFF:0000. Here's C code to do it:
-
- /* WARNING: data loss possible */
- void bootme(int want_warm) /* arg 0 = cold boot, 1 = warm */
- {
- void (far* boot)(void) = (void (far*)(void))0xFFFF0000UL;
-
- unsigned far* type = (unsigned far*)0x00400072UL;
- *type = (want_warm ? 0x1234 : 0);
- (*boot)( );
- }
-
- What's wrong with that method? It will boot right away, without closing
- files, flushing disk caches, etc. If you boot without flushing a
- write-behind disk cache (if one is running), you could lose data or
- trash the file allocation table in your hard drive.
-
- There are two methods of signaling the cache to flush its buffers:
-
- (1) Simulate a keyboard Ctrl-Alt-Del in the keystroke translation
- function of the BIOS (INT 15 AH=4F; but see notes below)
-
- (2) Issue a disk reset (DOS function 0D). Most disk-cache programs hook
- one or both of those interrupts, so if you use both methods you'll
- probably be safe.
-
- When user code simulates a Ctrl-Alt-Del, one or more of the programs
- that have hooked INT 15 AH=4F can ask that the key be ignored by
- clearing the carry flag. For example, HyperDisk does this when it has
- started but not finished a cache flush. So if the carry flag comes back
- cleared, the boot code has to wait a couple of clock ticks and then try
- again. (None of this matters on older machines whose BIOS can't support
- 101- or 102-key keyboards; see the discussion of INT 21 AH=4F in
- <Q:04.07> [What is the SysRq key for?])
-
- C code that tries to signal the disk cache (if any) to flush is given
- below. Turbo Pascal code by Timo Salmi that does more or less the same
- job may be found at question 49 (as of this writing) in the Turbo Pascal
- FAQ in comp.lang.pascal, and is downloadable as file FAQPAS2.TXT, which
- is part of: <ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip>
-
- Here's C code that reboots after trying to signal the disk cache:
-
- #include <dos.h>
-
- void bootme(int want_warm) /* arg 0 = cold boot, 1 = warm */
- {
- union REGS reg;
-
- void (far* boot)(void) = (void (far*)(void))0xFFFF0000UL;
- unsigned far* boottype = (unsigned far*)0x00400072UL;
- char far* shiftstate = (char far*)0x00400017UL;
- unsigned ticks;
- int time_to_waste;
-
- /* Simulate reception of Ctrl-Alt-Del: */
- for (;;)
- {
- *shiftstate |= 0x0C; /* turn on Ctrl & Alt */
- reg.h.ah = 0x4F; /* see notes below */
- reg.h.al = 0x53; /* 0x53 = Del's scan code */
- reg.x.cflag = 1; /* sentinel for ignoring key */
- int86(0x15, ®, ®);
-
- /* If carry flag is still set, we've finished. */
- if(reg.x.cflag)
- break;
-
- /* Else waste some time before trying again: */
- reg.h.ah = 0;
- int86(0x1A, ®, ®); /* system time into CX:DX */
-
- ticks = reg.x.dx;
- for (time_to_waste = 3; time_to_waste > 0; )
- {
- reg.h.ah = 0;
- int86(0x1A, ®, ®);
- if (ticks != reg.x.dx)
- ticks = reg.x.dx , --time_to_waste;
- }
- }
-
- /* Issue a DOS disk reset request: */
- reg.h.ah = 0x0D;
- int86(0x21, ®, ®);
-
- /* Set boot type and boot: */
- *boottype = (want_warm ? 0x1234 : 0);
- (*boot)( );
- }
-
- Reader Timo Salmi reported (26 July 1993) that the INT 15 AH=4F call may
- not work on older PCs (below AT, XT2, XT286), according to Ralf Brown's
- interrupt list (<Q:02.03> [What and where is Ralf Brown's interrupt
- list?]).
-
- Reader Roger Fulton reported (1 July 1993) that INT 15 AH=4F hangs even
- a modern PC "ONLY when ANSI.SYS [is] loaded high using EMM386.EXE.
- (Other things loaded high with EMM386.EXE were OK; ANSI.SYS loaded high
- with QEMM386.SYS was OK; ANSI.SYS loaded low with EMM386.EXE installed
- was OK.)" His solution was to use only the disk reset, INT 21 AH=0D,
- which does flush SMARTDRV, then wait five seconds in hopes that any
- other disk-caching software would have time to flush its queue.
-
- Reader Per Bergland reported (10 Sep 1993) that the jump to FFFF:0000
- will not work in Windows or other protected-mode programs. (For example,
- when the above reboot code ran in a DOS session under Windows, a box
- with "waiting for system shutdown" appeared. The PC hung and had to be
- reset by cycling power.) His solution, which does a cold boot not a warm
- boot, is to pulse pin 0 of the 8042 keyboard controller, which is
- connected to the CPU's "reset" line.
-
- He has tested the following code on various Compaqs, and expects it will
- work for any AT-class machine; he cautions that you must first flush the
- disk cache as indicated above.
-
- cli
- @@WaitOutReady: ; Busy-wait until 8042 ready for new command
- in al,64h ; read 8042 status byte
- test al,00000010b ; this bit indicates input buffer full
- jnz @@WaitOutReady
- mov al,0FEh ; Pulse "reset" = 8042 pin 0
- out 64h,al ; The PC will reboot now
-
- ------------------------------
-
- Subject: <Q:08.02> - How can I time events with finer resolution than the
- system clock's 55 ms (about 18 ticks a second)?
- Date: 8 Feb 2002 20:19:05 -0400
-
- The PC Timing FAQ / Application Note, maintained by Kris Heidenstrom
- (kheidenstrom@actrix.gen.nz), contains information relating to timing
- with PC hardware and software. It can be found on SimTel:
- <http://www.simtel.net/pub/pd/46935.html>
-
- The following files, among others, are downloadable from SimTel in the
- <http://www.simtel.net/pub/msdos/sysutl/> directory:
-
- atim.zip 4783 881126 Precision program timing for AT
-
- In the <http://www.simtel.net/pub/msdos/c/> directory:
-
- millisec.zip 37734 911205 MSC/asm src for millisecond timing
- mschrt3.zip 53708 910605 High-res timer toolbox for MSC 5.1
- msec_12.zip 8484 920320 High-def timer v1.2 (C,ASM)
- ztimer11.zip 77625 920428 Microsecond timer for C, C++, ASM
-
- For Turbo Pascal users, source and object code are downloadable as:
- <ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip>
-
- Also see "Q: How is millisecond timing done?" in FAQPAS.TXT,
- downloadable as part of: <ftp://garbo.uwasa.fi/pc/link/tsfaqp.zip>
-
- ------------------------------
-
- Subject: <Q:08.03> - How can I find the error level of the previous
- program?
- Date: 8 Feb 2002 20:21:49 -0400
-
- First, which previous program are you talking about? If your current
- program ran another one, when the child program ends its error level is
- available to the program that spawned it. Most high-level languages
- provide a way to do this; for instance, in Turbo Pascal it's
- Lo(DosExitCode) and the high byte gives the way in which the child
- terminated. In Microsoft C, the exit code of a synchronous child process
- is the return value of the spawn- type function that creates the
- process.
-
- If your language doesn't have a function to return the error code of a
- child process, you can use INT 21 AH=4D (get return code). By the way,
- this will tell you the child's exit code and the manner of its ending
- (normal, Ctrl-C, critical error, or TSR).
-
- It's much trickier if the current program wants to get the error level
- of the program that ran and finished before this one started. G.A.
- Theall has published source and compiled code to do this; the code is
- downloadable as: <http://www.simtel.net/pub/pd/40610.html>
-
- (The code uses undocumented features in DOS 3.3 through 5.0. In the .DOC
- file Theall says that the values returned under 4DOS or other
- replacements won't be right.)
-
- ------------------------------
-
- Subject: <Q:08.04> - How can a program set DOS environment variables?
- Date: 8 Feb 2002 20:22:43 -0400
-
- Program functions that read or write "the environment" typically access
- only the program's copy of it. What this Q really wants to do is to
- modify the active environment, the one that is affected by SET commands
- in batch files or at the DOS prompt. You need to do some programming to
- find the active environment, and that depends on the version of DOS.
-
- A fairly well-written article in PC Magazine 28 Nov 1989 (viii:20),
- pages 309-314, explains how to find the active environment, and includes
- Pascal source code. The article hints at how to change the environment,
- and suggests creating paths longer than 128 characters as one
- application.
-
- Now as for downloadable source code, there are many possibilities.
-
- Stan Brown, the former list maintainer recommends the following:
- <ftp://garbo.uwasa.fi/pc/envutil/rbsetnv1.zip>
-
- It includes some utilities to manipulate the environment, with source
- code in C. A newer program from PC Magazine 22 Dec 1992 (XI: 22) is:
- <ftp://garbo.uwasa.fi/pc/pcmagvol/vol11n22.zip>
-
- You can also use a call to INT 2E, Pass Command to Interpreter for
- Execution; see Ralf Brown's interrupt list (<Q:02.03> [What and where is
- Ralf Brown's interrupt list?]) for details and cautions.
-
- Reader Dr. John Stockton has written a unit for Turbo Pascal known as
- jrs_envu.pas to facilitate writing to the environment. It is for DOS
- (not DPMI) mode programs running under DOS to Win98, but not WinNT. It
- can be downloaded from here:
- <http://www.merlyn.demon.co.uk/programs/jrs_envu.pas>. For more
- information, see <http://www.merlyn.demon.co.uk/batprogs.htm>.
-
- ------------------------------
-
- Subject: <Q:08.05> - How can I change the switch character to - from /?
- Date: 5 Feb 2002 22:03:03 -0400
-
- Under DOS 5.0 and above you can not. INT 21 AX=3700, get switch
- character, always returns a '/' (hex 2F). But the DOS commands don't
- even call that function: they simply hard code '/' as the switch
- character.
-
- Some history: DOS used to let you change the switch character by using
- SWITCHAR= in CONFIG.SYS or by calling DOS function 3701. DOS commands
- and other programs called DOS function 3700 to find out the switch
- character. If you changed the switch character to '-' (the usual
- choice), you could then type "dir c:/c700 -p" rather than "dir c:\c700
- /p". Under DOS 4.0, the DOS commands ignored the switch character but
- functions 3700 and 3701 still worked and could be used by other
- programs. Under DOS 5.0, even those functions no longer work, though all
- DOS functions still accept '/' or '\' in file specs.
-
- You can reactivate the functions to get and set switchar by using
- programs like SLASH.ZIP or the sample TSR called SWITCHAR in
- amisl091.zip (see <Q:08.06> [How can I write a TSR
- (terminate-stay-resident utility)?]). DOS commands will still use the
- slash, but non-DOS programs that call DOS function 3700 will use your
- desired switch character. (DOS replacements like 4DOS may honor the
- switch character for internal commands.)
-
- Some readers may wonder why this is even an issue. Making '-' the switch
- character frees up the front slash to separate names in the path part of
- a file spec. This is easier for the ten-fingered to type, and it's one
- less difference to remember for commuters between DOS and Unix. The
- switch character is the only issue, since all the INT 21 functions
- accept '/' or '\' to separate directory names.
-
- ------------------------------
-
- Subject: <Q:08.06> - How can I write a TSR (terminate-stay-resident
- utility)?
- Date: 8 Feb 2002 20:31:08 -0400
-
- There are books, and there's code to download.
-
- First, the books:
-
- * Ray Duncan's {Advanced MS-DOS}, ISBN 1-55615-157-8, gives a brief
- checklist intended for experienced programmers. The ISBN is for the
- second edition, through DOS 4; but check to see whether the DOS 6
- version is available yet.
-
- * {DOS 5: A Developer's Guide} by Al Williams, ISBN 1-55851-177-6, goes
- into a little more detail, 90 pages worth!
-
- * Pascal programmers might look at {The Ultimate DOS Programmer's
- Manual} by John Mueller and Wallace Wang, ISBN 0-8306-3534-3, for an
- extended example in mixed Pascal and assembler.
-
- * For a pure assembler treatment, check Steven Holzner's {Advanced
- Assembly Language}, ISBN 0-13-663014-6. He has a book with the same
- title out from Brady Press, but it's about half as long as this one.
-
- Next, the code. Some of it is companion code to published articles,
- which are also listed below:
-
- * John English (<http://www.it.bton.ac.uk/staff/je/>) has created a
- wonderful C++ class for creating TSRs which includes several examples.
- This one is my personal favorite. It is downloadable as:
- <ftp://ftp.brighton.ac.uk/pub/je/tsr100je.zip>
- <http://www.simtel.net/pub/pd/42697.html>
-
- * The Alternate Multiplex Interrupt Specification (AMIS),downloadable
- as: <http://www.simtel.net/pub/pd/46788.html>
- <ftp://garbo.uwasa.fi/pc/programming/altmpx35.zip>
-
- * Ralf Brown's assembly-language implementation of the AMIS spec, with
- utilities in C, is downloadable as:
- <ftp://garbo.uwasa.fi/pc/c-lang/amisl092.zip>
-
- * Douglas Boling's MASM template for a TSR is downloadable as:
- <http://www.simtel.net/pub/pd/40314.html>
-
- * Code for Al Stevens's "Writing Terminate-and-Stay-Resident Programs",
- Computer Language, February 1988, pages 37-48 and March 1988, pages
- 67-76 is downloadable as: <http://www.simtel.net/pub/pd/41812.html>
-
- Finally, there are (were?) commercial products, of which TesSeRact (for
- C-language TSRs) is one of the best known.
-
- ------------------------------
-
- Subject: <Q:08.07> - Why does my interrupt function behave strangely?
- Date: 8 Feb 2002 20:32:03 -0400
-
- Interrupt service routines can be tricky, because you have to do some
- things differently from "normal" programs. If you make a mistake,
- debugging is a pain because the symptoms may not point at what's wrong.
- Your machine may lock up or behave erratically, or just about anything
- else can happen. Here are some things to look for. (See <Q:08.06> [How
- can I write a TSR (terminate-stay-resident utility)?] for general
- techniques that may prevent a problem.)
-
- First, did you fail to set up the registers at the start of your
- routine? When your routine begins executing, you can count on having CS
- point to your code segment and SS:SP point to some valid stack (of
- unknown length), and that's it. In particular, an interrupt service
- routine must set DS to DGROUP before accessing any data in its data
- segments. (If you're writing in a high-level language, the compiler may
- generate this code for you automatically; check your compiler manual.
- For instance, in Borland and Microsoft C, give your function the
- "interrupt" attribute.)
-
- Did you remember to turn off stack checking when compiling your
- interrupt server and any functions it calls? The stack during the
- interrupt is not where the stack-checking code expects it to be.
- (Caution: Some third-party libraries have stack checking compiled in, so
- you can't call them from your interrupt service routine.)
-
- Next, are you calling any DOS functions (INT 21, 25, or 26) in your
- routine? DOS is not re-entrant. This means that if your interrupt
- happens to be triggered while the CPU is executing a DOS function,
- calling another DOS function will wreak havoc. (Some DOS functions are
- fully re-entrant, as noted in Ralf Brown's interrupt list (<Q:02.03>
- [What and where is Ralf Brown's interrupt list?]). Also, your program
- can test, in a way too complicated to present here, when it's safe to
- call non-re-entrant DOS functions. See INT 28, INT 21 AH=34, and INT 21
- AX=5D06 or 5D0B; and consult {Undocumented DOS} by Andrew Schulman. Your
- program must read both the "InDOS flag" and the "critical error flag".)
-
- Is a function in your language library causing trouble? Does it depend
- on some initializations done at program startup that is no longer
- available when the interrupt executes? Does it call DOS (see preceding
- paragraph)? For example, in both Borland and Microsoft C the memory-
- allocation functions (malloc(), etc..) call DOS functions and also
- depend on setups that they can't get at from inside an interrupt; so do
- the standard I/O functions like scanf() and printf(). Many other library
- functions have the same problem, so you can't use them inside an
- interrupt function without special precautions.
-
- Is your routine simply taking too long? This can be a problem if you're
- hooking on to the timer interrupt, INT 1C or INT 8. That interrupt
- expects to be called about every 55 ms, which is 18.2 times a second.
- Therefore your routine, plus any others hooked to the same interrupts,
- must execute in less than 55 ms. If they use even a substantial fraction
- of that time, you'll see significant slowdowns of your foreground
- program. A good discussion is downloadable as:
- <http://www.simtel.net/pub/pd/46893.html>
-
- Did you forget to restore all registers at the end of your routine?
-
- Reader, Morten Welinder, notes that programmers of interrupt procedures
- in Borland/Turbo Pascal 7.0 should be aware that the high words or the
- 32-bit registers are not saved automatically and that the run-time
- library may trash them if, e.g., you use longint operations. The easy
- way around this is to do "Test8086 := 0;" before installing the
- interrupt handler.
-
- Did you chain improperly to the original interrupt? You need to restore
- the stack to the way it was upon entry to your routine, then do a far
- jump (not call) to the original interrupt service routine.
-
- (The process is a little different in high-level languages.)
-
- ------------------------------
-
- Subject: <Q:08.08> - How can I write a device driver?
- Date: 5 Feb 2002 22:03:03 -0400
-
- Many books answer this in detail. Among them are {Advanced MS-DOS} and
- {DOS 5: A Developer's Guide}, cited in the preceding Q. Michael
- Tischer's {PC System Programming}, ISBN 1-55755-036-0, has an extensive
- treatment, as does Dettman and Kyle's {DOS Programmer's Reference: 2d
- Edition}, ISBN 0-88022-458-4. For a really in-depth treatment, look for
- a specialized book like Robert Lai's {Writing MS-DOS Device Drivers},
- ISBN 0-201-13185-4.
-
- ------------------------------
-
- Subject: <Q:08.09> - What can I use to manage versions of software?
- Date: 8 Feb 2002 20:34:22 -0400
-
- A port of the Unix RCS utility is downloadable as:
- <http://www.simtel.net/gnudlpage.php?product=/gnu/gnuish/rcs57pc2.zip&name=rcs57pc2.zip>
- (executable)
- <http://www.simtel.net/gnudlpage.php?product=/gnu/gnuish/rcs57pc1.zip&name=rcs57pc1.zip>
- (source)
-
- This version of RCS is no longer limited to one-character extensions on
- filenames (for example, .CPP and .BAS are now OK).
-
- As for commercial software, I posted a question asking for readers'
- experiences in July 1993 and seven readers responded. PVCS from
- Intersolv (formerly Polymake) got five positive reviews, though several
- readers commented that it's expensive; RCS from MKS got one positive and
- one negative review; Burton TLIB got one negative review; DRTS from ILSI
- got one positive review.
-
- ------------------------------
-
- Subject: <Q:08.10> - What's this 'null pointer assignment' after my C
- program executes?
- Date: 8 Feb 2002 20:35:32 -0400
-
- Somewhere in your program, you assigned a value through a pointer
- without first assigning a value to the pointer. (This might have been
- something like a strcpy() or memcpy() with a pointer as its first
- argument, not necessarily an actual assignment statement.)
-
- Your program may look like it ran correctly, but if you get this message
- you can be certain that there's a bug somewhere.
-
- Microsoft and Borland C, as part of their exit code (after a call to
- exit() or a return from your main function), check whether the location
- 0000 in your data segment contains a different value from what you
- started with. If so, they infer that you must have used an uninitialized
- pointer. This implies that the message will appear at the end of
- execution of your program regardless of where the error actually
- occurred.
-
- To track down the problem, you can put exit() calls at various spots in
- the program and narrow down where the uninitialized pointer is being
- used by seeing which added exit() makes the null-pointer message
- disappear. Or, if your program was compiled with small or medium models,
- which use 16-bit data pointers, tell the debugger to set a watch at
- location 0000 in your data segment. (If data pointers are 32 bits, as in
- the compact and large models, a null pointer will overwrite the
- interrupt vectors at 0000:0000 and probably lock up your machine.)
-
- Under MSC/C++ 7.0, you can declare the undocumented library function:
- extern _cdecl _nullcheck(void);
-
- Sprinkle calls to _nullcheck() through your program at regular
- intervals.
-
- Borland's TechFax document TI726 discusses the null pointer assignment
- from a Borland point of view. It's one of many documents downloadable as
- part of: <http://www.simtel.net/pub/pd/50843.html>
- <ftp://garbo.uwasa.fi/pc/turbopas/bchelp10.zip>
-
- ------------------------------
-
- Subject: <Q:08.11> - How can a batch file tell whether it's being run in
- a DOS box under Windows?
- Date: 5 Feb 2002 22:03:03 -0400
-
- When Windows 3.0 or 3.1 is running, the DOS environment will contain a
- definition of the string windir, in lower case. That's not really
- useful, however, because the batch statement
-
- if "%windir%" == "" ...
-
- will test for an environment variable WINDIR in upper case.
-
- Your only real option is to write a program as suggested by the
- following question, and have it return a value which your batch file can
- test via "if errorlevel".
-
- ------------------------------
-
- Subject: <Q:08.12> - How can my program tell if it's running under
- Windows?
- Date: 8 Feb 2002 20:37:06 -0400
-
- Execute INT 2F AX=4680. If AX returns 0, you're in Windows real mode or
- standard mode (or under the DOS shell). Otherwise, call INT 2F AX=1600.
- If AL returns something other than 0 or 80, you're in Windows 386
- enhanced mode. See PC Magazine 24 Nov 1992 (xi:20) pages 492-493.
-
- For more information, see PC Magazine 26 May 1992 (xi:10) pages 345-346.
- A program, WINMODE, is available as part of:
- <http://www.simtel.net/pub/pd/48500.html>
- <ftp://garbo.uwasa.fi/pc/pcmagvol/vol11n10.zip>
-
- PC Magazine 29 March 1994 (xiii: 6) pages 312 and 320 published a new
- program, WINVER. This would be in:
- <http://www.simtel.net/pub/pd/48540.html>
- <ftp://garbo.uwasa.fi/pc/pcmagvol/vol13n06.zip>
-
- ------------------------------
-
- Subject: <Q:08.13> - How can a program tell whether ANSI.SYS is
- installed?
- Date: 5 Feb 2002 22:03:03 -0400
-
- In DOS 4.0 and above, call INT 2F AX=1A00. If the value FF is returned
- in AL, ANSI.SYS is installed. For more information, see Ralf Brown's
- interrupt list (<Q:02.03> [What and where is Ralf Brown's interrupt
- list?]).
-
- ------------------------------
-
- Subject: <Q:08.14> - How do I copyright software that I write?
- Date: 5 Feb 2002 22:03:03 -0400
-
- You can download a very comprehensive answer from the Internet. Terry
- Carroll posts a six-part Copyright FAQ to misc.legal, news.answers and
- other groups. A short answer follows, not based on that article.
-
- Disclaimer: I am not a lawyer, and this is not legal advice. Also, there
- are very likely to be differences in copyright law among nations. No
- matter where you live, if significant money may be involved, get legal
- advice. The following is adapted (and greatly condensed) from chapter 4
- of the Chicago Manual of Style (13th edition, ISBN 0-226- 10390-0).
-
- In the U.S. (at least), when you write something, you own the copyright.
- (The exception that matters most to programmers is "works made for
- hire", i.e., code you write because your employer or client pays you to.
- A contract, agreed in advance, can vest the copyright in the programmer
- even if an employee; otherwise the employer owns the copyright.) You
- don't have to register the work with the Copyright Office unless (until)
- the copyright is infringed and you intend to bring suit; however, it is
- easier to recover damages in court if you did register the work within
- three months of publication.
-
- From paragraph 4.16 of the Chicago Manual: "... the [copyright] notice
- consists of three parts: (1) the symbol [C-in-a-circle] (preferred
- because it also suits the requirements of the Universal Copyright
- Convention), the word 'Copyright', or the abbreviation 'Copr.', (2) the
- year of first publication, and (3) the name of the copyright owner. Most
- publishers also add the phrase 'All rights reserved' because it affords
- some protection in Central and South American countries...."
-
- Surprise: "(C)" is legally not the same as the C-in-a- circle, so those
- of us who are ASCII-bound must use the word or the abbreviation.
-
- ------------------------------
-
- Subject: <Q:08.15> - How can I place date and time information into
- environment variables?
- Date: 6 Feb 2002 10:16:12 -0400
-
- You can use a program known as NOWMINUS. More information about NOWMINUS
- can be found at <http://www.merlyn.demon.co.uk/programs/nowminus.txt>.
- Pascal source code is included.
-
- ------------------------------
-
- Subject: Conclusion
-
- This is the end of part 4 of 5 parts.
-
- This text is copyright 2003 by Jeffrey Carlyle. All rights reserved.
- Please see the top of this article for additional copyright information.
-
-