home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_PAS
/
NEWCAD.ZIP
/
NEWCAD.PAS
Wrap
Pascal/Delphi Source File
|
1994-02-23
|
42KB
|
913 lines
{$IFDEF Windows}
!! ERROR: This unit is not compatible with Windows applications !!
{$ENDIF}
{$F+,O-}
Unit NewCAD; { New Ctrl-Alt-Del }
{----------------------------------------------------------------------------}
{ }
{ Unit NewCAD Improved Ctrl-Alt-Del Handler for BP7 }
{ 1.00 DOS Real and Protected Mode Programs }
{----------------------------------------------------------------------------}
{ Copyright (c) 1994 Ray Bernard Consulting and Design. All Rights Reserved. }
{ Portions copyright (c) TurboPower Software 1987 - 1993 and used under }
{ Object Professional (tm) product license. All Rights Reserved. }
{ Portions copyright (c) Sunny Hill Software 1985, 1986 and used under }
{ license to TurboPower software. All Rights Reserved. }
{----------------------------------------------------------------------------}
{ }
{ NOTICE }
{ }
{ For use by registered licensees of Object Professional according to the }
{ terms of TurboPower's Object Professional license. This file may be }
{ distributed freely to Object Professional users. }
{ }
{ Any Object Professional users should feel free to use this unit }
{ in any applications where it is appropriate. NOTE: There are no }
{ guarantees expressed or implied here -- use completely at your own risk. }
{ }
{ }
{ PURPOSE }
{ }
{ This unit implements an improved Ctrl-Alt-Del handler in order to provide }
{ both the end user and the application programmer with more options than }
{ the standard abandonment of the program via warm reboot. }
{ }
{ Ctrl-Alt-Del is usually invoked by the user when desiring to halt an }
{ application due to application crash, system crash or too lengthy an }
{ application task (including being stuck in an infinite loop). Lack of }
{ application error trapping can result in infinite loops or program stuck }
{ points, sometimes at the point of interfaces to printers or other }
{ devices. }
{ }
{ Rebooting out of a program often results in unflushed file buffers, }
{ unclosed files, and incorrect or damaged disk directory entries. In }
{ some instances the system is unstable at the point where Ctrl-Alt-Del }
{ is pressed, and no further program execution is possible. But sometimes }
{ (as in the case of a program infinite loop) the application could perform }
{ exit routines successfully, if it could get unstuck to do so. This }
{ capability can come in handy for programmers who are testing software. }
{ }
{ The improved Ctrl-Alt-Del handler provides two aids to better and safer }
{ program termination instead of (or prior to) a system reboot. First of }
{ all, the user can select program termination as an option instead of }
{ system reboot. Program termination is accompilshed by a call to the }
{ Halt procedure, which invokes the program's normal chain of exit }
{ procedures if any have been assigned. For programs that are stuck in }
{ an infinite loop or unable to escape from a hardware interface point, }
{ program termination is the preferred option compared to system reboot. }
{ }
{ Secondly, for unstable situation where only limited processing is }
{ available before the system freezes completely, a special program exit }
{ procedure can be assigned which will be called prior to the call to }
{ Halt. This allows the most important routines to be given an chance }
{ to execute first, independent of the exit procedure chain. Such critical }
{ tasks as closing files or toggling serial port handshake lines may have }
{ a better chance of executing under conditions of system instability, if }
{ they are executed prior to the applications normal exit procedure chain. }
{ }
{ In addition to the usual Ctrl-Alt-Del Warm Boot, a Cold Boot option is }
{ offered which is equivalent to a system reset. }
{ }
{ This Ctrl-Alt-Del handler also has the major advantage of preventing an }
{ instant reboot when Ctrl-Alt-Del is pressed prematurely or accidentally. }
{ }
{ }
{ DESIGN }
{ }
{ This unit installs an Interrupt Service Routine (ISR) which replaces the }
{ standard keyboard ISR. The replacement ISR checks for Ctrl-Alt-Del and }
{ simply passes on all other key presses. When Ctrl-Alt-Del is pressed, }
{ the UserReboot procedure is called, which offers a menu of choices for }
{ the application user. }
{ }
{ }
{ MENU }
{ }
{ Here is the menu invoked by Ctrl-Alt-Del under the new handler: }
{ }
{ ┌───────────────────────────────┐ }
{ │ Ctrl-Alt-Del Reboot Request │ }
{ ├───────────────────────────────┤ }
{ │ Perform (W)arm Boot │ }
{ │ Perform (C)old Boot │ }
{ ├───────────────────────────────┤ }
{ │ No Boot, Just (Q)uit Program │ }
{ │ (Esc) - (R)eturn to Program │ }
{ └───────────────────────────────┘ }
{ }
{ If Ctrl-Alt-Del is pressed again while the menu is displayed, the }
{ handler simply beeps and waits for a valid response. If any other }
{ non-menu keys are pressed, the handle just "eats" them silently }
{ and waits for a valid keypress. Menu choices are case insensitive. }
{ }
{ If Quit program is selected, the previous keyboard handler ISR is }
{ restored upon program exit. If a special exit procedure has been }
{ set by the procedure SetCallBeforeProgramHaltProc, it will be called }
{ before calling Halt. }
{ }
{ A special halt code can be set to cause the application to return a }
{ specific exit code to the operating system upon program termination. }
{ This is useful in situations where it is desireable to report that }
{ the program was halted through the Ctrl-Alt-Del handler. }
{ }
{ SetPgmQuitOption can be used to disable or enable the "(Q)uit Program" }
{ option, which is enabled by default. This is especially applicable to }
{ TSRs since they don't run as a foreground task and cannot subject to }
{ Halting like a foreground application. If the Quit Program option is }
{ disabled, a different menu display is used: }
{ }
{ ┌───────────────────────────────┐ }
{ │ Ctrl-Alt-Del Reboot Request │ }
{ ├───────────────────────────────┤ }
{ │ Perform (W)arm Boot │ }
{ │ Perform (C)old Boot │ }
{ ├───────────────────────────────┤ }
{ │ (Esc) - (R)eturn to the │ }
{ │ Currently Executing Program │ }
{ └───────────────────────────────┘ }
{ }
{ }
{ SPECIAL ACTION }
{ }
{ There is also a user-assignable Special Action procedure variable. }
{ When a procedure has been assigned via SetSpecialActionProc, an }
{ additional menu item will appear: }
{ }
{ ┌───────────────────────────────┐ }
{ │ Ctrl-Alt-Del Reboot Request │ }
{ ├───────────────────────────────┤ }
{ │ Perform (W)arm Boot │ }
{ │ Perform (C)old Boot │ }
{ │ Perform (S)pecial Action │ }
{ │ No Boot, Just (Q)uit Program │ }
{ │ (Esc) - (R)eturn to Program │ }
{ └───────────────────────────────┘ }
{ }
{ This is mainly of use to programmers who wish to interrupt execution of }
{ the program a specific points to display data, write information to }
{ disk, or perform some other specific task. To enable or disable }
{ this Special Action on demand, SetSpecialActionProc takes a boolean }
{ parameter CheckEnvFlag to determine whether or not it should look for }
{ a DOS environment variable SPECIALACTION. When CheckEnvFlag is True, }
{ "Perform (S)pecial Action" will only display if the environment variable }
{ is present and set to "TRUE" or "YES". The DOS commands to set this }
{ variable at the command prompt or in a batch file are" }
{ }
{ SET SPECIALACTION=TRUE or SET SPECIALACTION=YES }
{ }
{ depending on how you wanted it set. This provides a means of enabling }
{ or disabling this option at run-time. }
{ }
{ }
{ TIMEOUT }
{ }
{ If there is no response to the menu, the menu will time out and return }
{ as though the user pressed Esc. Use the SetMenuTimeoutTics to change }
{ the timeout from its default value of about 20 seconds. }
{ }
{ }
{ IMPLEMENTATION }
{ }
{ To install the new handler requires a single call to TakeOverKbdInterrupt. }
{ RestoreKbdInterrupt is called automatically by the unit's exit procedure, }
{ but may be explicitly called by the programmer to deinstall the }
{ Ctrl-Alt-Del handler at a point prior to program exit. RestoreKbdInterrupt }
{ will do nothing if the keyboard interrupt is not taken over by NEWCAD's }
{ keyboard handler at the time RestoreKbdInterrupt is called. }
{ }
{ The user menu procedure, UserReboot, is interfaced so that it may be }
{ called from an application menu as well as by Ctrl-Alt-Del. }
{ }
{ The procedure SetShowKbdTakeover is used to cause Writeln messages to }
{ be written to the screen both when the Ctrl-Alt-Del keyboard handler is }
{ installed and when the previous handler is restored. This is for use }
{ during application testing, to provide visual evidence of the }
{ installation and deinstallation of the replacement keyboard handler. }
{ }
{ Assignments to CallBeforeProgramHaltProc and SpecialActionProc can be }
{ cleared by passing NIL as the procedure parameter. }
{ }
{ The WarmReboot and ColdReboot procedures are taken from the OpInline }
{ Reboot procedure. The standard OpInt ISR support is used to implement }
{ the replacement keyboard handler. }
{ }
{ }
{ CONFLICTS }
{ }
{ There are many TSR programs that take over one or more system interrupts. }
{ Some application programs (like XyWrite) take over the keyboard handler }
{ and trap Ctrl-Alt-Del themselves. You should test the use of this unit }
{ in the system environment in which you expect it to be used. }
{ }
{ This Ctrl-Alt-Del handler was written for operation in DOS text mode. }
{ If you intend to use it in graphics mode, you will have to revise }
{ or eliminate the screen display procedures since they are not compatible }
{ with graphics mode. }
{ }
{ The Ctrl-Alt-Del handler is not meant to be used in a multi-tasking }
{ environment such as DesqView or Windows. }
{ }
{ }
{ TECHNICAL INFORMATION }
{ }
{ This unit was written based on information in the Object Professional }
{ user manuals and the 1991 book PC INTERRUPTS by Ralph Brown and Jim Kyle. }
{ Thanks to the Object Professional library and the excellence of its }
{ documentation, this program was written and tested in a matter of hours }
{ instead of days. The Object Professional ISR support made that possible. }
{ }
{ }
{ THE NEWCAD UNIT }
{ }
{ Additional details can be seen from the source code and comments, }
{ contained in the file NEWCAD.PAS. A simple but effective test program }
{ (TNEWCAD.PAS) is included in a commented section of the source code file. }
{ }
{ -Ray Bernard }
{ February 22, 1994 }
{----------------------------------------------------------------------------}
{ }
{ VERSION HISTORY }
{ }
{ Tue 02-22-1994 Ray Bernard }
{ Version 1.00 released for CIS TurboPower Forum library and the }
{ TurboPower BBS. }
{ }
{ Tue 02-22-1994 Ray Bernard }
{ Version 1.01 released. Support for DOS environment variable }
{ SPECIALACTION was in documentation but left out of unit. }
{ }
{ }
{----------------------------------------------------------------------------}
{ }
{ Please send any comments or suggestions for enhancement to: }
{ }
{ Ray Bernard }
{ Ray Bernard Consulting and Design }
{ Glendale, CA }
{ CIS: 73354,3325 }
{ Tel: 818-507-7017 }
{ Fax: 818-240-3394 }
{ }
{----------------------------------------------------------------------------}
(* ---TNEWCAD.PAS: SAMPLE TEST PROGRAM FOR NEWCAD----------------------------
{$F+}
program TNewCAD; { Test the NewCAD unit in real or protected modes.}
{$IFDEF Windows}
!! ERROR: This program is not compatible with Windows applications !!
{$ENDIF}
Uses
OpCrt,
OpString,
NewCAD;
const
_Esc = 283;
var
KeyCount : Word;
procedure PromptUser; forward; {so it can be called by TestSpecialActionProc}
{-Prompt user with instructions, increment prompt counter}
procedure TestProgramHaltProc;
{-A procedure to test the execution of the assignable program exit procedure}
begin
Writeln;
Writeln('Program perform-before-halt routines would be executed here.');
Writeln('Program ended by user selection from Ctrl-Alt-Del menu.');
end;
procedure TestSpecialActionProc;
{-A procedure to test the execution of the assignable Special Action procedure}
begin
Writeln;
Writeln('Special Action Memory Report:');
Writeln('MaxAvail is: ',MaxAvail,' bytes.');
Writeln('MemAvail is: ',MemAvail,' bytes.');
Writeln;
PromptUser;
end;
procedure PromptUser;
{-Prompt user with instructions, increment prompt counter}
begin
Inc(KeyCount);
Writeln(KeyCount:3,
'. Press any key ... Ctrl-Alt-Del to test ... Esc to Quit.');
if Odd(KeyCount) then {make the Special Action available only }
SetSpecialActionProc(Nil) {on even numbered prompts, as a means of}
else {testing the Special Action feature }
SetSpecialActionProc(TestSpecialActionProc);
end;
{-Test out a number of the program features, displaying start and end messages}
begin
KeyCount := 0;
Writeln;
{$IFDEF DPMI} {show which mode we're running in}
Writeln('Test of New Ctrl-Alt-Del handler in protected mode.');
{$ELSE}
Writeln('Test of New Ctrl-Alt-Del handler in real mode.');
{$ENDIF}
SetCheckEnvFlag(False); {set True to test this feature}
SetShowKbdTakeover(True); {activate display of ISR install/deinstall}
if ParamCount > 0 then {option for testing with/without exit proc}
if StUpCase(ParamStr(1)) = 'USEEXITPROC' then
SetCallBeforeProgramHaltProc(TestProgramHaltProc) {set pgm exit proc}
else
if StUpCase(ParamStr(1)) = 'NOQUITPGM' then
SetPgmQuitOption(False); {test TSR Mode}
{ This is what makes it all happen: }
TakeOverKbdInterrupt; {install new Ctrl-Alt-Del keyboard handler}
Writeln;
repeat {give test program something to do}
PromptUser;
until ReadKeyWord = _Esc;
Writeln;
Writeln('Normal end of program.'); {verify normal termination}
end.
--------------------------------------------------------------------------- *)
{***} Interface {***}
type
ProcVarType = procedure;
procedure SetCADHaltValue(B : Byte);
{-Allows application to set Exit Code for Ctrl-Alt-Del initiated halt}
procedure SetCheckEnvFlag(B : Boolean);
{-Set Performing Special Action to follow the SPECIALACTION DOS env variable}
procedure SetShowKbdTakeover(B : Boolean);
{-For application testing, writes message when new keyboard ISR installed}
procedure SetCallBeforeProgramHaltProc(P : ProcVarType);
{-Set the procedure to be called just prior to halting program}
procedure SetSpecialActionProc(P : ProcVarType);
{-Set the Special Action procedure to be called by menu selection}
procedure SetPgmQuitOption(B : Boolean);
{-Enable or disable the "No Boot, Just (Q)uit Program" menu item}
procedure SetMenuTimeoutTics(T : LongInt);
{-Set the number of timer tics the menu will wait before timing out}
procedure TakeOverKbdInterrupt;
{-Take over the keyboard interrupt to replace default Ctrl-Alt-Delete response}
procedure RestoreKbdInterrupt;
{-Restore the keyboard interrupt if we took it over}
procedure UserReboot;
{-Give user choices and if halting or rebooting }
{ execute the appplicatio's assigned halt procedure. }
procedure WarmReboot; { based upon OpInline's Reboot }
{-Perform soft reboot equivalent to usual Ctrl-Alt-Del}
{$IFNDEF Dpmi} {for real mode only; see implementation for pmode version}
inline(
$B8/$40/$00/ {mov ax,$40}
$8E/$D8/ {mov ds,ax}
$C7/$06/$72/$00/$34/$12/ {mov word ptr [$0072],$1234}
$EA/$00/$00/$FF/$FF); {jmp far $FFFF:$0000}
{$ENDIF}
procedure ColdReboot; { based upon OpInline's Reboot }
{-Perform a reset (the one that starts the memory check)}
{$IFNDEF Dpmi} {for real mode only; see implementation for pmode version}
inline(
$B8/$40/$00/ {mov ax,$40}
$8E/$D8/ {mov ds,ax}
$C7/$06/$72/$00/$00/$00/ {mov word ptr [$0072],$0000}
$EA/$00/$00/$FF/$FF); {jmp far $FFFF:$0000}
{$ENDIF}
{***} Implementation {***}
Uses
DOS,
OpInt,
OpCrt,
OpColor,
OpString,
{$IFDEF DPMI }
DPMI,
{$ENDIF}
OpInline;
const
X1 = 24; { X and Y coordinates of Reboot window which are }
X2 = 56; { used for display and to set size of save buffer }
Y1 = 8;
Y2 = 16;
BiosDataSeg = $0040; { Bios Data Area segment }
KbdStatusOfs = $0017; { offset of Keyboard Status Byte }
BiosDataTicsOfs = $006C; { offset of Bios Timer Tics }
CheckEnvFlag : Boolean = False; { if True check DOS env SPECIALACTION }
PgmQuitOK : Boolean = True; { flag for enable/disable quit option }
MenuTimeoutTics : Longint = 18*20; { default timeout of about 10 seconds }
MenuTextAttr : Byte = WhiteOnRed; { change these constants to change }
MenuHighAttr : Byte = YellowOnRed; { the menu display colors }
MenuTextMono : Byte = LtGrayOnBlack; { these are the monochrome values }
MenuHighMono : Byte = WhiteOnBlack; { to be automatically assigned }
ScrBufAllocated : Boolean = False; { has screen buffer been allocated? }
WinSaved : Boolean = false; { has screen below window been saved? }
Halting : Boolean = False; { flag to activate pgm exit proc msg display }
HaveKbdInterrupt : Boolean = False; { keep track of interrupt ownership }
KeyBInt = $09; { the keyboard interrupt we are taking over }
KbdIntIsrHandle = 16; { recommended ISR handle starting }
{ number per the OPRO manual }
type
ScrBuf =
array[X1..X2,Y1..Y2,1..2] of Byte; { buffer to save what's under window }
BootRequestType = { user selectable responses }
(NoBoot,QuitProgram,WarmBoot,ColdBoot,SpecialAction);
GetKeyType =
record { convenient variant record }
case Flag : Byte of { for handling keys codes, }
0 : (Value : Word); { access to word value, ch }
1 : (Ch : Char; ScanCode : Byte); { or scan code }
end;
const
Scan_C = 46; { scan codes for keys we want to process }
Scan_Q = 16;
Scan_R = 19;
Scan_S = 31;
Scan_W = 17;
Scan_Del = 83;
Scan_Esc = 1;
var
Key : GetKeyType; { see type declarations above }
BootRequest : BootRequestType; { see type declarations above }
InUserReboot : Boolean; { global flag to prevent reentrancy }
ScrBufPtr : ^ScrBuf; { don't use up data segment, allocate with pointer }
BufPtr : Pointer absolute ScrBufPtr; { SaveWindow required parameter }
BiosTics : ^LongInt; { unit init sets to Bios Data Area timer tics }
const
CADHaltValue : Byte = 0; { To be be set by application if desired }
ShowKbdTakeover : Boolean = False; { for application testing see: }
{ procedure TakeOverKbdInterrupt }
var
CallBeforeProgramHaltProc : ProcVarType;
{ Initialized to nil, you may assign your own procedure to it using }
{ SetCallBeforeProgramHaltProc to close files or do some required }
{ tasks before the program is halted or the system is rebooted. }
SpecialActionProc : ProcVarType;
{ Initialized to nil, you may assign your own procedure to it using }
{ SetSpecialActionProc to perform a task via the Ctrl-Alt-Del menu }
{ selection "Perform (S)pecial Action". }
{$IFDEF Dpmi}
procedure WarmReboot;
{-Perform soft reboot equivalent to usual Ctrl-Alt-Del}
var
Regs : DPMIRegisters;
begin
Word(Ptr(Seg0040, $72)^) := $1234; { magic number for soft reboot }
FillChar(Regs, SizeOf(Regs), 0);
Regs.CS := $FFFF;
Regs.IP := $0000;
if CallFarRealModeProc(0, nil, Regs) <> 0 then ;
end;
{$ENDIF}
{$IFDEF Dpmi}
procedure ColdReboot;
{-Perform a reset (the one that starts the memory check)}
var
Regs : DPMIRegisters;
begin
Word(Ptr(Seg0040, $72)^) := $0000; { value for full reset }
FillChar(Regs, SizeOf(Regs), 0);
Regs.CS := $FFFF;
Regs.IP := $0000;
if CallFarRealModeProc(0, nil, Regs) <> 0 then ;
end;
{$ENDIF}
procedure SetCADHaltValue(B : Byte);
{-Allows application to set Exit Code for Ctrl-Alt-Del initiated halt}
begin
CADHaltValue := B;
end;
procedure SetCheckEnvFlag(B : Boolean);
{-Set Performing Special Action to follow the SPECIALACTION DOS env variable}
begin
CheckEnvFlag := B;
end;
procedure SetShowKbdTakeover(B : Boolean);
{-For application testing, writes message when new keyboard ISR installed}
begin
ShowKbdTakeover := True;
end;
procedure SetCallBeforeProgramHaltProc(P : ProcVarType);
{-Set the procedure to be called just prior to halting program}
begin
CallBeforeProgramHaltProc := P;
end;
procedure SetSpecialActionProc(P : ProcVarType);
{-Set the Special Action procedure to be called by menu selection}
begin
SpecialActionProc := P;
end;
function ProgramHaltProcInstalled : Boolean;
{-Return True if procedure variable is not nil}
begin
ProgramHaltProcInstalled := @CallBeforeProgramHaltProc <> nil;
end;
function SpecialActionProcInstalled : Boolean;
{-Return True if procedure variable is not nil}
begin
SpecialActionProcInstalled := @SpecialActionProc <> nil;
end;
procedure SetPgmQuitOption(B : Boolean);
{-Enable or disable the "No Boot, Just (Q)uit Program" menu item}
begin
PgmQuitOK := B;
end;
procedure SetMenuTimeoutTics(T : LongInt);
{-Set the number of timer tics the menu will wait before timing out}
begin
MenuTimeoutTics := T;
end;
function GetCurrentTics : LongInt;
{-Return current Bios Data Area timer tics}
begin
GetCurrentTics := BiosTics^;
end;
procedure PerformProgramHaltProc;
{-Perform assigned program halt tasks}
begin
if ProgramHaltProcInstalled then
CallBeforeProgramHaltProc;
end;
procedure PerformSpecialActionProc;
{-Perform special action procedure}
begin
if SpecialActionProcInstalled then
SpecialActionProc;
end;
procedure RestoreKbdInterrupt;
{-Restore the keyboard interrupt if we took it over}
begin
if HaveKbdInterrupt then
begin
HaveKbdInterrupt := False;
RestoreVector(KbdIntIsrHandle);
if ShowKbdTakeover then
Writeln(#10#13,'Keyboard handler has been restored.');
end
else
if ShowKbdTakeover then
Writeln(#10#13,'No need to restore Keyboard handler ... ',
'program did not have control.');
end;
function SpecialActionOkay : Boolean;
{-Return True unless CheckEnvFlag is True and DOS environment }
{ variable SPECIALACTION is not set to YES or TRUE. }
var
S : String;
begin
SpecialActionOkay := True;
if not CheckEnvFlag then
Exit;
S := 'FALSE';
S := StUpCase(GetEnv('SPECIALACTION'));
SpecialActionOkay := (S = 'TRUE') or (S = 'YES');
end;
procedure SoundBlip;
{-Blip for repeated Ctrl-Alt-Del keypresses}
begin
Sound(1600);
Delay(100);
NoSound;
end;
procedure DrawWindowFrame;
{-Draw the window frame to prepare for subsequent message display}
begin
FastWrite('┌───────────────────────────────┐',Y1+0,X1,MenuTextAttr);
FastWrite('│ Ctrl-Alt-Del Reboot Request │',Y1+1,X1,MenuTextAttr);
FastWrite('├───────────────────────────────┤',Y1+2,X1,MenuTextAttr);
FastWrite('│ │',Y1+3,X1,MenuTextAttr);
FastWrite('│ │',Y1+4,X1,MenuTextAttr);
FastWrite('├───────────────────────────────┤',Y1+5,X1,MenuTextAttr);
FastWrite('│ │',Y1+6,X1,MenuTextAttr);
FastWrite('│ │',Y1+7,X1,MenuTextAttr);
FastWrite('└───────────────────────────────┘',Y1+8,X1,MenuTextAttr);
end;
procedure ShowNewCADMenu;
{-Add the new Ctrl-Alt-Del menu items to the window}
begin
DrawWindowFrame;
FastWrite('│ Perform (W)arm Boot │',Y1+3,X1,MenuTextAttr);
FastWrite('│ Perform (C)old Boot │',Y1+4,X1,MenuTextAttr);
if PgmQuitOK then
begin
FastWrite('│ No Boot, Just (Q)uit Program │',Y1+6,X1,MenuTextAttr);
FastWrite('│ (Esc) - (R)eturn to Program │',Y1+7,X1,MenuTextAttr);
end
else
begin
FastWrite('│ (Esc) - (R)eturn to the │',Y1+6,X1,MenuTextAttr);
FastWrite('│ Currently Executing Program │',Y1+7,X1,MenuTextAttr);
end;
if SpecialActionProcInstalled and SpecialActionOkay then
begin
FastWrite('│ Perform (S)pecial Action │',Y1+5,X1,MenuTextAttr);
FastWrite('(S)', Y1+5,X1+11,MenuHighAttr);
end;
FastWrite('(W)', Y1+3,X1+11,MenuHighAttr);
FastWrite('(C)', Y1+4,X1+11,MenuHighAttr);
if PGmQuitOK then
begin
FastWrite('(Q)', Y1+6,X1+17,MenuHighAttr);
FastWrite('(Esc)',Y1+7,X1+ 3,MenuHighAttr);
FastWrite('(R)', Y1+7,X1+11,MenuHighAttr);
end
else
begin
FastWrite('(Esc)',Y1+6,X1+ 3,MenuHighAttr);
FastWrite('(R)', Y1+6,X1+11,MenuHighAttr);
end;
end;
procedure Notify(Msg : String);
var
X,Y : byte;
begin
DrawWindowFrame;
X := X2 - (X2-X1) div 2; { find middle column of window }
Y := Y1+3; { use 3rd line of window for display line }
if Halting and ProgramHaltProcInstalled then
begin
Dec(X,10); { adjust to starting col }
FastWrite('Performing tasks then',Y,X,MenuHighAttr);
Inc(X,10); { restore to middle col }
Inc(Y); { increment display line }
end;
Dec(X,Length(Msg) div 2); { adjust to starting col }
FastWrite(Msg,Y,X,MenuHighAttr);
Delay(2000);
end;
procedure RestoreScreen;
{-Restore screen area under Ctrl-Alt-Del menu window}
begin
if WinSaved then
RestoreWindow(X1,Y1,X2,Y2,not ScrBufAllocated,BufPtr);
WinSaved := False;
end;
procedure UserReboot;
{-Give user choices and if halting or rebooting }
{ execute the appplicatio's assigned halt procedure. }
var
MenuStartTics : LongInt; { record current tics for timeout check }
begin
InUserReboot := True; { set reentrancy flag }
BootRequest := NoBoot; { set a default response }
Halting := False; { set initial value }
WinSaved := SaveWindow(X1,Y1,X2,Y2,not ScrBufAllocated,BufPtr);
ShowNewCADMenu;
MenuStartTics := GetCurrentTics;
Key.Value := 0;
repeat { get menu choices }
if GetCurrentTics < MenuStartTics then { cheap way of handling midnight }
MenuStartTics := GetCurrentTics;
if GetCurrentTics >= MenuStartTics + MenuTimeoutTics then
Key.ScanCode := Scan_Esc; { set per timeout }
if KeyPressed then
Key.Value := ReadKeyWord;
until (Key.ScanCode in [Scan_Esc,Scan_C,Scan_Q,Scan_R,Scan_S,Scan_W]);
case Key.ScanCode of
Scan_W : BootRequest := WarmBoot;
Scan_C : BootRequest := ColdBoot;
Scan_Q : BootRequest := QuitProgram;
Scan_S : BootRequest := SpecialAction;
Scan_Esc,
Scan_R : BootRequest := NoBoot;
end; {case}
case BootRequest of { handle menu choices }
NoBoot: ; { do nothing }
ColdBoot: begin
Halting := True; { set flag to display "Performing Tasks" }
Notify('Performing Cold Boot...');
RestoreScreen;
PerformProgramHaltProc;
ColdReboot;
end;
WarmBoot: begin
Halting := True; { set flag to display "Performing Tasks" }
Notify('Performing Warm Boot...');
RestoreScreen;
PerformProgramHaltProc;
WarmReboot;
end;
SpecialAction : if SpecialActionProcInstalled and SpecialActionOkay then
begin
Notify('Performing Special Action...');
RestoreScreen; { restore prior to Special Action }
PerformSpecialActionProc;
{ do not exit - must clear reentrancy flag }
end;
QuitProgram:
if PgmQuitOK then
begin
Halting := True; { flag to display "Performing Tasks" }
Notify(' Quitting Program... ');
RestoreScreen;
PerformProgramHaltProc;
Halt(CADHaltValue); { will invoke exit procedure chain }
end; { see TP/BP help and manuals }
end; {case}
RestoreScreen; { may not have been called yet }
InUserReboot := False; { clear reentrancy flag }
end;
procedure KbdIsr(BP : Word); Interrupt;
{-Services keyboard interrupt and calls UserReboot if Ctrl-Alt-Del was }
{ pressed, otherwise just passes control to previous Keyboard ISR. }
var
Regs : IntRegisters absolute BP;
const
KbdInPort = $60; { Keyboard input port }
KbdOutPort = $61; { Keyboard output port for clear/enable }
Alt_Mask = $08; { bit mask for alt key status }
Ctrl_Mask = $04; { bit mask for ctrl key status }
var
B : byte;
KbdStatusBytePtr : ^Byte; { point to kbd status byte in real or pmode }
begin
{$IFDEF DPMI }
KbdStatusBytePtr := Ptr(BiosDataSele,KbdStatusOfs);
{$ELSE}
KbdStatusBytePtr := Ptr(BiosDataSeg,KbdStatusOfs);
{$ENDIF}
B := KbdStatusBytePtr^;
if B and Ctrl_Mask <> 0 then { If Ctrl key is pressed check }
if B and Alt_Mask <> 0 then { if Alt is pressed. If both }
begin { are pressed check to see if }
B := Port[KbdInPort]; { the Del key is also pressed. }
if B = Scan_Del then { If so handle Ctrl-Alt-Del. }
begin
B := Port[KbdOutPort]; { read kbd control port }
Port[KbdOutPort] := B or $80; { set high bit to reset keyboard }
Port[KbdOutPort] := B; { restore port value }
SendEOI; { clear kbd hardware interrupt }
if InUserReboot then { Don't reenter UserReboot. Beep }
SoundBlip { and skip a second Ctrl-Alt-Del. }
else
UserReboot; { call our Ctrl-Alt-Del handler }
Exit;
end;
end;
{ Chain to previous interrupt handler }
ChainInt(Regs,IsrArray[KbdIntIsrHandle].OrigAddr);
end;
procedure TakeOverKbdInterrupt;
{-Take over the keyboard interrupt to replace default Ctrl-Alt-Delete response}
begin
if not HaveKbdInterrupt then
begin
if InitVector(KeybInt,KbdIntIsrHandle,@KbdIsr) then
begin
HaveKbdInterrupt := True; { set our flag for deinstall reference }
New(ScrBufPtr); { allocate the screen save buffer now }
ScrBufAllocated := True; { in case we're short on memory later }
if CurrentDisplay = MonoHerc then
begin
MenuTextAttr := MenuTextMono; { autodetect monochrome systems }
MenuHighAttr := MenuHighMono; { and set menu colors accordingly }
end;
if ShowKbdTakeover then
Writeln('Ctrl-Alt-Del has been taken over '+
'by program keyboard handler.');
end
else
if ShowKbdTakeover then
Writeln('Error: Could not take over the keyboard interrupt.')
end
else
begin
if ShowKbdTakeover then
begin
Writeln('Ctrl-Alt-Del has ALREADY been taken over '+
'by program keyboard handler.');
Writeln('No action is being taken at this time.');
end;
Exit;
end;
end;
var
SavedExitProc : pointer;
procedure NoCadExitProc;
{-Automatically restore previous keyboard handler at program exit }
begin
ExitProc := SavedExitProc;
RestoreKbdInterrupt;
end;
{ Put procedure to call RestoreKbdInterrupt in the exit procedure chain }
begin
SavedExitProc := ExitProc; { save previous exit proc }
ExitProc := @NoCadExitProc; { install new exit proc in chain }
@CallBeforeProgramHaltProc := nil; { must initialize procedure variable }
@SpecialActionProc := nil; { must initialize procedure variable }
{$IFDEF DPMI }
BiosTics := Ptr(BiosDataSele, BiosDataTicsOfs);
{$ELSE}
BiosTics := Ptr(BiosDataSeg, BiosDataTicsOfs);
{$ENDIF}
end.