home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Internet Info 1997 December
/
Internet_Info_CD-ROM_Walnut_Creek_December_1997.iso
/
faqs
/
alt
/
answers
/
msdos-programmer-faq
/
part4
< prev
next >
Wrap
Internet Message Format
|
1997-10-01
|
40KB
Path: senator-bedfellow.mit.edu!faqserv
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 4/5
Supersedes: <msdos-programmer-faq/part4_873193441@rtfm.mit.edu>
Followup-To: comp.os.msdos.programmer
Date: 30 Sep 1997 09:50:07 GMT
Organization: The COMP-FAQ Project
Lines: 1154
Sender: jeffrey@carlyle.com (Jeffrey Carlyle)
Approved: news-answers-request@MIT.Edu
Expires: 3 Nov 1997 09:49:05 GMT
Message-ID: <msdos-programmer-faq/part4_875612945@rtfm.mit.edu>
References: <msdos-programmer-faq/part1_875612945@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: 1997/08/04
Originator: faqserv@penguin-lust.MIT.EDU
Xref: senator-bedfellow.mit.edu comp.os.msdos.programmer:92883 alt.msdos.programmer:39080 comp.answers:28271 alt.answers:29278 news.answers:113416
Archive-name: msdos-programmer-faq/part4
Comp-os-msdos-programmer-archive-name: dos-faq-pt4.txt
Posting-frequency: 28 days
Last-modified: 04 Aug 97
------------------------------
Subject: comp.os.msdos.programmer FAQ part 4/5
For more information about this FAQ list please see Part 1.
FAQ updates can be found at
<http://www.premiernet.net/~carlyle>.
This is part 4 of the frequently asked question list for
the newsgroup comp.os.msdos.programmer.
Part 4:
Section 7. Other hardware questions and problems
Section 8. Other software questions and problems
------------------------------
Subject: comp.os.msdos.programmer FAQ
Comp.os.msdos.programmer FAQ Version 1997.08
Copyright 1997 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.
=============================
TABLE OF CONTENTS
=============================
Part 1:
Section 1. General FAQ and Newsgroup Information
Section 2. General Reference
Part 2:
Section 3. Compile and Link
Section 4. Keyboard
Part 3:
Section 5. Disks and files
Section 6. Serial ports (COM ports)
Part 4:
Section 7. Other hardware questions and problems
Section 8. Other software questions and problems
Part 5:
Section 9. Downloading
Section 10. Vendors and products
------------------------------
Subject: Section 7. Other hardware questions and problems
<Q: 7.01> - Which 80x86 CPU is running my program?
<Q: 7.02> - How can a C program send control codes to my
printer?
<Q: 7.03> - How can I redirect printer output to a file?
<Q: 7.04> - Which video adapter is installed?
<Q: 7.05> - How do I switch to 43- or 50-line mode?
<Q: 7.06> - How can I find the Microsoft mouse position and
button status?
<Q: 7.07> - How can I access a specific address in the PC's
memory?
<Q: 7.08> - How can I read or write my PC's CMOS memory?
<Q: 7.09> - How can I access memory beyond 640K?
<Q: 7.10> - How can I use the protected mode?
<Q: 7.11> - How can I tell if my program is running on a
PS/2-style machine.
<Q: 7.12> - Is there a 80x87 math unit installed?
------------------------------
Subject: <Q: 7.01> - Which 80x86 CPU is running my program?
Date: Sun, 03 Aug 97 20:32:26 CST
SNIPPETS (see <Q: 2.08>) contains C-callable x86 assembly
language code for determining the type of CPU in
CPUCHECK.ASM.
------------------------------
Subject: <Q: 7.02> - How can a C program send control codes
to my printer?
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: 7.03> - How can I redirect printer output to a
file?
Please see <Q: 5.08> "How can I redirect printer output to
a file?"
------------------------------
Subject: <Q: 7.04> - Which video adapter is installed?
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: 7.05> - How do I switch to 43- or 50-line mode?
The following file contains .COM utilities and .ASM source
code:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/screen/vidmode.zi
p>
------------------------------
Subject: <Q: 7.06> - How can I find the Microsoft mouse
position and button status?
Date: Sun, 03 Aug 97 20:35:38 CST
Use INT 33 AX=3, described in Ralf Brown's interrupt list
<Q: 2.03>.
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
<ftp://ftp.simtel.net/pub/simtelnet/msdos/mouse>
------------------------------
Subject: <Q: 7.07> - How can I access a specific address in
the PC's memory?
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.
- 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: 7.08> - How can I read or write my PC's CMOS
memory?
Date: Sun, 03 Aug 97 20:35:57 CST
There are a great many public-domain utilities that do
this. The following files can be downloaded from
<ftp://ftp.simtel.net/pub/simtelnet/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:
<ftp://garbo.uwasa.fi/pc/ts/tsutle22.zip>
<ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl/tsutle22.z
ip>
Good reports of CMOS299.ZIP have been posted:
<ftp://cantva.canterbury.ac.nz/pub/pc/cmos299.zip>
Of the above, my only experience is with CMOSRAM, which
seems to work 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: 7.09> - How can I access memory beyond 640K?
Date: Sun, 03 Aug 97 14:24:56 CST
PC Magazine 29 June 1993 (xii: 12) pages 302-304 carry an
article, "How DOS Programs Can Use Over 1MB of RAM".
See also <Q: 7.10> - How can I use the protected mode?
------------------------------
Subject: <Q: 7.10> - How can I use the protected mode?
Date: Sun, 03 Aug 97 20:43:48 CST
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.06> - What and where is DJGPP?"
If you are using Borland C++ Version 4.xx, you can purchase
the Borland PowerPack for DOS Version 1.00. 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).
There are more extenders out there. One notable DOS
extender is Adam Seychell's DOS32. It can be found at:
<ftp://ftp.cdrom.com/.24/demos/code/pmode/dos32b35.zip>
------------------------------
Subject: <Q: 7.11> - How can I tell if my program is running
on a PS/2-style machine.
Use INT 15 AX=C0, described in Ralf Brown's interrupt list
<Q: 2.03>.
------------------------------
Subject: <Q: 7.12> - Is there a 80x87 math unit installed?
SNIPPETS (see <Q: 2.08>) contains C-callable assembly code
to determine presence of coprocessor in NDPCHECK.ASM.
------------------------------
Subject: Section 8. Other software questions and problems
<Q: 8.01> - How can a program reboot my PC?
<Q: 8.02> - How can I time events with finer resolution than
the system clock's 55 ms (about 18 ticks a second)?
<Q: 8.03> - How can I find the error level of the previous
program?
<Q: 8.04> - How can a program set DOS environment variables?
<Q: 8.05> - How can I change the switch character to - from
/?
<Q: 8.06> - How can I write a TSR (terminate-stay-resident
utility)?
<Q: 8.07> - Why does my interrupt function behave strangely?
<Q: 8.08> - How can I write a device driver?
<Q: 8.09> - What can I use to manage versions of software?
<Q: 8.10> - What's this "null pointer assignment" after my C
program executes?
<Q: 8.11> - How can a batch file tell whether it's being run
in a DOS box under Windows?
<Q: 8.12> - How can my program tell if it's running under
Windows?
<Q: 8.13> - How can a program tell whether ANSI.SYS is
installed?
<Q: 8.14> - How do I copyright software that I write?
------------------------------
Subject: <Q: 8.01> - How can a program reboot my PC?
Date: Tue, 7 Mar 95 12:00:00 CDT
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 "307. 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/ts/tsfaqp*.zip>
<ftp://ftp.simtel.net/pub/simtelnet/msdos/info/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:
2.03>).
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: 8.02> - How can I time events with finer
resolution than the system clock's 55 ms (about 18
ticks a second)?
Date: Sun, 03 Aug 97 20:47:02 CST
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:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/info/pctim*.zip>
The following files, among others, are downloadable from
SimTel:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/sysutl>:
atim.zip 4783 881126 Precision program timing for
AT
<ftp://ftp.simtel.net/pub/simtelnet/msdos/c>
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://ftp.simtel.net/pub/simtelnet/msdos/turbopas/bonus507
.zip>
<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/ts/tsfaqp*.zip>
<ftp://ftp.simtel.net/pub/simtelnet/msdos/info/tsfaqp*.zip>
------------------------------
Subject: <Q: 8.03> - How can I find the error level of the
previous program?
Date: Sun, 03 Aug 97 20:47:59 CST
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:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/batchutil/errlvl1
3.zip>
(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: 8.04> - How can a program set DOS environment
variables?
Date: Sun, 03 Aug 97 20:52:18 CST
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.
I looked at some of these, and liked this file the best:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/envutil/rbsetnv1.
zip>
<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://ftp.simtel.net/pub/simtelnet/msdos/batchutl/string25
.zip>
<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: 2.03> for details and cautions.
------------------------------
Subject: <Q: 8.05> - How can I change the switch character
to - from /?
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: 8.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: 8.06> - How can I write a TSR (terminate-stay-
resident utility)?
Date: Sun, 03 Aug 97 21:03:10 CST
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:
- The Alternate Multiplex Interrupt Specification,
downloadable as
<ftp://ftp.simtel.net/pub/simtelnet/msdos/info/altmpx35.zip>
or
<ftp://garbo.uwasa.fi/pc/programming/altmpx35.zip>
- Ralf Brown's assembly-language implementation of the
spec, with utilities in C, is downloadable as
<ftp://ftp.simtel.net/pub/simtelnet/msdos/asmutil/amisl092.z
ip>
or
<ftp://garbo.uwasa.fi/pc/c-lang/amisl092.zip>
- John English has created a wonderful C++ class for
creating TSRs which includes several examples. It is
downloadable as:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/cpluspls/tsr100je.
zip>
- Douglas Boling's MASM template for a TSR is
downloadable as
<ftp://ftp.simtel.net/pub/simtelnet/msdos/asmutl/template.zi
p>
- A posted article mentions Boling's "Strategies and
Techniques for Writing State-of-the-Art TSRs that Exploit MS-
DOS 5", Microsoft Systems Journal, Jan-Feb 1992, Volume 7,
Number 1, pages 41-59, with examples downloadable in
<ftp://ftp.simtel.net/pub/simtelnet/msdos/msjournl/msjv7-
1.zip>
- 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
<ftp://ftp.simtel.net/pub/simtelnet/msdos/c/tsrc.zip>
- Software examples to accompany Kaare Christian's "Using
Microsoft C Version 5.1 to Write Terminate-and-Stay-Resident
Programs", Microsoft Systems Journal, September 1988, Volume
3, Number 5, pages 47-57 are downloadable as
<ftp://oak.oakland.edu/pub/msdos/msjournl/msjv3-5.zip>
Finally, there are commercial products, of which TesSeRact
(for C-language TSRs) is one of the best known.
------------------------------
Subject: <Q: 8.07> - Why does my interrupt function behave
strangely?
Date: Sun, 03 Aug 97 21:05:15 CST
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:
8.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: 2.03>. 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:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/info/intshare.zip
>
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: 8.08> - How can I write a device driver?
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: 8.09> - What can I use to manage versions of
software?
Date: Sun, 03 Aug 97 21:07:50 CST
A port of the Unix RCS utility is downloadable as:
<ftp://ftp.simtel.net/pub/simtelnet/msdos/gnuish/rcs55ax.z
ip> (EXE and docs)
<ftp://ftp.simtel.net/pub/simtelnet/msdos/gnuish/rcs55as.z
ip> (source)
<ftp://garbo.uwasa.fi/pc/unix/alrcs5ex.zip> (EXE and
docs?)
This version of RCS is no longer limited to one-character
extensions on filenames (for example, .CPP and .BAS are now
OK).
An RCS56 is available at a number of archive sites, but it
appears to be unauthorized. In response to a query, Keith
Petersen, SimTel administrator, said that RCS56 was removed
from SimTel at the author's request because it did not
contain source code and thus was in violation of the GNU
copyleft.
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: 8.10> - What's this "null pointer assignment"
after my C
program executes?
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
<ftp://ftp.simtel.net/pub/simtelnet/msdos/turbo-
c/bchelp10.zip>
<ftp://garbo.uwasa.fi/pc/turbopas/bchelp10.zip>
------------------------------
Subject: <Q: 8.11> - How can a batch file tell whether it's
being run in a DOS box under Windows?
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: 8.12> - How can my program tell if it's running
under Windows?
Date: Sun, 03 Aug 97 21:12:33 CST
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
<ftp://ftp.simtel.net/pub/simtelnet/msdos/pcmag/vol11n10.zi
p>
<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
<ftp://ftp.simtel.net/pub/simtelnet/msdos/pcmag/vol13n06.zi
p>
<ftp://garbo.uwasa.fi/pc/pcmagvol/vol13n06.zip>
------------------------------
Subject: <Q: 8.13> - How can a program tell whether ANSI.SYS
is installed?
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: 2.03>).
------------------------------
Subject: <Q: 8.14> - How do I copyright software that I
write?
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: End
(FAQ updates can be found at
<http://www.premiernet.net/~carlyle>.)
(End of comp.os.msdos.programmer FAQ Version 1997.08 Part
4/5)
(This text is copyright 1997 by Jeffrey Carlyle. All rights
reserved.)
// Jeffrey Carlyle, Bowling Green, Kentucy USA
//
// comp.os.msdos.programmer FAQ maintainer
// <http://www.premiernet.net/~carlyle>