_BRIDGING THE GAP WITH RESIDENT_C_ by Charles Albert Mirho [LISTING ONE] /* tsr.h */ #define FALSE 0 #define TRUE 1 /* Some commonly used scan codes */ #define SC_ESCAPE 0x01 #define SC_PRTSC 0x37 #define SC_SPACE_BAR 0x39 #define SC_CAP_LOCK 0x3A #define SC_NUM_LOCK 0x45 #define SC_SCROLL_LOCK 0x46 /* toggle key codes for inittsr() */ #define ALT_KEY 0x08 #define CTRL_KEY 0x04 #define LEFT_SHIFT 0x02 #define RIGHT_SHIFT 0x01 /* TSR signature */ #define SIG *((unsigned int *)"ESI") extern unsigned char Tsr24Result, Tsr24Error; /* used for int24 */ struct HKEYS{ unsigned char hotscancode; unsigned char hottoggle; unsigned char key_identifier; }; struct sharedata{ /* shared structure definition */ unsigned oldpsp; unsigned ourpsp; unsigned ourextra; unsigned tsr_size; unsigned tsr_stat; unsigned char hottoggle; unsigned char hotscancode; unsigned char safewait; unsigned char oldbreak; unsigned char freeflag; unsigned char beepflag; unsigned char more_hotkeys; unsigned char cdummy; struct HKEYS far *hotkey_data; int far *indosflag; int far *critflag; int far *oldint8; int far *oldint9; int far *oldint10; int far *oldint13; int far *oldint16; int far *oldint1b; int far *oldint1c; int far *oldint21; int far *oldint23; int far *oldint24; int far *oldint28; int far *shareptr; unsigned int oldss; unsigned int oldsp; unsigned int ourss; unsigned int oursp; int far *resident; int far *dosstack; int far *olddta; int far *ourdta; unsigned int ourcs; unsigned long vec_table[256]; unsigned long our_floats[44]; unsigned long float_hold[44]; }; [LISTING TWO] /************************************************************************** * File Name: tsr.c * Description: Main body of the TSR. Traps hot keys LSHIFT-ALT-C (copy text), * LSHIFT-ALT-P (paste text), LSHIFT-ALT-R (remove TSR from memory). **************************************************************************/ #include #include #include "tsr.h" #include "isr.h" #include "clip.h" extern unsigned long cculMode; extern int cciColumns; extern int cciRows; extern BYTE far *ccfpVidMem; extern ATTRIBUTE ccatDef25x80; extern ATTRIBUTE ccatSecond25x80; extern BYTE *ccabAttrBuffer; //Undo buffer of attributes char szDataBuffer[3000] = "Yo de do de do."; //Holds transfer data BOOL bNewData = FALSE; #define SCAN_C 46 //popup scan code #define SCAN_P 25 //popup scan code #define SCAN_R 19 //menu scan code unsigned int uiCCSig = 0x9191; //randomly selected signature code extern int _hotkey_num; //will hold value of hot key pressed //additional hot keys to trap extern char *kb_str_ptr; //points to buffer for the //keystuffer routine to use extern unsigned kb_in_progress; //non-zero if more bytes waiting //in buffer to be stuffed extern int _hotkey_hit; //true if a hot key was pressed struct HKEYS ahkHotKeys[] = { SCAN_R, LEFT_SHIFT | ALT_KEY, 1, SCAN_C, LEFT_SHIFT | ALT_KEY, 2, }; void tsrpost (); void tsrpre (); void vResprog(); //function which gets control upon invocation int isr60(); int isr61(); RECTANGLE rtScreen; RECTANGLE rtRect = {20,5,20,5}; /**************************************************************************** FUNCTION: Main PURPOSE: Main of TSR program ****************************************************************************/ main (int argc, char *argv[]) { int irc; cciColumns = 80; cciRows = 25; ccfpVidMem = (unsigned char far *) 0xB8000000; MAKEATTRIBUTE (ccatDef25x80, COLOR_TEXT_BLUE, COLOR_TEXT_RED, INTENSITY_HIGH, NOBLINK); MAKEATTRIBUTE (ccatSecond25x80, COLOR_TEXT_RED, COLOR_TEXT_BLUE, INTENSITY_HIGH, NOBLINK); if ((ccabAttrBuffer = (BYTE *) calloc (cciColumns*cciRows, sizeof(BYTE)))==NULL) { printf ("Allocation error\n"); } //End if (not enough memory) //Test if TSR already loaded. If not, do initialization code if (!tsrloaded (uiCCSig)) { //initialization code //initializes a TSR that works off the system timer if ((irc=inittsr (LEFT_SHIFT|ALT_KEY, SCAN_P, vResprog, 1000, uiCCSig, SIG, (void far *) 0L)) != 0) { printf ("Error loading TSR: Error %d\n", irc); return 1; } //End if (failed to initialize TSR) } //End if (TSR not loaded already) } //End function (main) /* This function is called on every clock tick, approx. 18 times per sec. It should do its processing and exit as quickly as possible */ void vResprog () { static bStuffing = FALSE; //The variable kb_in_progress holds the number of bytes //remaining in the buffer that need to be stuffed into application. if(kb_in_progress) { return; } //End if (in the middle of stuffing keystrokes) if (!_hotkey_hit) { return; } //End if (no hot key pressed) //If we were previously stuffing but now we are done, clean up if (bStuffing && !kb_in_progress) { bStuffing = FALSE; kb_close (); } //End if (done stuffing) if (_hotkey_hit) { _hotkey_hit = 0; if (_hotkey_num == 0) { //Now initiate the hook function kybdstuf2() to stuff //all the bytes in the buffer into the application kb_str_ptr = szDataBuffer; kb_in_progress = strlen(szDataBuffer); kb_init(); bStuffing = TRUE; return; } //End if (hot key to paste) if (_hotkey_num == 1) { if (freetsr()) { printf ("Error - could not free tsr.\n"); } //End if (failed to free) freeisr1 (); freeisr2 (); } //End if (hot key to free tsr) if (_hotkey_num == 2) { cciSaveAttrRect(&rtScreen); if (cciHilightRect(&rtRect) == ccSUCCESS) { cciSaveCharRect (&rtRect); bNewData = TRUE; } //End if (sucessful highlight) cciRestoreAttrRect(&rtScreen); } //End if (hot key to clip screen) } //End if (hot key hit) } //End function (vRespProg) void tsrpre () { tsrhotkeys (uiCCSig, (struct HKEYS far *)ahkHotKeys, 2); MAKERECTANGLE (rtScreen, 0, 0, cciColumns-1, cciRows-1); initisr1 (0x60, isr60, 1); initisr2 (0x61, isr61, 1); printf ("TSR Loaded.\n"); printf ("LSHIFT-ALT-C to copy\n"); printf ("LSHIFT-ALT-P to paste\n"); printf ("LSHIFT-ALT-R to remove from memory\n"); return; } //End function (tsrpre) void tsrpost () { if (ccabAttrBuffer) { free (ccabAttrBuffer); } //End if (attribute buffer defined) printf ("\n** TSR removed from memory. **"); printf ("\n** Hit enter to continue. **\n"); return; } //End function (tsrpost) char far *szTransferBuf; int i; isr60 () { FP_SEG (szTransferBuf) = isr1_ds; FP_OFF (szTransferBuf) = isr1_dx; i = 0; while (szTransferBuf[i] != 0) { szDataBuffer[i++] = szTransferBuf[i]; } //End while (more bytes to transfer) szDataBuffer[i] = 0; return 0; } //End function (isr60) isr61 () { if (!bNewData) { isr2_ax = 0; return 0; } //End if (no new data to copy) bNewData = FALSE; FP_SEG (szTransferBuf) = isr2_ds; FP_OFF (szTransferBuf) = isr2_dx; i = 0; while (szDataBuffer[i] != 0) { szTransferBuf[i] = szDataBuffer[i]; i++; } //End while (more bytes to transfer) szTransferBuf[i] = 0; isr2_ax = 1; return 0; } //End function (isr61) [LISTING THREE] /* Windos.h */ int PASCAL WinMain(HANDLE, HANDLE, LPSTR, int); long FAR PASCAL MainWndProc(HWND, unsigned, WORD, LONG); int pmiIntX (int iIntNo, LPSTR szSwapData); #define BUFFER_SIZE 3000L //size of transfer buffer #define TEXT_INC 15 //space between lines of text #define SIG "windos" //Signature to place on clipboard [LISTING FOUR] /**************************************************************************** PROGRAM: WINDOS PURPOSE: Reads text from the clipboard and writes it to a DOS TSR using DPMI. Or, reads text from a DOS TSR and writes it to clipboard. ****************************************************************************/ #include "windows.h" #include "windos.h" #include "dpmi.h" #include #include #include HWND hwndMain; //Global handle to main window WORD cfSignature; //signature format (proprietary) char szClipData[3000]; SELECTOR PMSelector; //protected mode selector SEGMENT RMSegment; //real-mode segment DWORD dwSegSelector; //seg:selector pair returned by //GlobalDosAlloc() LPSTR lpTransferBuf; //Points to transfer buffer /**************************************************************************** FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int) PURPOSE: Calls initialization functions and processes message loop Only one instance of the program is allowed to run. ****************************************************************************/ int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; if (!hPrevInstance) { if (!InitApplication(hInstance)) { return (FALSE); } //End if (failed initializing application params) } //End if (no previous instance running) else { return FALSE; } //End if (previous instance already running) if (!InitInstance(hInstance, nCmdShow)) { return (FALSE); } //End if (failed initializing instance data) while (GetMessage(&msg, NULL, NULL, NULL)) { TranslateMessage(&msg); DispatchMessage(&msg); } //End while (not a quit message) return (msg.wParam); } //End function (WinMain) /**************************************************************************** FUNCTION: InitApplication(HANDLE) PURPOSE: Initializes window data and registers window classes ****************************************************************************/ BOOL InitApplication(HANDLE hInstance) { WNDCLASS wc; wc.style = NULL; wc.lpfnWndProc = MainWndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(hInstance, "SMILEY"); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = GetStockObject(WHITE_BRUSH); wc.lpszMenuName = NULL; wc.lpszClassName = "WinDos"; return (RegisterClass(&wc)); } //End function (InitApplication) /**************************************************************************** FUNCTION: InitInstance(HANDLE, int) PURPOSE: Saves instance handle and creates main window ****************************************************************************/ BOOL InitInstance(HANDLE hInstance, int nCmdShow) { HDC hDC; TEXTMETRIC tm; hwndMain = CreateWindow( "WinDos", "WinDos", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL ); if (!hwndMain) { return (FALSE); } //End if (error creating main window) ShowWindow(hwndMain, SW_SHOWMINIMIZED); UpdateWindow(hwndMain); return (TRUE); } //End function (InitInstance) /**************************************************************************** FUNCTION: MainWndProc(HWND, unsigned, WORD, LONG) PURPOSE: Processes messages for WINDOS application. ****************************************************************************/ long FAR PASCAL MainWndProc(HWND hWnd, unsigned message, WORD wParam, LONG lParam) { HANDLE hClipData, hSig; LPSTR lpClipData, lpSig; int i, j; switch (message) { case WM_CREATE: if (GetWinFlags() & WF_ENHANCED) { MessageBox (hWnd, "Cannot use WINDOS in 386 enhanced mode", "Error", MB_OK); PostQuitMessage(0); break; } //End if (running 386 enhanced mode) // Allocate the transfer buffer // Take selector from low word of return value // (real-mode segment is in high word) if ((dwSegSelector = GlobalDosAlloc (BUFFER_SIZE+1))==NULL) { MessageBox (hWnd, "Unable to allocate transfer buf", "Error", MB_OK); PostQuitMessage(0); break; } //End if (could not allocate transfer buf) PMSelector = LOWORD (dwSegSelector); RMSegment = HIWORD (dwSegSelector); // Set pointer to transfer buffer lpTransferBuf = (LPSTR) MAKELONG (0, PMSelector); //Register our proprietary format with the clipboard if (!(cfSignature = RegisterClipboardFormat("Sig"))) { MessageBox (hWnd, "Unable to register clipbd format", "Error", MB_OK); PostQuitMessage(0); break; } //End if (error registering proprietary clipboard format) //Receive timer messages every 1/2 second if (!SetTimer (hWnd, 1, 500, NULL)) { MessageBox (hWnd, "Unable to create timer", "Error", MB_OK); PostQuitMessage(0); break; } //End if (could not create timer) break; case WM_TIMER: //Check the clipboard; if signature not present, then copy //data. do { if (OpenClipboard(hWnd)) { if (IsClipboardFormatAvailable (cfSignature)) { CloseClipboard (); break; } //End if (signature present - stale data) else { if (IsClipboardFormatAvailable (CF_TEXT)) { if (!(hClipData = GetClipboardData (CF_TEXT))) { CloseClipboard (); break; } //End if (error getting data from clipboard) if (!(lpClipData = GlobalLock (hClipData))) { CloseClipboard (); break; } //End if (error dereferencing clip handle) } //End if (text available on clipboard) else { CloseClipboard (); break; } //End if (no text on clipboard) } //End if (new data on the clipboard) CloseClipboard (); } //End if (able to open clipboard) else { break; } //End if (unable to open clipboard) //Now copy the data to the TSR //Do the real-mode interrupt to get the TSR's attention. pmiIntX (0x60, lpClipData); //Now copy signature to clipboard if (!(hSig = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)lstrlen(SIG)))) { break; } //End if (couldn't find the memory) if (!(lpSig = GlobalLock(hSig))) { GlobalFree(hSig); break; } //End if (couldn't lock the memory) lstrcpy (lpSig, SIG); GlobalUnlock(hSig); if (OpenClipboard(hWnd)) { SetClipboardData(cfSignature, hSig); CloseClipboard(); } //End if (clipboard open) } while (FALSE); do { if (!pmiIntX (0x61, szClipData)) { if (OpenClipboard(hWnd)) { //Now copy data to clipboard; allocate a few extra //bytes for CR - CR-LF combos. if (!(hClipData = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD) 3300))) { CloseClipboard (); break; } //End if (couldn't find the memory) if (!(lpClipData = GlobalLock(hClipData))) { CloseClipboard (); GlobalFree(hClipData); break; } //End if (couldn't lock the memory) //Copy the data to clipboard buf, translating //CR to CR-LF combo; this is the clipboard //TEXT format. i=0; j=0; while (szClipData[j] != 0) { if (szClipData[j] == 0x0D) { lpClipData[i] = 0x0D; i++; lpClipData[i] = 0x0A; } //End if (CR found) else { lpClipData[i] = szClipData[j]; } //End if (normal byte) i++; j++; } //End while (more bytes to copy) lpClipData[i] = 0; GlobalUnlock(hClipData); //Now copy signature to clipboard if (!(hSig = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE, (DWORD)lstrlen(SIG)))) { CloseClipboard (); break; } //End if (couldn't find the memory) if (!(lpSig = GlobalLock(hSig))) { CloseClipboard (); GlobalFree(hSig); break; } //End if (couldn't lock the memory) lstrcpy (lpSig, SIG); GlobalUnlock(hSig); EmptyClipboard(); SetClipboardData(CF_TEXT, hClipData); SetClipboardData(cfSignature, hSig); CloseClipboard(); } //End if (clipboard opened) } //End if (got data from TSR) } while (FALSE); break; case WM_DESTROY: /* message: window being destroyed */ KillTimer (hWnd, 1); GlobalDosFree (PMSelector); PostQuitMessage(0); break; default: /* Passes it on if unproccessed */ return (DefWindowProc(hWnd, message, wParam, lParam)); } //End switch (on message) return (NULL); } //End function (MainWndProc) /**************************************************************************** FUNCTION: pmiIntX PURPOSE: High level: Performs real mode interrupt ****************************************************************************/ int pmiIntX (int iIntNo, LPSTR szSwapData) { if (iIntNo == 0x60) { //Copy data to transfer buffer, including trailing NULL _fmemcpy (lpTransferBuf, (LPSTR) szSwapData, lstrlen (szSwapData)+1); } //End if (writing data TO TSR) //If running protected mode, simulate real mode interrupt //Otherwise do an int86x() if (GetWinFlags() & WF_PMODE) { RM386_INT rmInt; //structure for making real-mode //interrupts from protected mode memset (&rmInt, 0, sizeof(rmInt)); rmInt.edx = 0x0000; rmInt.ds = RMSegment; dpmiRMInt (iIntNo, 0, &rmInt, 0); if (iIntNo == 0x61) { if (rmInt.eax == 0) { return -1; } //End if (no TSR data to read) } //End if (reading data FROM TSR) } //End if (running in protected mode) else { union REGS inregs, outregs; struct SREGS sregs; sregs.ds = RMSegment; inregs.x.dx = 0; int86x (iIntNo, &inregs, &outregs, &sregs); if (iIntNo==0x61 && outregs.x.ax == 0) { return -1; } //End if (no TSR data to read) } //End if (running in real mode) if (iIntNo == 0x61) { //Copy data from transfer buffer, including trailing NULL _fmemcpy ((LPSTR) szSwapData, lpTransferBuf, lstrlen (lpTransferBuf)+1); } //End if (reading data FROM TSR) return 0; } //End function (pmiDPMIIntX) /**************************************************************************** FUNCTION: pmiDPMIIntX PURPOSE: Low level: Performs simulated real mode interrupt using DPMI ****************************************************************************/ BOOL dpmiRMInt(WORD wIntno, WORD wFlags, RM386_INT far *rmInt, WORD wStackVals) { if (wFlags) { wIntno |= 0x100; } //End if (flags set) _asm { push di mov ax, 0300h mov bx, word ptr wIntno mov cx, word ptr wStackVals les di, dword ptr rmInt int 31h jc error mov ax, 1 jmp short done } //End (low-level dpmi real-mode interrupt) error: _asm xor ax, ax done: _asm pop di } //End function (dpmiRMInt)