Question

I have a strange situation using SetWindowsHookEx

I have a bcb 2009 project with a form and a Memo on it.

in the create we load the Dll and attach the function handler's to both sides.

The idea is that when the key board is hit a message appear in the memo box and when a mouse event happen an other text appears in the memo box.

The strange this is that when I cleaned the code from debug information it stops working. That means the hook got triggered one time and than it was over. In the debug I was using some VCL TStringList to log key stokes data to disk. Playing with that code I finally detected that by adding

[code]

TList* lList = new TList();
delete lList;

To every one of the hook functions (keyboard, mouse) the code is working again.

What is wrong in my code that I have to do this?

This is the first time in 15 years I make a dll. so it can be something real basic in creating a dll or exporting the functions.

Every suggestion is welcome.

regards

JVDN

Some new additional information:

[solved]My target is win XP embedded. my application creates a error that closes the explorer by windows. And the hook is not working global in xp but only local. But it is working on my develop platform win 7 x64 global typing and mousing in notepad result in messages in the application. [solution] Modified the WH_KEYBOARD to WH_KEYBOARD_LL and the mouse from WH_MOUSE to WH_MOUSE_LL solves the receiving key and mouse on Windows XP embedded.

Both the dll and the application have no runtime lib or packages.

DLL Code

[code]

//---------------------------------------------------------------------------

#include <vcl.h>
#include <windows.h>
#pragma hdrstop
//---------------------------------------------------------------------------
//   Important note about DLL memory management when your DLL uses the
//   static version of the RunTime Library:
//
//   If your DLL exports any functions that pass String objects (or structs/
//   classes containing nested Strings) as parameter or function results,
//   you will need to add the library MEMMGR.LIB to both the DLL project and
//   any other projects that use the DLL.  You will also need to use MEMMGR.LIB
//   if any other projects which use the DLL will be performing new or delete
//   operations on any non-TObject-derived classes which are exported from the
//   DLL. Adding MEMMGR.LIB to your project will change the DLL and its calling
//   EXE's to use the BORLNDMM.DLL as their memory manager.  In these cases,
//   the file BORLNDMM.DLL should be deployed along with your DLL.
//
//   To avoid using BORLNDMM.DLL, pass string information using "char *" or
//   ShortString parameters.
//
//   If your DLL uses the dynamic version of the RTL, you do not need to
//   explicitly add MEMMGR.LIB as this will be done implicitly for you
//---------------------------------------------------------------------------

typedef void __stdcall ( *typFn)(WPARAM,LPARAM);


static typFn gGUIProcessingKeyboard = NULL;

static HHOOK gGUIProcessingKeyboardHook = NULL;


static typFn gGUIProcessingMouse = NULL;;

static HHOOK gGUIProcessingMouseHook = NULL;


#pragma argsused

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)

{

  return 1;

}

//---------------------------------------------------------------------------



extern "C"

{ __declspec(dllexport) void SetGUIProcessingKeyboard(typFn aHandle);

 __declspec(dllexport) void ReleaseGUIProcessingKeyboard(typFn aHandle);

 __declspec(dllexport) LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam);

 __declspec(dllexport) void SetKeyboardHookHandle(HHOOK aHook );


 __declspec(dllexport) void SetGUIProcessingMouse(typFn aHandle);

 __declspec(dllexport) void ReleaseGUIProcessingMouse(typFn aHandle);

 __declspec(dllexport) void SetMouseHookHandle(HHOOK aHook );

 __declspec(dllexport) LRESULT CALLBACK wireMouseProc(int code, WPARAM wParam,LPARAM lParam);




 /**
  * Set the keyboard loop back handle
  */

void SetGUIProcessingKeyboard(typFn aHandle)
{
  if (aHandle != gGUIProcessingKeyboard)
  {
    gGUIProcessingKeyboard = aHandle;
  }
}


 /**
  * Release the keyboard loop back handle
  */
void ReleaseGUIProcessingKeyboard(typFn aHandle)
{
  gGUIProcessingKeyboard = NULL;
}

/**
 * Set the handle used for tapping the Keyboard
 */
void SetKeyboardHookHandle(HHOOK aHook )
{
  gGUIProcessingKeyboardHook = aHook;
}


 /**
  * Tapping the keyboard from the other applications
  */
