Interrupts_in_C++,_create_TSRs_+_serial,_wsrc
所属分类:VC书籍
开发工具:C#
文件大小:146KB
下载次数:2
上传日期:2005-01-08 22:32:50
上 传 者:
liwen
说明: 这是一个C++编程文档
(This is a C Programming Document)
文件列表:
DOSFREE (0, 1993-08-30)
DOSFREE\DOSFREE.CPP (6129, 1993-09-01)
DOSFREE\DOSFREE.H (2853, 1993-09-01)
DOSFREE\EXAMPLES (0, 1993-08-31)
DOSFREE\EXAMPLES\DOSFREE.CPP (6129, 1993-09-01)
DOSFREE\EXAMPLES\DOSFREE.H (2853, 1993-09-01)
DOSFREE\EXAMPLES\ISC.CPP (10692, 1993-09-01)
DOSFREE\EXAMPLES\ISC.H (6022, 1993-09-01)
DOSFREE\EXAMPLES\ISCSERVE.ASM (2004, 1993-09-01)
DOSFREE\EXAMPLES\KBD.CPP (2693, 1993-09-01)
DOSFREE\EXAMPLES\KBD.H (3254, 1993-09-01)
DOSFREE\EXAMPLES\SNAP.CPP (3445, 1993-09-01)
DOSFREE\EXAMPLES\SNAP.DSK (1900, 1993-09-01)
DOSFREE\EXAMPLES\SNAP.EXE (9392, 1993-09-01)
DOSFREE\EXAMPLES\SNAP.PRJ (5906, 1993-09-01)
DOSFREE\EXAMPLES\TCCONFIG.TC (3898, 1993-09-01)
DOSFREE\ISC.CPP (10692, 1993-09-01)
DOSFREE\ISC.H (6022, 1993-09-01)
DOSFREE\ISCSERVE.ASM (2004, 1993-09-01)
EXAMPLES (0, 1993-08-30)
EXAMPLES\EXAMPLE1.CPP (2719, 1993-09-01)
EXAMPLES\EXAMPLE1.DSK (1182, 1993-09-01)
EXAMPLES\EXAMPLE1.EXE (9120, 1993-09-01)
EXAMPLES\EXAMPLE1.PRJ (5428, 1993-09-01)
EXAMPLES\EXAMPLE2.CPP (2547, 1993-09-01)
EXAMPLES\EXAMPLE2.DSK (370, 1993-09-01)
EXAMPLES\EXAMPLE2.EXE (9392, 1993-09-01)
EXAMPLES\EXAMPLE2.PRJ (5428, 1993-09-01)
EXAMPLES\EXAMPLE3.CPP (1829, 1993-09-01)
EXAMPLES\EXAMPLE3.DSK (850, 1993-09-01)
EXAMPLES\EXAMPLE3.EXE (6720, 1993-09-01)
EXAMPLES\EXAMPLE3.PRJ (5331, 1993-09-01)
EXAMPLES\EXAMPLE4.CPP (3105, 1993-09-01)
EXAMPLES\EXAMPLE4.DSK (829, 1993-09-01)
EXAMPLES\EXAMPLE4.EXE (7232, 1993-09-01)
EXAMPLES\EXAMPLE4.PRJ (5365, 1993-09-01)
EXAMPLES\ISC.CPP (10692, 1993-09-01)
EXAMPLES\ISC.H (6022, 1993-09-01)
EXAMPLES\ISCSERVE.ASM (2004, 1993-09-01)
EXAMPLES\TCCONFIG.TC (3898, 1993-09-01)
... ...
----------------------------------------------------------------------------
ISC V3.66
by: Ofer Laor (AKA LeucroTTA)
----------------------------------------------------------------------------
ISC- Interrupt Service Class
-----------------------------------------------
hooking interrupts into C++ objects made easy
-----------------------------------------------
----------------------------------------------------------------------------
NEW in version
----------------------------------------------------------------------------
ver 3.66 - ISC destructor turned virtual. Encorperated a __NOT_TSR__ macro
for the guys that are using ISC in embedded systems (via Paradigm systems'
"Paradigm Locate" package), as well as interrupt handlers in non-TSRs.
To use this feature define __NOT_TSR__ before including ISC.h (or place
this macro in the defines section in Options|Compiler options. Killed the
ASSUME DS!=SS problem (no specific settings neccessary for SMALL & COMPACT
models). Also, Added KBD class that hooks keyboard (for programs with a
hotkey). Added a DOSFREE example (DOSFREE + KBD) that snaps a picture of
the screen and appends to a file called . Dosfree allocates more
stack for it's ISC (so that sprintf, and other stack memory hogs will not
crash the system). More docs on the derived classes can be found here also.
+++ ISC turned PD. Info about that can be found in the end of this file.
----------------------------------------------------------------------------
OVERVIEW
----------------------------------------------------------------------------
This article describes a class for Turbo / Borland C++ (checked with
versions 3.x), for hooking interrupts into C++ objects. For those of us
who need to write heavy TSRs or regular programs that need interrupt
handlers - hooking the interrupt handlers into the C++ code was a bit of
a fuss. Borland made it easy enough for us to hook interrupts into C code
through the "interrupt" keyword, but objects could not use this feature.
The reason for this is that every C++ object needs an identifier to be passed
to it when using one of it's functions. This identifier (called "this") is the
real name of the object and is used by it to access data and function members.
When a member function is called - (a.foo() for example) a is the "this" and
foo() is the function to be called. When the actual call is made - a is
pushed unto the stack and foo() is called. Now, foo() uses data members
through "this" and knows it's own name through it. If you could somehow
get foo's address and called it (something that C++ prohibits and protects
its programmers from) you would not pass on the right "this" and cause a
malfunction when foo() accesses an internal data member or calls a
virtual function. What people would usually do is to make a static interrupt
function for each of the interrupts in the system. This is a common solution
(in lack of a better one). ISC offers a different approach - and a more useful
one.
A class that uses ISC will derive from it and overload a function called
isr() - (Interrupt Service Routine). Now all that needs doing is activating
the interrupt (activate(int_num)) and the interrupt is hooked into that
OBJECT!!! What this means is that if you have a class for Serial
communications that works through interrupts - you don't have to make a
different interrupt function for each of the possible ports you'd be using-
you would write the class as you would any other. Each of the instances of
the Serial class you are writing will hook into a different interrupt (or the
same one if needs be).
ISC works in a simple way, it produces what Windows 3.x programmers call
a thunk (a small piece of code that contains your data segment and sets it
just before the real call is made- or in this case the id of your object) for
each of the objects that are currently hooked into interrupts through ISC.
ISC reproduces the thunk for each object. Each Thunk contains in it's code
- the id of the object that owns it. Then it calls a special dispatcher that
handles the call to the right ISC derived object. The dispatcher also sets
up the stack for all the ISC users (so that no stack cramming is needed in
your interrupt routines). The dispatcher also sets up a structure that
contains the registers that the interrupt entered through (so you may modify
them or use them if they are needed).
In the first two versions of this class I tried to utilize (without much
success) properties in the local C++ compilers (how the virtual function
tables work) and tried to call virtual functions directly from ASM. While
this was fairly easy to do (a bit of reverse engineering) - it was compiler
dependent (and even compiler version dependent). I have seen the light and
this version is COMPILER INDEPENDENT (although the ASM routines are written
to work specifically under tasm - and a bit of semantic changes might be
needed to make it work under different assemblers). A close look will have
taught you that porting the code to your local machine, and compiler is a
simple enough task!
Since the ISC class is mainly for use in TSRs (although it is usable in
regular programs just as well)- these are some of the pitfalls that TSR
writers in C++ will encounter:
ISC CANNOT be compiled under the TINY memory model (there is a problem
with the segment locations in the asm module. As it couldn't be solved
up till now, I don't think I'll spend more time with it...
----------------------------------------------------------------------------
ISC functions.
----------------------------------------------------------------------------
ISC provides your classes with the ability to hook into hardware and
software interrupts.
it does this by providing 2 "overloadable" functions: both named isr.
* HARDWARE INTERRUPTS: virtual void isr(void);
just overload this function and when your class is activated the isr will
be called whenever the hardware calls it.
* SOFTWARE INTERRUPTS: virtual void isr(IREGS& regs);
IREGS is NOT compatible with the regular REGS union although it is very
close to it (it has MORE registers than REGS). The 32 bit option is not
supported in the interrupt keyword - so I have not incorporated it into ISC.
* IREGS contains two structures:
struct IBYTEREGS {
unsigned char al, ah, bl, bh;
unsigned char cl, ch, dl, dh;
};
struct IWORDREGS {
unsigned int ax, bx, cx, dx;
unsigned int si, di, ds, es, cs, flags, ip, bp;
};
you may access IWORDREGS and IBYTEREGS through .x and .h :-
IREGS regs;
...
regs.x.ax= regs.h.bl+ regs.h.dl;
all of these registers are what the register situation was BEFORE the
interrupt was called.
if you change the content of the regs parameter that is passed to you in
the isr function - this will be the value of that register when the
interrupt exits.
* void activate(const int in_num) - will hook the interrupt handler to the
function isr (software). The default software isr calls the hardware isr,
so that if you hook to the hardware isr - you will be called as required.
But if you overload both - you must literally call the hardware interrupt
handler in order for it to work. This function prevents the programmer
from activating an ISC derived class twice (you must deactivate it first).
* void deactivate(void) - will unhook you from the interrupt. The destructor
of ISC also does that - so unless you'd like to unhook and rehook to another
interrupt - you shouldn't need this function. The function enables you to call
activate again (for rehooking to another interrupt, for example).
some GENERAL PURPOSE functions are also available here as part of ISC -
since I use ISC to build TSR's in C++ (for example a real time communication
program that runs in the background)- I though it useful to provide TSR
functions here as well. These STATIC functions ( is_TSR and TSR) take care
of managing your TSR needs (the most basic ones).
* static int is_TSR(const char *app_name)- will figure out if your program is
running already as a TSR. You must choose a unique application name and put
it's name as parameter. Returns (1) if you are RESIDENT already and (0) if
you're not. I used a simple method for this - (for more info. read the
source file).
* static int TSR(const int exit_code= 0, unsigned long extra_heap= 0)- will
keep you resident in memory. if you call TSR() it will attempt to stay
resident (minimal memory possible) and return 0 to DOS. You can return any
exit code by calling TSR(1) for example. If your TSR needs more room to grow
(extra interrupt-time heap for example) put the extra heap (in bytes) in the
second parameter. Remember that in the LARGER models malloc and new use the
far heap so that you may not be able to use your preallocated memory in them
(and most likely no heap at all will be available in those memory models at
all). Problem with run time heap (SMALLER MEMORY MODELS ONLY) is that when
you allocate past the max heap you declared (in parameter extra_heap) the
program will crash (in a probably very bizarre way!!!). USE THOUGHTFULLY.
The method for finding the minimum memory necessary for reallocation is
an algorithm I am quite proud of- it works in all the memory models and with
a lot less memory that the sources Borland provides in their help of KEEP.
It can be converted to C very easily (change new into malloc!). This is a
brand new method (new from V3.6) and is not prone to heap failures and
possible problems (as the previous versions were).
One ISC specific static function is reallocStack(unsigned long stacklen):-
* static int reallocStack(unsigned stackLen)- will reallocate the hardware
interrupt stack frame to the specified size. If you need to call this
function you must:- either call it while no ISC derived class is active or
simply disable interrupts before you call it (don't forget to re-enable them).
----------------------------------------------------------------------------
ISC data members.
----------------------------------------------------------------------------
* There are 2 data members of major importance - int_num and old_vect;
both must not be changed (since deactivate uses them to recover the state
of the interrupt as it was before ISC was used.
int_num - contains the number of the interrupt hook.
old_vect - is a pointer to the function that was the previous interrupt
vector. It can be called - by -> old_vect();
DO NOT CALL IT WITH PARAMETERS!!!!
To get the registers to be as they were use PSEUDO VARIABLE (_AX, _BX...)
or call the vector in some alternative way!!!
Beware of changing _BP (will demolish automatic parameter referencing),
and _DS (will demolish static parameter referencing).
* There are 3 static data members that refer to the hardware stack frame:-
StackFrame- points to the actual stack frame.
StackFrameLen- contains the current stack frame length.
ISCcount- holds the number of ISC objects that currently exist in the
system.
----------------------------------------------------------------------------
EXAMPLES
----------------------------------------------------------------------------
There are 4 examples:-
EXAMPLE1:- is a resident that keeps a timer tick watcher on screen (by
incrementing the first char on the top left of the screen once every timer
tick). Also, it keeps a keyboard interrupt watcher right next to it. This
example shows how to make an ISC derivative- how to check if already
resident. How to use 2 ISCs together...
EXAMPLE2:- is an example of a software interrupt - it is a software
interrupt that beeps with a length and pitch which are passed as register
parameters. The main routine will test it and verify that it had not
failed through return values (also through register as well as flags).
** - when using ISC classes on automatic (local vars) rememeber:- NOT ALL
COMPILERS call DESTRUCTORS for automatic vars if exit() or do-alike funcs
(like abort()) run (they simply do not call the destructors), so that loca
ISC vars might not be freed and the interrupt will stay hooked, resulting
in a crash in most cases). So, using stack ISC (or derivitives) is ill
advised unless you know what you're doing...
EXAMPLE3:- is a more complex example of a class that has to do a lot of
processing (each one taking longer than the timer tick interval).
it slows the computer down (so before running it).
EXAMPLE4:- sends a novell look alike "send" message onto the screen (which
stops the forground and waits for the user to free it). Pretty annonying
program, so it before running.
----------------------------------------------------------------------------
MORE DIRECTORIES:- an overview
----------------------------------------------------------------------------
Also included are some more files and directories:-
ISC :- This directory contains all that you need in order to work with
ISC. (Include ISC.cpp and ISCSERVE.asm into your project and #include
ISC.h in your source files).
KBD :- keyboard hooking. example can be found in DOSFREE/EXAMPLE.
DOSFREE :- allows you to execute dos functions (except 0-ch meaning that
line input through scanf is forbidden) - such as opening a file and reading
writing or deleting it.
an example can be found that hooks a keyboard (via the kbd class),
and snap a shot from the screen into a file called snap.dat in the local
directory. The example program (called snap) is a parellel to a snap
program that is found in the "DOS ENCYLOPEDIA" from Microsoft press.
The hotkey for this program is SHIFT-TAB.
SERIAL :- Some more advanced ISC derivative classes that handle interrupt
driven serial and modem communications. Although ISC has changed in the
past year - no changes have been made to these sources. Previously these
sources were distributed under XSERIAL.arj and XSERIAL1.arj. Also included
is a sample of a Buffer class I used that a colleague of mine wrote...
there are two examples in serial- RECEIVE and TRANSMIT:- RECEIVE
will set COM1 to 9600baud, 8bytes, 1stopbit, No parity- and put on the
screen anything that comes in from the port. The program will stop if
a key is typed in, as well as if the string "hello there!!!" is entered
from the com port.
TRANSMIT will transmit the string "hello there!!!" to com1 (same port
settings as receive), wait until the string is completely sent and exit.
These classes works great in TSRs (that's what I use it for).
----------------------------------------------------------------------------
KBD
----------------------------------------------------------------------------
This class makes hooking into keyboard hotkeys very easy.
Constructor:-
KBD(unsigned char scan_code, unsigned char controls= 0, int kill_key= 1);
first parameter is the hot-key itself (KB_A is the letter A , etc.).
the hot-key's shift state (ALT/CTRL/SHIFT) is found in controls. The control
codes start with KBS (KBS_LSHIFT, etc.). For Ctrl-Alt-A you would pass
KB_A as the scan_code, KBS_CTRL| KBS_ALT as the controls parameter. The
third parameter is kill_key. To kill the key is to make the hot-key not
visible to the forground app. The default is 1 (meaning make the hot-key
invisible to forground).
To hook a hotkey, just derive from KBD and overload the virtual function
hotkey. This function gets called if the hotkey matches.
An example is joined with DOSFREE (take a look at DOSFREE's example).
----------------------------------------------------------------------------
DOSFREE
----------------------------------------------------------------------------
This class allows using DOS functions inside your TSRs in an easy manner.
Go - call this function when you want your app to run (use this instead of
calling AppFunc directly.
AppFunc - overload this function (by deriving to DOSFREE), this function is
called when it is safe to use dos. Call this function using Go. Do not use
int21h funcs 0-0ch within this function.
There is an example of DOSFREE in directory examples. The example uses
the KBD class to hook a hotkey, and DOSFREE to photograph the screen and
save it into a file. The hotkey for this program is SHIFT-TAB. (Window's
users beware..).
----------------------------------------------------------------------------
SERIAL CLASSES
----------------------------------------------------------------------------
These classes are 3:- SERIAL_PORT, XONOFF, MODEM.
To use serial port comunications you need only know the following:-
create a serial port with serial port num. as constructor param (1 is
com1, 1-4 are allowed in this way). For compatible systems, a diffrent
constructor is provided that allows changing every param in the serial
port. If you prefer changing/ setting the com port on a later occasion
use activate with com num param. To set the serial port's communication
parameters use function-
void set_up_port(const long baud_rate,const BYTE word_len,
const BYTE parity, const BYTE stop_bits);
for example:- com1.set_up_port(9600, 8, 'N', 1) sets up com1 object
with a 9600 baud rate, 8 bits, no parity, and 1 stop bit.
to read from that object use com1>> my_char (my_char is an unsigned char).
to write to that object use com1<< my_char (ditto).
to peek at the next char that arrived without pulling it from the buffer use:
com1> my_peek_char
MODEM, XONOFF adhere to the same principles but have additional functions
and will also handle the flow control (outgoing only).
The BUFF class is a buffer class that adheres to the same I/O operators,
and can be used as FIFO, or as an array (however the user wishes). This
class was jointly designed and written with my colleague- Ram Machness,
god bless him (;-D).
----------------------------------------------------------------------------
NOTE
----------------------------------------------------------------------------
If you need to hook with ISC to a software interrupt like int13h or int21h
don't forget that when you call { old_vect() } you must set the correct
registers to what they were after the isr was called (these register values
are in the IREGS parameter passed to isr). Usually the pseudo variables
_AX, _BX, _FLAGS, etc... will do just fine. Also remember that the values
of the registers after the software interrupts are called might be needed
by the forground too (so you can put them back into the IREGS parameter).
WARNING- if you do not do these things you will probabl ... ...
近期下载者:
相关文件:
收藏者: