Advanced MFC Programming
Advanced MFC Programming Advanced MFC Programming
Chapter 13. Adding Special Features to Application window handle to the DLL, we can call a function exported from the DLL when the hook is installed, and ask the DLL to keep this handle for later use. However, data stored in the DLL is slightly different from data stored in a common process. For a normal process, it has its own memory space, the static variables stored in this space will not change throughout their lifetime. However, for a DLL, since it can be shared by several processes, its variables are mapped to the application’s memory space separately. By doing this, for a variable contained in the DLL, different applications may have different values. This will eliminate data conflicting among different processes. To prevent the value of a variable stored in DLL from being changed, we can define a custom data segment to store the variable. Defining Data Segment In order to specify a special data segment for storing such type of variables, we can use macro #pragma data_seg to specify the data segment, and use -SEGMENT switch to link the project. DLL Implementation Sample 13.10\Hook demonstrates keyboard hook implementation. The hook procedure stays in a separate DLL file: “HookLib.Dll”. Creating a DLL is slightly different from creating MFC based applications, there is no skeleton generated at the beginning. After using the application wizard to generate a Win32 based DLL project, we are not provided with a single line of source code. Since our DLL is relatively small, we can use just one “.c” and “.h” file to implement it. We can create these two files by opening new text files, then executing command Project | Add To Project | Files... to add them into the project. In the sample, the DLL is implemented by “HookLib.h” and “HookLib.c” files. File “HookLib.h” declares all the functions that will be included in the DLL: #if !defined(__HOOKLIB_H__) #define __HOOKLIB_H__ #include "Windows.h" #include "BaseTyps.h" #if !defined(__DLLIMPORT__) #define DLLENTRY EXTERN_C __declspec(dllexport) #define STDENTRY EXTERN_C __declspec(dllexport) HRESULT STDAPICALLTYPE #define STDENTRY_(type) EXTERN_C __declspec(dllexport) type STDAPICALLTYPE BOOL CALLBACK LibMain(HANDLE, DWORD, LPVOID); int CALLBACK WEP(int); LRESULT CALLBACK KeyboardProc(int, WPARAM, LPARAM); #else #define DLLENTRY EXTERN_C __declspec(dllimport) #define STDENTRY EXTERN_C __declspec(dllimport) HRESULT STDAPICALLTYPE #define STDENTRY_(type) EXTERN_C __declspec(dllimport) type STDAPICALLTYPE #endif STDENTRY_(BOOL) SetKeyboardHook(HWND, HINSTANCE); STDENTRY_(BOOL) UnsetKeyboardHook(); #endif Function LibMain(…) and WEP(…) are the entry point and the exit point of the DLL respectively. The reason for using so many #if macros here is that it enables us to use the same header file for both the DLL and the application that links the DLL. As we build the DLL, we want to export functions so that they can be called outside the DLL; in the application, we need to import these functions from the DLL. Macro __declspec(dllimport) declares an import function and __declspec(dllexport) declares an export 416
Chapter 13. Adding Special Features to Application function. As we can see, if macro __DLLIMPORT__ is defined, function LibMain(…), WEP(…) and KeyboardProc(…) will be declared (they will be used only in the DLL). In this case, two other functions SetKeyboardHook(…) and UnsetKeyboardHook() will be declared as import function. If the macro is not defined, the two functions will be declared as export functions. The reason for using macro EXTERN_C is that the DLL is built with C convention and our application is built with C++ convention. To make them compatible, we must explicitly specify how to build the functions in the DLL. In the sample, two functions are exported from the DLL: SetKeyboardHook(…) will be used by the application to install hook; UnsetKeyboardHook() will be used to remove the hook. In file “HookLib.c”, first two static variables are declared: #pragma data_seg("SHARDATA") static HWND g_hWnd=NULL; static HHOOK g_hHook=NULL; #pragma data_seg() We use #pragma data_seg("SHARDATA") to specify that g_hWnd and g_hHook will be stored in "SHARDATA" segment instead of being mapped to calling processes. Function SetKeyboardHook(…) installs system wide keyboard hook by calling function SetWindowsHookEx(…). When using this function, we must provide the instance handle of the DLL library and the handle of the application’s mainframe window: STDENTRY_(BOOL) SetKeyboardHook(HWND hWnd, HINSTANCE hInstance) { g_hHook=SetWindowsHookEx ( WH_KEYBOARD, KeyboardProc, hInstance, 0 ); if(g_hHook == FALSE) { return FALSE; } g_hWnd=hWnd; } return TRUE; The handle of application’s mainframe window is stalled in variable g_hWnd for later use. The handle of the hook is stored in variable g_hHook and will be used in function UnsetKeyboardHook() to remove the keyboard hook: STDENTRY_(BOOL) UnsetKeyboardHook() { return UnhookWindowsHookEx(g_hHook); } Function KeyboardProc(…) is the hook procedure. When there is a keystroke, this function will be called, and the keystroke information will be processed within this function: LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam) { if(code < 0 || code != HC_ACTION) { return CallNextHookEx(g_hHookKeyboard, code, wParam, lParam); } if(code == HC_ACTION) { int nKeyState; nKeyState=GetKeyState(VK_CONTROL); if(lParam & 0x80000000 || lParam & 0x40000000) { 417
- Page 381 and 382: Chapter 11. Sample: Simple Paint
- Page 383 and 384: Chapter 11. Sample: Simple Paint Ho
- Page 385 and 386: Chapter 11. Sample: Simple Paint 1)
- Page 387 and 388: Chapter 12. Screen Capturing & Prin
- Page 389 and 390: Chapter 12. Screen Capturing & Prin
- Page 391 and 392: Chapter 12. Screen Capturing & Prin
- Page 393 and 394: Chapter 12. Screen Capturing & Prin
- Page 395 and 396: Chapter 12. Screen Capturing & Prin
- Page 397 and 398: Chapter 12. Screen Capturing & Prin
- Page 399 and 400: Chapter 12. Screen Capturing & Prin
- Page 401 and 402: Chapter 12. Screen Capturing & Prin
- Page 403 and 404: Chapter 12. Screen Capturing & Prin
- Page 405 and 406: Chapter 12. Screen Capturing & Prin
- Page 407 and 408: Chapter 13. Adding Special Features
- Page 409 and 410: Chapter 13. Adding Special Features
- Page 411 and 412: Chapter 13. Adding Special Features
- Page 413 and 414: Chapter 13. Adding Special Features
- Page 415 and 416: Chapter 13. Adding Special Features
- Page 417 and 418: Chapter 13. Adding Special Features
- Page 419 and 420: Chapter 13. Adding Special Features
- Page 421 and 422: Chapter 13. Adding Special Features
- Page 423 and 424: Chapter 13. Adding Special Features
- Page 425 and 426: Chapter 13. Adding Special Features
- Page 427 and 428: Chapter 13. Adding Special Features
- Page 429 and 430: Chapter 13. Adding Special Features
- Page 431: Chapter 13. Adding Special Features
- Page 435 and 436: Chapter 13. Adding Special Features
- Page 437 and 438: Chapter 13. Adding Special Features
- Page 439 and 440: Chapter 13. Adding Special Features
- Page 441 and 442: Chapter 13. Adding Special Features
- Page 443 and 444: Chapter 13. Adding Special Features
- Page 445 and 446: Chapter 14. Views ID_EDIT_PASTE pas
- Page 447 and 448: Chapter 14. Views Another feature o
- Page 449 and 450: Chapter 14. Views szFind=newName; s
- Page 451 and 452: Chapter 14. Views ON_COMMAND(ID_BUT
- Page 453 and 454: Chapter 14. Views IDB_BITMAP_CLOSEF
- Page 455 and 456: Chapter 14. Views Because we do not
- Page 457 and 458: Chapter 14. Views For the root dire
- Page 459 and 460: Chapter 14. Views The columns are a
- Page 461 and 462: Chapter 14. Views } ff.Close(); Des
- Page 463 and 464: Chapter 14. Views …… …… if(
- Page 465 and 466: Chapter 14. Views void CDirView::Ad
- Page 467 and 468: Chapter 14. Views Actually, in the
- Page 469 and 470: Chapter 14. Views } if(szName1.GetL
- Page 471 and 472: Chapter 14. Views Mouse Cursor Coor
- Page 473 and 474: Chapter 16. Context Sensitive Help
- Page 475 and 476: Chapter 16. Context Sensitive Help
- Page 477 and 478: Chapter 16. Context Sensitive Help
- Page 479 and 480: Chapter 16. Context Sensitive Help
- Page 481 and 482: Chapter 16. Context Sensitive Help
Chapter 13. Adding Special Features to Application<br />
function. As we can see, if macro __DLLIMPORT__ is defined, function LibMain(…), WEP(…) and<br />
KeyboardProc(…) will be declared (they will be used only in the DLL). In this case, two other functions<br />
SetKeyboardHook(…) and UnsetKeyboardHook() will be declared as import function. If the macro is not<br />
defined, the two functions will be declared as export functions.<br />
The reason for using macro EXTERN_C is that the DLL is built with C convention and our application is<br />
built with C++ convention. To make them compatible, we must explicitly specify how to build the<br />
functions in the DLL. In the sample, two functions are exported from the DLL: SetKeyboardHook(…) will<br />
be used by the application to install hook; UnsetKeyboardHook() will be used to remove the hook.<br />
In file “HookLib.c”, first two static variables are declared:<br />
#pragma data_seg("SHARDATA")<br />
static HWND g_hWnd=NULL;<br />
static HHOOK g_hHook=NULL;<br />
#pragma data_seg()<br />
We use #pragma data_seg("SHARDATA") to specify that g_hWnd and g_hHook will be stored in<br />
"SHARDATA" segment instead of being mapped to calling processes.<br />
Function SetKeyboardHook(…) installs system wide keyboard hook by calling function<br />
SetWindowsHookEx(…). When using this function, we must provide the instance handle of the DLL library<br />
and the handle of the application’s mainframe window:<br />
STDENTRY_(BOOL) SetKeyboardHook(HWND hWnd, HINSTANCE hInstance)<br />
{<br />
g_hHook=SetWindowsHookEx<br />
(<br />
WH_KEYBOARD,<br />
KeyboardProc,<br />
hInstance,<br />
0<br />
);<br />
if(g_hHook == FALSE)<br />
{<br />
return FALSE;<br />
}<br />
g_hWnd=hWnd;<br />
}<br />
return TRUE;<br />
The handle of application’s mainframe window is stalled in variable g_hWnd for later use. The handle<br />
of the hook is stored in variable g_hHook and will be used in function UnsetKeyboardHook() to remove the<br />
keyboard hook:<br />
STDENTRY_(BOOL) UnsetKeyboardHook()<br />
{<br />
return UnhookWindowsHookEx(g_hHook);<br />
}<br />
Function KeyboardProc(…) is the hook procedure. When there is a keystroke, this function will be<br />
called, and the keystroke information will be processed within this function:<br />
LRESULT CALLBACK KeyboardProc(int code, WPARAM wParam, LPARAM lParam)<br />
{<br />
if(code < 0 || code != HC_ACTION)<br />
{<br />
return CallNextHookEx(g_hHookKeyboard, code, wParam, lParam);<br />
}<br />
if(code == HC_ACTION)<br />
{<br />
int nKeyState;<br />
nKeyState=GetKeyState(VK_CONTROL);<br />
if(lParam & 0x80000000 || lParam & 0x40000000)<br />
{<br />
417