Article View: borland.public.cppbuilder.nativeapi
Article #63Setting (and losing) a keyboard hook
From: salamander1965
Date: Wed, 18 Jun 2008 22:55
Date: Wed, 18 Jun 2008 22:55
169 lines
6303 bytes
6303 bytes
I'm having some difficulty with a system hook to intercept NUMLOCK and
CAPSLOCK keystrokes. My main application (THWin32) has a status window that
displays whether these keys are toggled on or off, and I want the status
window to be updated when the user presses these keys even if some other
window is active. A system keyboard hook seemed to be the best solution.
However, I wanted there to be only one hook set for any number of instances
of the application running to minimize the number of messages being
broadcast to windows. As a result, the DLL uses a FileMapping object to
share memory among the processes attaching to the DLL.
The current DLL containing the code to set the hook seemed to work. If I
start one instance of THWin32, the status window updates properly. If I
start two or more instances of the program, all are updated properly, and if
I close the instances in the reverse order in which they were started, the
remaining instances update correctly. However, if I close the first
instance before the others, the remaining instances no longer respond to the
message sent by the hook procedure. So ... there seems to be something
'special' about terminating the first instance, but I can't figure out what
it might be.
Here are the relevant parts of the main application and the DLL -- any
comments would be appreciated.
//===========
// THWin32.cpp
//===========
#include <windows.h>
#include <windowsx.h>
#include "THWin32WndProc.h"
#include "THWin32UI.h"
#include "THWin32KB.h"
//windows procedure for main application window
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM
lParam) {
static HINSTANCE hDll;
static UINT uiKeyLockMsgID;
switch (message) {
case WM_CREATE:
//set keyboard hook for NUMLOCK and CAPSLOCK keys
hDll = LoadLibrary("THWin32KB");
uiKeyLockMsgID = RegisterWindowMessage(szRegMsgName);
//simulate NUMLOCK and CAPSLOCK keystrokes so initial state will be set
correctly
keybd_event(VK_NUMLOCK, 0, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CAPITAL, 0, KEYEVENTF_KEYUP, 0);
.
.
.
return 0;
// other message processing
case WM_DESTROY:
DeleteObject(hfont);
FreeLibrary(hDll);
PostQuitMessage(0);
return 0;
default:
if (message == uiKeyLockMsgID) {
switch (wParam) {
case VK_CAPITAL:
SetCapsLockStatus(hwnd, (int) lParam);
break;
case VK_NUMLOCK:
SetNumLockStatus(hwnd, (int) lParam);
break;
}
}
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
//===========
// THWin32KB.cpp (code for the DLL)
//===========
typedef struct {
int nRefCount;
HHOOK hHook;
UINT uiRegMsgID;
} SHAREDVARS, * LPSHAREDVARS;
#define SMSIZE sizeof(SHAREDVARS)
#define SMNAME "THWin32KB_SharedMem"
#define SMFILE ((HANDLE) 0xffffffff)
#define SMPROT PAGE_READWRITE
HHOOK AttachKeyboardHook(HINSTANCE);
BOOL DetachKeyboardHook(HHOOK);
static LPVOID lpvSharedMem = NULL;
static HANDLE hMapObject = NULL;
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void*
lpReserved) {
BOOL bInit;
switch (reason) {
case DLL_PROCESS_ATTACH:
if ((hMapObject = CreateFileMapping(SMFILE, NULL, SMPROT, 0, SMSIZE,
SMNAME)) == NULL)
return false;
//set init flag: true if first time DLL is being loaded; false otherwise
bInit = (GetLastError() != ERROR_ALREADY_EXISTS);
if ((lpvSharedMem = MapViewOfFile(hMapObject, FILE_MAP_WRITE, 0, 0, 0))
== NULL)
return false;
//initialize shared memory and set the keyboard hook first time DLL is
loaded
if (bInit) {
memset(lpvSharedMem, '\0', SMSIZE);
((LPSHAREDVARS) lpvSharedMem)->hHook = AttachKeyboardHook(hinst);
((LPSHAREDVARS) lpvSharedMem)->uiRegMsgID =
RegisterWindowMessage(szRegMsgName);
}
//increase the count of modules accessing the DLL
((LPSHAREDVARS) lpvSharedMem)->nRefCount++;
break;
case DLL_PROCESS_DETACH:
//decrease the count of modules accessing the DLL
((LPSHAREDVARS) lpvSharedMem)->nRefCount--;
//if no modules are accessing the DLL, remove the keyboard hook
if (((LPSHAREDVARS) lpvSharedMem)->nRefCount == 0) {
DetachKeyboardHook(((LPSHAREDVARS) lpvSharedMem)->hHook);
}
UnmapViewOfFile(lpvSharedMem);
CloseHandle(hMapObject);
break;
}
return 1;
}
LRESULT CALLBACK KBLockDetectProc(int nCode, WPARAM wParam, LPARAM lParam) {
LPARAM bKeystate;
if (nCode < 0)
return CallNextHookEx(((LPSHAREDVARS) lpvSharedMem)->hHook, nCode,
wParam, lParam);
//check for release (specifically) of either NUMLOCK of CAPSLOCK key
if ((wParam == VK_CAPITAL || wParam == VK_NUMLOCK) && (lParam &
0x80000000)) {
bKeystate = (LPARAM) (GetKeyState(wParam) & 0x0001);
PostMessage(HWND_BROADCAST, ((LPSHAREDVARS) lpvSharedMem)->uiRegMsgID,
wParam, bKeystate);
}
return CallNextHookEx(((LPSHAREDVARS) lpvSharedMem)->hHook, nCode, wParam,
lParam);
}
HHOOK AttachKeyboardHook(HINSTANCE hinst) {
return SetWindowsHookEx(WH_KEYBOARD, KBLockDetectProc, hinst, NULL);
}
BOOL DetachKeyboardHook(HHOOK hhook) {
return UnhookWindowsHookEx(hhook);
}
Thanks -- Steve
Technical Details
Message-ID:
<4859926a@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!eweka.nl!lightspeed.eweka.nl!213.239.142.3.MISMATCH!feed.xsnews.nl!border-2.ams.xsnews.nl!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mailShow Full Headers
Complete Article Headers
X-Google-Thread: 10cc67,21bdbb7b8038a591,start X-Google-Attributes: gid10cc67,domainid0,public,usenet X-Google-Language: ENGLISH,ASCII-7-bit From: "salamander1965" <salamander1@verizon.net> Newsgroups: borland.public.cppbuilder.nativeapi Subject: Setting (and losing) a keyboard hook Date: Wed, 18 Jun 2008 18:55:42 -0400 Lines: 171 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2900.3138 X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2900.3198 X-RFC2646: Format=Flowed; Original NNTP-Posting-Host: 68.162.175.73 Message-ID: <4859926a@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1213829738 68.162.175.73 (18 Jun 2008 15:55:38 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!eweka.nl!lightspeed.eweka.nl!213.239.142.3.MISMATCH!feed.xsnews.nl!border-2.ams.xsnews.nl!194.25.134.126.MISMATCH!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail