🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #63

Setting (and losing) a keyboard hook

#63
From: salamander1965
Date: Wed, 18 Jun 2008 22:55
169 lines
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-mail

Show 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