LRESULT CALLBACK wireKeyboardProc(int code, WPARAM wParam,LPARAM lParam)
{
    TList* lList = new TList();
    delete lList;
    if (code < 0) {
      return CallNextHookEx(gGUIProcessingKeyboardHook, code, wParam, lParam);
    }
    if (NULL != gGUIProcessingKeyboard)
    {
      gGUIProcessingKeyboard( wParam,lParam);
    }
    return CallNextHookEx(gGUIProcessingKeyboardHook, code, wParam, lParam);
}


 /**
  * Set the mouse loop back handle
  */

void SetGUIProcessingMouse(typFn aHandle)
{
  if (aHandle != gGUIProcessingMouse)
  {
    gGUIProcessingMouse = aHandle;
  }
}


 /**
  * Release the mouse loop back handle
  */

void ReleaseGUIProcessingMouse(typFn aHandle)
{
  gGUIProcessingMouse = NULL;
}


/**
 * Set the handle used for tapping the mouse
 */

void SetMouseHookHandle(HHOOK aHook )
{
  gGUIProcessingMouseHook = aHook;
}


 /**
  * Tapping the mouse from the other applications
  */

LRESULT CALLBACK wireMouseProc(int code, WPARAM wParam,LPARAM lParam)
{
    TList* lList = new TList();
    delete lList;
//  if (gGUIProcessingMouseHook != NULL)
//  {
    if (code < 0) {
      return CallNextHookEx(gGUIProcessingMouseHook, code, wParam, lParam);
    }
    if (NULL != gGUIProcessingMouse)
    {
      gGUIProcessingMouse( wParam,lParam);
    }
    return CallNextHookEx(gGUIProcessingMouseHook, code, wParam, lParam);
    //  }
    //  return 0;

    }

    } // extern C

And here is the application.

[code cpp]

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "MonitoringToolMain.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"

typedef void __stdcall ( __closure *typFn)(WPARAM,LPARAM);

TForm1 *Form1;
HHOOK TForm1::mHook = NULL;
typedef void __stdcall (*typSetHook)(HHOOK);
typedef LRESULT CALLBACK (  *typHookFunc)(int,WPARAM,LPARAM);
static HHOOK gMyGUIProcessingKeyboardHook = NULL;
static HHOOK gMyGUIProcessingMouseHook = NULL;


//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
}

void __stdcall TForm1::MyKeyboardProc(
  WPARAM wParam,
  LPARAM lParam
)
{
  if (Form1 != NULL)
  {
    Form1->Memo1->Lines->Add(L"GotA keyboard");
  }
}
void __stdcall TForm1::MyMouseProc(
  WPARAM wParam,
  LPARAM lParam
)
{
  if (Form1 != NULL)
  {
    Form1->Memo1->Lines->Add(L"Pip pip");
  }
}

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  if (NULL == mHinst)
  {
    mHinst = LoadLibrary("KeyboardMouseHookDLL.dll");
  }

  if (mHinst)
  {
    typedef void (*Install)(typFn);

    // the keyboard

    typSetHook SetHook = (typSetHook) GetProcAddress( mHinst, "_SetKeyboardHookHandle" );
    typHookFunc wireKeyboardProc = (typHookFunc)GetProcAddress(mHinst, "wireKeyboardProc" );

    Install install = (Install) GetProcAddress(mHinst, "_SetGUIProcessingKeyboard");

    if (install)
    {
       install(&MyKeyboardProc);
    }

    if ((NULL != wireKeyboardProc) &&
        (NULL != SetHook) )
    {
      gMyGUIProcessingKeyboardHook = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)wireKeyboardProc,mHinst,NULL);
      SetHook(gMyGUIProcessingKeyboardHook);
    }

    // The mouse
    typSetHook  SetMouseHook = (typSetHook) GetProcAddress(mHinst, "_SetMouseHookHandle");
    typHookFunc wireMouseProc = (typHookFunc)GetProcAddress(mHinst, "wireMouseProc");

    Install installMouse = (Install) GetProcAddress(mHinst, "_SetGUIProcessingMouse");

    if (installMouse)
    {
       installMouse(&MyMouseProc);
    }

    if ((NULL != wireMouseProc) &&
        (NULL != SetMouseHook) )
    {
      gMyGUIProcessingMouseHook = SetWindowsHookEx(WH_MOUSE,(HOOKPROC)wireMouseProc,mHinst,NULL);
      SetMouseHook(gMyGUIProcessingMouseHook);
    }
  }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
  if (NULL == mHinst)
  {
    mHinst = LoadLibrary("KeyboardMouseHookDLL.dll");
  }

  if (mHinst)
  {

    if (NULL != gMyGUIProcessingKeyboardHook )
    {
      UnhookWindowsHookEx(gMyGUIProcessingKeyboardHook);
      gMyGUIProcessingKeyboardHook = NULL;
    }
    typedef void (*Uninstall)(typFn);

    Uninstall uninstall = (Uninstall) GetProcAddress(mHinst, "_ReleaseGUIProcessingKeyboard");

    if (uninstall)
    {
      uninstall(&MyKeyboardProc);
    }

    if (NULL != gMyGUIProcessingMouseHook )
    {
      UnhookWindowsHookEx(gMyGUIProcessingMouseHook);
      gMyGUIProcessingMouseHook = NULL;
    }

    Uninstall uninstallMouse = (Uninstall) GetProcAddress(mHinst, "_ReleaseGUIProcessingMouse");

    if (uninstallMouse)
    {
      uninstallMouse(&MyMouseProc);
    }

    FreeLibrary(mHinst);
    mHinst = NULL;
  }
}
//---------------------------------------------------------------------------

