Sunday 20 November 2011

How do you interrupt a Windows program? in C programming

How do you interrupt a Windows program?

There is no trivial way to interrupt a Windows application so that you can perform a necessary task (if that is your goal). Windows 3.x is a nonpreemptive multitasking operating system. Put another way, it is a cooperative multitasking operating system. It is cooperative partly because there is no way to simply steal time away from a Windows program that is currently in control of the processor. If you look at the Windows API,
you’ll see functions such as PeekMessage() and WaitMessage(). As the Microsoft help documentation saysconcerning these functions:

The GetMessage, PeekMessage, and WaitMessage functions yield control to other applications. Using these functions is the only way to allow other applications to run. Applications that do not call any of these functions for long periods prevent other applications from running. All that having been said, it still can be done. One method is to create a timer in your Windows program that “goes off ” every so often. As long as your program is alive, you will get time to perform whatever taskyou want to when the timer goes off. However, this action is not technically interrupting a program in process—it is simply using the cooperative multitasking features of Windows. If you need to interrupt a  Windows program, you can do so with a filter function (also called a hook function). A filter function in Windows is analogous to an interrupt service routine in DOS (see FAQs XX.12 and XX.17). Using a filterfunction, you can hook certain Windows events and perform tasks when that event occurs. In fact, you can use a filter function to monitor nearly every message that exists in Windows using one or more of the available hooks. This example, however, uses the keyboard hook because it enables you to interrupt a program at will by entering a specific key combination. The following example hooks the keyboard event chain and puts up a message box when the Ctrl-Alt-F6 key is pressed. This method works regardless of the application that is currently running.

#include <dos.h>
#include <windows.h>
DWORD FAR PASCAL __loadds KeyBoardProc(int, WORD, DWORD);
static FARPROC nextKeyboardFilter = NULL;
BOOL shiftKeyDown, ctrlKeyDown;
#define REPEAT_COUNT 0x000000FF /* test key repeat */
#define KEY_WAS_UP 0x80000000 /* test WM_KEYUP */
#define ALT_KEY_DOWN 0x20000000 /* test Alt key state */
#define EAT_THE_KEY 1 /* swallow keystroke */
#define SEND_KEY_ON 0 /* act on keystroke */
BOOL useAltKey = TRUE; /* use Alt key in sequence */
BOOL useCtrlKey = TRUE; /* also use Ctrl key */
BOOL useShiftKey = FALSE; /* don’t use Shift key */
/* Entry point into the DLL. Do all necessary initialization here */
int FAR PASCAL LibMain(hModule, wDataSeg, cbHeapSize, lpszCmdLine)
HANDLE hModule;
WORD wDataSeg;
WORD cbHeapSize;
LPSTR lpszCmdLine;
{
/* initialize key state variables to zero */
shiftKeyDown = 0;
ctrlKeyDown = 0;
return 1;
}
/* The keyboard filter searches for the hotkey key sequence.
If it gets it, it eats the key and displays a message box.
Any other key is sent on to Windows. */
DWORD FAR PASCAL __loadds
KeyBoardProc(int nCode, WORD wParam, DWORD lParam)
{
BOOL fCallDefProc;
DWORD dwResult = 0;
dwResult = SEND_KEY_ON; /* default to send key on */
fCallDefProc = TRUE; /* default to calling DefProc */
switch(nCode){
case HC_ACTION:
case HC_NOREMOVE:
/* If key is Shift, save it */
if(wParam == (WORD)VK_SHIFT){
shiftKeyDown = ((lParam & KEY_WAS_UP) ? 0 : 1);
break;
}
/* If key is Ctrl, save it */
else if(wParam == (WORD)VK_CONTROL){
ctrlKeyDown = ((lParam & KEY_WAS_UP) ? 0 : 1);
break;
}
/* If key is the F6 key, act on it */
else if(wParam == (WORD)VK_F6){
/* Leave if the F6 key was a key release and not press */
if(lParam & KEY_WAS_UP) break;
/* Make sure Alt key is in desired state, else leave */
if( (useAltKey) && !(lParam & ALT_KEY_DOWN) ){
break;
}
else if( (!useAltKey) && (lParam & ALT_KEY_DOWN) ){
break;
}
/* Make sure Shift key is in desired state, else leave */
if(useShiftKey && !shiftKeyDown){
break;
}
else if(!useShiftKey && shiftKeyDown){
break;
}
/* Make sure Ctrl key is in desired state, else leave */
if(useCtrlKey && !ctrlKeyDown){
break;
}
else if(!useCtrlKey && ctrlKeyDown){
break;
}
/* Eat the keystroke, and don’t call DefProc */
dwResult = EAT_THE_KEY;
fCallDefProc = FALSE;
/* We made it, so Ctrl-Alt-F6 was pressed! */
MessageBox(NULL, (LPSTR)”You pressed Ctrl-Alt-F6!”,
(LPSTR)”Keyboard Hook”, MB_OK);
break;
}
default:
fCallDefProc = TRUE;
break;
}
if( (nCode < 0) || (fCallDefProc && (nextKeyboardFilter != NULL)))
dwResult = DefHookProc(nCode, wParam, lParam,
&nextKeyboardFilter);
return(dwResult);
}
/* This function is called by the application to set up or tear
down the filter function hooks. */
void FAR PASCAL
SetupFilters(BOOL install)
{
if(install){
nextKeyboardFilter = SetWindowsHook(WH_KEYBOARD,
(FARPROC)KeyBoardProc);
}
else{
UnhookWindowsHook(WH_KEYBOARD, (FARPROC)KeyBoardProc);
nextKeyboardFilter = NULL;
}
}

Microsoft strongly recommends placing filter functions in a DLL rather than your application (notice the presence of a LibMain() and the lack of a WinMain()). To complete this application, you need to write an ordinary Windows application that calls the SetupFilters() function with TRUE as the argument to start monitoring keystrokes, and FALSE as the argument to stop monitoring keystrokes. While your application is alive and you have called SetupFilters(TRUE), the callback function KeyBoardProc() is receiving all keystrokes, even while you are running other Windows applications. If you press Ctrl-Alt-F6, a small messagebox appears on-screen informing you that you pressed those keys. Presto, you have just interrupted whateverWindows application was running at the time you pressed those keys!

Note that the keyboard filter function will not receive keystrokes while in a DOS shell. However, the filter function will receive, and can interrupt, a system modal dialog box like the one that asks whether you really want to exit Windows.

Cross Reference:

XX.12: How can I pass data from one program to another?
XX.17: Can you disable warm boots (Ctrl-Alt-Del)?
XXI.10: What is dynamic linking?

No comments:

Post a Comment