386 lines
10 KiB
C
386 lines
10 KiB
C
|
//Copyright (c) 1998 - 1999 Microsoft Corporation
|
||
|
|
||
|
|
||
|
|
||
|
/* Get the standard C includes */
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <process.h>
|
||
|
#include <dos.h>
|
||
|
#include <errno.h>
|
||
|
|
||
|
#define FALSE 0
|
||
|
#define TRUE 1
|
||
|
#define STARTMON "StartMonitor"
|
||
|
|
||
|
/*=============================================================================
|
||
|
== External Functions Used
|
||
|
=============================================================================*/
|
||
|
|
||
|
int OptionsParse( int, char * [] );
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Local Functions Used
|
||
|
=============================================================================*/
|
||
|
|
||
|
char GetCommandLine(char *);
|
||
|
|
||
|
/*=============================================================================
|
||
|
== Global data
|
||
|
=============================================================================*/
|
||
|
|
||
|
char bQ = FALSE;
|
||
|
char bDefaults = FALSE;
|
||
|
char bStartMonitor = FALSE;
|
||
|
char bStopMonitor = FALSE;
|
||
|
int dDetectProbationCount = -1;
|
||
|
int dInProbationCount = -1;
|
||
|
int dmsAllowed = -1;
|
||
|
int dmsSleep = -1;
|
||
|
int dBusymsAllowed = -1;
|
||
|
int dmsProbationTrial = -1;
|
||
|
int dmsGoodProbationEnd = -1;
|
||
|
int dDetectionInterval = -1;
|
||
|
|
||
|
|
||
|
|
||
|
typedef struct _DOSKBDIDLEKNOBS
|
||
|
{
|
||
|
short int DetectProbationCount;
|
||
|
short int InProbationCount;
|
||
|
short int BusymsAllowed;
|
||
|
short int msAllowed;
|
||
|
short int msGoodProbationEnd;
|
||
|
short int msProbationTrial;
|
||
|
short int msSleep;
|
||
|
short int msInSystemTick;
|
||
|
short int DetectionInterval;
|
||
|
} DOSKBDIDLEKNOBS, *PDOSKBDIDLEKNOBS;
|
||
|
|
||
|
typedef union {
|
||
|
unsigned long longword;
|
||
|
struct {
|
||
|
unsigned short usloword;
|
||
|
unsigned short ushiword;
|
||
|
} words;
|
||
|
} LONGTYPE;
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* main
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* argc (input)
|
||
|
* number of arguments
|
||
|
* argv (input)
|
||
|
* pointer to arguments
|
||
|
*
|
||
|
* EXIT:
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
void
|
||
|
main( int argc, char * argv[] )
|
||
|
{
|
||
|
LONGTYPE totalticks;
|
||
|
LONGTYPE totalpolls;
|
||
|
unsigned short usminpolls;
|
||
|
unsigned short usmaxpolls;
|
||
|
int rc;
|
||
|
char bExec = FALSE;
|
||
|
|
||
|
DOSKBDIDLEKNOBS data = {-1,-1,-1,-1,-1,-1,-1,-1,-1};
|
||
|
|
||
|
//get command line options into global variables
|
||
|
if (OptionsParse( argc, argv )) return; //non zero return code is failure
|
||
|
|
||
|
//if /Defaults then we do a special bop to reset everything
|
||
|
//and then we continue as a display information only
|
||
|
//dont worry about optimizing for the /q case
|
||
|
|
||
|
if (bDefaults) {
|
||
|
_asm {
|
||
|
push ax
|
||
|
mov al,3 ;for the set registry defaults subparm
|
||
|
mov ah,254 ;for the main pop parm
|
||
|
|
||
|
mov BYTE PTR cs:crap,0c4h
|
||
|
mov BYTE PTR cs:crap+1,0c4H
|
||
|
mov BYTE PTR cs:crap+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap
|
||
|
crap:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
|
||
|
; db 0c4H;,0c4H,16H ;the bop
|
||
|
|
||
|
pop ax
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
_asm {
|
||
|
push ax
|
||
|
push bx
|
||
|
push cx
|
||
|
push dx
|
||
|
|
||
|
mov al,0 ;for first BOP
|
||
|
mov ah,254 ;for first BOP
|
||
|
mov bx,WORD PTR dDetectProbationCount
|
||
|
mov cx,WORD PTR dInProbationCount
|
||
|
mov BYTE PTR cs:crap1,0c4h
|
||
|
mov BYTE PTR cs:crap1+1,0c4H
|
||
|
mov BYTE PTR cs:crap1+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap1
|
||
|
crap1:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
|
||
|
; db 0c4H;,0c4H,16H ;the bop
|
||
|
mov WORD PTR data.DetectProbationCount,bx
|
||
|
mov WORD PTR data.InProbationCount,cx
|
||
|
mov WORD PTR data.msInSystemTick,dx
|
||
|
|
||
|
mov al,1 ;for second BOP
|
||
|
mov ah,254 ;for second BOP
|
||
|
mov bx,WORD PTR dBusymsAllowed
|
||
|
mov cx,WORD PTR dmsAllowed
|
||
|
mov dx,WORD PTR dmsSleep
|
||
|
mov BYTE PTR cs:crap2,0c4h
|
||
|
mov BYTE PTR cs:crap2+1,0c4H
|
||
|
mov BYTE PTR cs:crap2+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap2
|
||
|
crap2:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
; db 0c4H;,0c4H,16H ;the BOP
|
||
|
mov WORD PTR data.BusymsAllowed,bx
|
||
|
mov WORD PTR data.msAllowed,cx
|
||
|
mov WORD PTR data.msSleep,dx
|
||
|
|
||
|
mov al,2
|
||
|
mov ah,254
|
||
|
mov bx,WORD PTR dmsGoodProbationEnd
|
||
|
mov cx,WORD PTR dmsProbationTrial
|
||
|
mov dx,WORD PTR dDetectionInterval
|
||
|
|
||
|
mov BYTE PTR cs:crap3,0c4h
|
||
|
mov BYTE PTR cs:crap3+1,0c4H
|
||
|
mov BYTE PTR cs:crap3+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap3
|
||
|
crap3:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
; db 0c4H;,0c4H,16H
|
||
|
mov WORD PTR data.msGoodProbationEnd,bx
|
||
|
mov WORD PTR data.msProbationTrial,cx
|
||
|
mov WORD PTR data.DetectionInterval,dx
|
||
|
|
||
|
pop dx
|
||
|
pop cx
|
||
|
pop bx
|
||
|
pop ax
|
||
|
|
||
|
}
|
||
|
|
||
|
// Turn on keyboard monitoring
|
||
|
if (bStartMonitor) {
|
||
|
|
||
|
_asm {
|
||
|
mov al,4
|
||
|
mov ah,254
|
||
|
|
||
|
mov BYTE PTR cs:crap4,0c4h
|
||
|
mov BYTE PTR cs:crap4+1,0c4H
|
||
|
mov BYTE PTR cs:crap4+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap4
|
||
|
crap4:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
; db 0c4H;,0c4H,16H
|
||
|
}
|
||
|
|
||
|
// If they specified the name of the app, try to exec it
|
||
|
if (argc > 2) {
|
||
|
char *pch = NULL;
|
||
|
char bBatFile = FALSE;
|
||
|
|
||
|
// If this is a batch file, pass to command processor
|
||
|
if ((pch = strrchr(argv[2],'.')) && !stricmp(pch, ".bat")) {
|
||
|
bBatFile = TRUE;
|
||
|
} else {
|
||
|
rc = spawnvp(P_WAIT, argv[2], &argv[2]);
|
||
|
}
|
||
|
bExec = TRUE;
|
||
|
|
||
|
if ((rc == -1) || bBatFile) {
|
||
|
// maybe they tried to run a batch file, so look for xxx.bat
|
||
|
if ((errno == ENOENT) || (bBatFile)) {
|
||
|
char pcmdline[256];
|
||
|
|
||
|
if (GetCommandLine(pcmdline)) {
|
||
|
rc = system(pcmdline);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bStopMonitor || bExec) {
|
||
|
_asm {
|
||
|
push di
|
||
|
push si
|
||
|
mov al,5
|
||
|
mov ah,254
|
||
|
|
||
|
mov BYTE PTR cs:crap5,0c4h
|
||
|
mov BYTE PTR cs:crap5+1,0c4H
|
||
|
mov BYTE PTR cs:crap5+2,16H
|
||
|
;we need to flush the prefetch buffer for self modifying code
|
||
|
;asm in c will not allow db directive
|
||
|
jmp short crap5
|
||
|
crap5:
|
||
|
nop
|
||
|
nop
|
||
|
nop
|
||
|
; db 0c4H;,0c4H,16H
|
||
|
|
||
|
mov totalticks.words.usloword, ax ; get the polling data
|
||
|
mov totalticks.words.ushiword, bx ; get the polling data
|
||
|
mov totalpolls.words.usloword, cx
|
||
|
mov totalpolls.words.ushiword, dx
|
||
|
mov usmaxpolls, si
|
||
|
mov usminpolls, di
|
||
|
pop si
|
||
|
pop di
|
||
|
}
|
||
|
|
||
|
|
||
|
// If they entered /stopmonitor or the app exited while monitoring,
|
||
|
// display the statistics
|
||
|
if (!bExec || (bExec && (rc != -1))) {
|
||
|
double avg;
|
||
|
|
||
|
printf("\nTotal polls: %lu\n", totalpolls.longword);
|
||
|
printf("Total ticks: %lu\n", totalticks.longword);
|
||
|
avg = (double)(totalpolls.longword)/(double)(totalticks.longword);
|
||
|
printf("Avg. polls/tick: %.1f\n", avg);
|
||
|
printf("Minimum polls per detection interval: %u\n", usminpolls);
|
||
|
printf("Maximum polls per detection interval: %u\n", usmaxpolls);
|
||
|
printf("Number of milliseconds in a system timer tick is %hd\n",
|
||
|
data.msInSystemTick);
|
||
|
printf("DetectionInterval = %hd tick(s) (%hd msec)\n",
|
||
|
data.DetectionInterval,
|
||
|
data.DetectionInterval*data.msInSystemTick);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bQ && !bStartMonitor && !bStopMonitor) {
|
||
|
printf("Number of milliseconds in a system timer tick is %hd\n",
|
||
|
data.msInSystemTick);
|
||
|
|
||
|
printf("DetectionInterval = %hd tick(s) (%hd msec)\n",
|
||
|
data.DetectionInterval,
|
||
|
data.DetectionInterval*data.msInSystemTick);
|
||
|
|
||
|
printf("DetectProbationCount= %hd\nInProbationCount= %hd\n",
|
||
|
data.DetectProbationCount,data.InProbationCount);
|
||
|
|
||
|
printf("msAllowed= %hd\nmsSleep= %hd\n",data.msAllowed,data.msSleep);
|
||
|
|
||
|
printf("BusymsAllowed= %hd\nmsProbationTrial= %hd\n\
|
||
|
msGoodProbationEnd= %hd\n",data.BusymsAllowed,
|
||
|
data.msProbationTrial,data.msGoodProbationEnd);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************************
|
||
|
*
|
||
|
* GetCommandLine
|
||
|
*
|
||
|
* Return the command line following the /startmonitor switch.
|
||
|
*
|
||
|
* ENTRY:
|
||
|
* char *pbuff: pointer to hold command line (returned)
|
||
|
*
|
||
|
* EXIT:
|
||
|
* SUCCESS: returns TRUE
|
||
|
* FAILURE: returns FALSE
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
|
||
|
char GetCommandLine(char *pbuff)
|
||
|
{
|
||
|
char *pch, *pcmdline;
|
||
|
char bfound = FALSE;
|
||
|
|
||
|
// copy the command line from the PSP to a near buffer
|
||
|
if (pcmdline = malloc(256)) {
|
||
|
_asm {
|
||
|
push ds
|
||
|
push si
|
||
|
push di
|
||
|
mov ax, _psp
|
||
|
mov ds, ax
|
||
|
mov si, 80h
|
||
|
mov di, pcmdline
|
||
|
xor ax,ax
|
||
|
lodsb
|
||
|
mov cx,ax
|
||
|
rep movsb
|
||
|
xor ax,ax
|
||
|
stosb
|
||
|
pop di
|
||
|
pop si
|
||
|
pop ds
|
||
|
}
|
||
|
pch = pcmdline;
|
||
|
while (pch && !bfound) {
|
||
|
|
||
|
// Get next / or -
|
||
|
pch = strchr(pch, '/');
|
||
|
if (!pch) {
|
||
|
pch = strchr(pch, '-');
|
||
|
}
|
||
|
|
||
|
// If we found a / or -, skip over it and check for startmonitor
|
||
|
if (pch) {
|
||
|
pch++;
|
||
|
|
||
|
if (!strnicmp(pch, STARTMON, sizeof(STARTMON) - 1)) {
|
||
|
pch += sizeof(STARTMON);
|
||
|
bfound = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we found /startmonitor, return the rest of the command line
|
||
|
if (bfound) {
|
||
|
strcpy(pbuff, pch);
|
||
|
return(TRUE);
|
||
|
}
|
||
|
free(pcmdline);
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|