And the form header

[code]

//---------------------------------------------------------------------------

#ifndef MonitoringToolMainH
#define MonitoringToolMainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:    // IDE-managed Components
  TMemo *Memo1;
  void __fastcall FormCreate(TObject *Sender);
  void __fastcall FormDestroy(TObject *Sender);
private:    // User declarations
  int __stdcall lKeyBoard();
  void __stdcall MyKeyboardProc( WPARAM wParam, LPARAM lParam );
  void __stdcall MyMouseProc( WPARAM wParam, LPARAM lParam );
  HINSTANCE mHinst;
static  HHOOK mHook;

public:     // User declarations
  __fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Was it helpful?

Solution

If you're installing a global system hook, the hook DLL will be injected in each running process. As each process has its own memory space, you'll need to define a shared data section to place variables like the hook handles, otherwise they will be different for each process.

#pragma data_seg(".SHARDAT")
static HHOOK gGUIProcessingKeyboardHook = NULL;
static HHOOK gGUIProcessingMouseHook = NULL;
#pragma data_seg()

Also don't register function pointers to the hook DLL, as you will ask other processes to call the registered functions in your application. It's better to register the HWND of your application and a window message.

Create a exported function in your DLL that sets the hook and stores HWND and custom message number, f.e.:

#pragma data_seg(".SHARDAT")
static HHOOK g_keybHook = NULL;
    static HHOOK g_mouseHook = NULL;
HWND g_registeredWnd = NULL;
UINT g_registeredKeybMsg = 0;
UINT g_registeredMouseMsg = 0; 
#pragma data_seg()
HINSTANCE g_hInstance = NULL;

BOOL InstallHook(HWND registeredWnd, UINT registeredKeybMsg, UINT registeredMouseMsg)
{
    if (g_hHook != NULL) return FALSE;  // Hook already installed
    g_keybHook = SetWindowsHookEx(WH_KEYBOARD_LL, (HOOKPROC)KeybProc, g_hInstance, 0);
    if (g_keybHook == NULL) return FALSE;   // Failed to install hook
    g_registeredWnd = registeredWnd;
    g_registeredKeybMsg = registeredKeybMsg;
    g_registeredMouseMsg = registeredMouseMsg;
    return TRUE;
}

In the DllEntryPoint you save hinst in g_hInstance in case reason == DLL_PROCESS_ATTACH:

int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
    if ((reason == DLL_PROCESS_ATTACH) && (g_hInstance == NULL))
        g_hInstance = hinst;

    return 1;
}

In your application you register 2 window messages with the RegisterWindowMessage function and pass these values to the InstallHook function from the hook DLL. Then your application needs to handle those messages in its message loop.

registeredKeybMsg = RegisterWindowMessage("MyOwnKeybHookMsg");
registeredMouseMsg = RegisterWindowMessage("MyOwnMouseHookMsg");
InstallHook(hwnd, registeredKeybMsg, registeredMouseMsg);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top