11.04.2014 Views

Advanced MFC Programming

Advanced MFC Programming

Advanced MFC Programming

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

Chapter 13. Adding Special Features to Application<br />

There are two ways of implementing this feature: 1) Register the hot key by calling function<br />

::RegisterHotKey(…). After doing this, whenever user presses the hot key, a WM_HOTKEY type message will<br />

be sent to the application. 2) Install a keyboard hook in the system to monitor all the keystrokes. If the hot<br />

key is pressed, we can activate the hidden application.<br />

Obviously, the second method will slow down the system, because it tries trap every keystroke in the<br />

system. Whenever possible, this method should be avoided.<br />

However, in some situations, we can use this powerful feature to create some special effects. For<br />

example, if we want to trap a special combination of key strokes, it is relatively difficult to implement it by<br />

registering hot keys.<br />

In this section we will demonstrate how to implement keyboard hook.<br />

Hook Installation<br />

Hooks can be installed either system wide or specific to a single thread. In the former case, we can<br />

monitor the activities in the whole system. To install a hook, we need to provide a hook procedure, which<br />

will be used to handle the intercepted message. For different kind of hooks, we need to provide different<br />

procedures. For example, the mouse hook procedure and the keyboard hook procedure look like the<br />

following:<br />

LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam);<br />

LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);<br />

Although they look the same, the meanings of their parameters are different. For keyboard hook<br />

procedure, WPARAM parameter represents virtual-key code, and lParam parameter represents keystroke<br />

information. For mouse hook procedure, WPARAM parameter represents message ID, and LPARAM represents<br />

mouse coordinates. Different types of hooks have different hook procedures, they should be provided by<br />

the programmer when one or more types of hooks are implemented.<br />

To install a hook, we need to call function ::SetWindowsHookEx(…):<br />

HHOOK ::SetWindowsHookEx(int idHook, HOOKPROC lpfn, HINSTANCE hMod, DWORD dwThreadId);<br />

The first parameter indicates the type of hook, for a keyboard hook, it should be WH_KEYBOARD, for a<br />

mouse hook, it should be WH_MOUSE. The second parameter is the address of the hook procedure described<br />

above. The third and fourth parameters should be set differently for system wide hook and thread specific<br />

hook.<br />

System Wide Hook<br />

The complex aspect of hook is that if we want to install a system wide hook, the hook procedure must<br />

reside in a DLL (Except for journal record hook and journal playback hook, which will be introduced in the<br />

next section). In this case, parameter hMod must be the instance of the DLL, and dwThreadId should be 0. If<br />

we want to install a thread specific hook and the hook procedure resides within the application rather than a<br />

separate DLL, parameter hMode must be NULL.<br />

Variables in DLL<br />

Obviously in our case, we want the hook to be system wide, so we have to build a separate DLL. This<br />

causes us some inconvenience. When the hook procedure receives the hot-key stroke, it needs to activate<br />

the application. But since the DLL and the application are separate from one another, it is difficult to access<br />

the application process from the DLL.<br />

Suppose we want to implement the hot-key based screen capturing, as we execute Capture | Go!<br />

command (see Chapter 12), we can hide the application by calling function CWnd::ShowWindow(…) using<br />

SW_HIDE flag. From now on the application has no way to receive keystrokes, we have to process them in<br />

the keyboard hook procedure residing in the DLL. As we get the predefined key stoke, we need to make the<br />

capture and call function CWnd::ShowWindow(…) using flag SW_SHOW to activate the application.<br />

We can implement this by sending message from DLL to the application. If the DLL knows the<br />

window handle of the application’s mainframe window, this can be easily implemented. To pass the<br />

415

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!