C++ using SetWindowsHookEx only works with strange vcl code added to it. in BCB2009 - c++

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

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);

Related

C++ Unknown override specifier when using function in callback

I'm working with C++ and the Windows API now for just a little while. I've never used a callback in C++ since yesterday, when the Windows API required me to do so for installing a low level mouse event hook (link to hook function). To keep my code a little cleaner I wanted to outsource some code to a function and then I ran into a problem that I don't understand. I think it has to do something with me not totally understanding the callback scope or something like that. My code looks like this and I use C++11 and VS2017:
MouseHandler.h
#ifndef __MOUSEHANDLER_H_INCLUDED__
#define __MOUSEHANDLER_H_INCLUDED__
#include <Windows.h>
class MouseHandler
{
private:
public:
static _bstr_t coordinatesToString(POINT point);
MouseHandler();
~MouseHandler();
};
#endif // !__MOUSEHANDLER_H_INCLUDED__
MouseHandler.cpp
#include "stdafx.h"
#include "MouseHandler.h"
#include <comutil.h>
#include <string>
using namespace std;
HHOOK mouseHook = NULL;
_bstr_t MouseHandler::coordinatesToString(POINT point)
{
_bstr_t coordinates = "(";
_bstr_t xcoordinate = to_string(point.x).c_str();
_bstr_t ycoordinate = to_string(point.y).c_str();
coordinates += xcoordinate + "," + ycoordinate + ")";
return coordinates;
}
LRESULT CALLBACK MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT event = *((MSLLHOOKSTRUCT *)lParam);
if (nCode == HC_ACTION)
{
_bstr_t message = "Mouse action happened at position: ";
_bstr_t mouseCoordinates = MouseHandler::coordinatesToString(event.pt);
message += mouseCoordinates;
}
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
MouseHandler::MouseHandler()
{
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0);
while (GetMessage(NULL, NULL, 0, 0) != 0);
}
MouseHandler::~MouseHandler()
{
}
When I try to compile I get the error C3646 'coordinatesToString': unknown override specifier. I searched up and down and asked my colleagues, but I couldn't get help with this, so I hope someone here can help me. Thanks in advance!
Make sure you specify the correct type of data.
to_string((long double)point.x).c_str();
Load the lib.
#pragma comment (lib, "comsuppw.lib")
or
#pragma comment (lib, "comsuppwd.lib")
Include comutil.h to the header CMouseHandler.h.
I tested your code in VS2010 C++ on Win10 1803 x64.
CMouseHandler.h
#pragma once
#include <Windows.h>
#include <comutil.h>
#include <string>
using namespace std;
#pragma comment (lib, "comsuppw.lib")
class CMouseHandler
{
public:
CMouseHandler(void);
~CMouseHandler(void);
static _bstr_t coordinatesToString(POINT point);
};
CMouseHandler.cpp
#include "CMouseHandler.h"
HHOOK mouseHook = NULL;
_bstr_t CMouseHandler::coordinatesToString(POINT point)
{
_bstr_t coordinates = "(";
_bstr_t xcoordinate = to_string((long double)point.x).c_str();
_bstr_t ycoordinate = to_string((long double)point.y).c_str();
coordinates += xcoordinate + "," + ycoordinate + ")";
return coordinates;
}
LRESULT CALLBACK MouseHookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
MSLLHOOKSTRUCT event = *((MSLLHOOKSTRUCT *)lParam);
if (nCode == HC_ACTION)
{
_bstr_t message = "Mouse action happened at position: ";
_bstr_t mouseCoordinates = CMouseHandler::coordinatesToString(event.pt);
message += mouseCoordinates;
}
return CallNextHookEx(mouseHook, nCode, wParam, lParam);
}
CMouseHandler::CMouseHandler()
{
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookCallback, NULL, 0);
while (GetMessage(NULL, NULL, 0, 0) != 0);
}
CMouseHandler::~CMouseHandler(void)
{
}
_bstr_t isn't defined, as visual studio doesn't recognise the type it assumes its an override specifier. You need to include comutil.h as specified in the documentation.

Globally installed keyboard hook prevents keyboard input to other applications

I am setting a global hook for keyboard. When I give keyboard inputs to other applications, the application does not receive the input and it hangs. When the console is stopped, the application recovers and the keyboard inputs are posted together.
DLL source:
#include <iostream>
#include <Windows.h>
#include <string>
using namespace std;
#define DLLEXPORT __declspec(dllexport)
DLLEXPORT bool installhook();
DLLEXPORT void unhook();
DLLEXPORT string TestLoaded();
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam );
static HHOOK kb_hook;
string test = "not loaded";
HINSTANCE hDLL;
DLLEXPORT LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if(code == HC_ACTION) // if there is an incoming action and a key was pressed
{
switch(wParam)
{
case VK_SPACE:
printf("Space was pressed\n"); //tried without this also
MessageBoxA(NULL, "Hi", "Space", MB_OK);
break;
}
}
return CallNextHookEx(NULL, code, wParam, lParam);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
test = "loaded";
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDLL = hModule;
break;
}
printf("test str = %s \n", test.c_str());
return TRUE;
}
bool installhook()
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, hDLL, NULL);
if(!kb_hook)
{
return false;
}
return true;
}
void unhook()
{
if(kb_hook)
{
UnhookWindowsHookEx(kb_hook);
}
}
string TestLoaded()
{
return test;
}
Console applicatioon source:
#include <iostream>
#include <Windows.h>
#include <string>
#define DLLIMPORT __declspec(dllimport)
using namespace std;
DLLIMPORT void unhook();
DLLIMPORT bool installhook();
DLLIMPORT string TestLoaded();
int main()
{
cout << TestLoaded() <<endl;
installhook();
for(int i = 1; i<=10 ; i++)
{
//Do some keyboard activities in this 10 secs
Sleep(1000);
cout << i<<endl;
}
unhook();
cin.get();
return 1;
}
My suspicion was that since the dll will be loaded into each process in the process's own address space and console would not be present in other applications, it gets void and crashed. So I removed the console outputs and replaced with messagebox. Then also no difference.
What could be the problem?
Update:
I tried to do a local hook to a specific thread before trying it global. But I get Parameter is incorrect error 87 at setwindowshookex. Below are the updated code:
dll:
bool installhook(DWORD ThreadId) //exporting this function
{
kb_hook = SetWindowsHookEx(WH_KEYBOARD, KeyboardProc, NULL, ThreadId); //tried with the dll module's handle also instead of NULL
if(!kb_hook)
{
printf("SetWindowsHookEx failed : %d\n", GetLastError());
return false;
}
return true;
}
Console application source:
DWORD myThread()
{
cout<< "Thread started\n";
char str[250];
cin>>str;
return 0;
}
int main()
{
cout << TestLoaded() <<endl;
DWORD myThreadID;
HANDLE myHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)myThread, NULL, 0, &myThreadID);
installhook(myThreadID);
for(int i = 0; i<100 ; i++)
{
Sleep(100);
if(i%10 == 0)
{
cout << i<<endl;
}
}
unhook();
}
Try to use WH_KEYBOARD_LL. You can set global hook even without dll declaring hook function in you process. Plus, you should detect space action using PKBDLLHOOKSTRUCT struct
LRESULT CALLBACK KeyboardProc ( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION )
{
switch ( wParam )
{
case WM_KEYDOWN:
{
// Get hook struct
PKBDLLHOOKSTRUCT p = ( PKBDLLHOOKSTRUCT ) lParam;
if ( p->vkCode == VK_SPACE)
{
MessageBoxA( NULL, "Hi", "Space", MB_OK );
}
}
break;
}
}
return CallNextHookEx( NULL, code, wParam, lParam );
}
....
// Somewhere in code
kb_hook = SetWindowsHookEx( WH_KEYBOARD_LL, KeyboardProc, NULL, NULL );
Thanks for all the inputs in answers and comments.
I have found out the actual problem. The mistake I made was trying to use console window without any message queue.
If I understand correctly, console windows are hosted by conhost.exe and they don't have any message pumps. And the hook works correctly only if the application which installs it has a message queue (should explore more on why it's this way). See below for ways you can make it work
If you are not posting any message to the console application:
Replace the for loop in the console application's main with this:
MSG msg;
while(GetMessage(&msg, NULL, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
In case you are posting any message to the console application:
Create a window using CreateWindowEx, there is an option for a message only window also. You would have to create a class and assign a CALLBACK process. Read here for more details. Create that and pass the handle along to the hook dll and postmessage to the handle. Use the loop for Getting msg and dispatching it (mentioned above). Then all the messages you post the dummy window from your hook dll can be processed using the CALLBACK window process.
References:
Why must SetWindowsHookEx be used with a windows message queue
CreateWindowEx MSDN
I had the same issue, working with QT, the GUI would be blocked (as planned) but whenever it came back online, it would process my keyboard and mouse clicks.
I am not sure if this is the most efficient way of handling it, but to solve this, I handled all the keyboard and mouse events separately. If, some task was in progress, I would just ignore the key event.
Otherwise I guess it just queues up and waits for its' turn!

Mouse and Keyboard system Global Hook

I want to set a global system hook for keyboard and mouse in C++ using a DLL. My program is working but not exactly as I need. For example the program will not hook mouse events on other windows or popup menu, or modal dialogs. I want to hook the mouse and keyboard events anywhere in other windows, programs, ect.., all system mouse and keyboard events. What is wrong with my code what to change to get it to work as I need, I cannot find myself what is wrong, I'm doing as is described in documentation, I need help.
I'm coding in C++ Builder using VCL
DLL:
#include <vcl.h>
#include <windows.h>
#include "main.h"
#pragma hdrstop
#pragma argsused
typedef struct _HOOKSTRUCT
{
int nType;
HOOKPROC hkprc;
HHOOK hhook;
bool bInstalled;
} HOOKSTRUCT;
static HOOKSTRUCT hook[2];
HINSTANCE hDLL;
int nThreadCode;
bool bInit;
TForm1 *form;
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam);
//---------------------------------------------------------------------------
int WINAPI DllEntryPoint(HINSTANCE hinst, unsigned long reason, void* lpReserved)
{
hDLL = hinst;
bInit = false;
return 1;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void Init()
{
hook[0].nType = WH_KEYBOARD;
hook[0].hkprc = (HOOKPROC)KeyboardProc;
hook[0].bInstalled = false;
hook[1].nType = WH_MOUSE;
hook[1].hkprc = (HOOKPROC)MouseProc;
hook[1].bInstalled = false;
bInit = true;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) bool SetHook(int nHook)
{
if(!bInit)
{
Init();
}
hook[nHook].hhook = NULL;
hook[nHook].hhook = SetWindowsHookEx(hook[nHook].nType,
(HOOKPROC)hook[nHook].hkprc, hDLL, 0);
if(hook[nHook].hhook != NULL)
{
MessageBox(NULL, "Setup hook successful", "Information", MB_OK);
}
return true;
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void UnsetHook(int nHook)
{
UnhookWindowsHookEx(hook[nHook].hhook);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
{
if(form != NULL)
{
form->Memo1->Lines->Add("Key Pressed");
}
}
return CallNextHookEx(hook[0].hhook, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
char str[128];
PMOUSEHOOKSTRUCT Info = (PMOUSEHOOKSTRUCT)lParam;
wsprintf(str, "The mouse message at X: %d,Y: %d", Info->pt.x, Info->pt.y);
form->Memo2->Lines->Add(str);
return CallNextHookEx(hook[1].hhook, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
extern "C" __stdcall __declspec(dllexport) void SetControl(TForm1 *Object, int nApp)
{
form = Object;
nThreadCode = nApp;
}
Program:
#include <vcl.h>
#pragma hdrstop
#include "main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
HINSTANCE hInst;
typedef bool (*install)(int);
typedef void (*uninstall)(int);
typedef void (*passself)(TForm1 *, int);
install InstallHook;
uninstall UninstallHook;
passself PassThis;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
N2->Enabled = true;
N3->Enabled = true;
N4->Enabled = false;
N5->Enabled = false;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
Memo1->Clear();
Memo2->Clear();
hInst = LoadLibrary("ch49dll.dll");
if(hInst == NULL)
{
ShowMessage("Load DLL error " + AnsiString(GetLastError()));
return;
}
InstallHook = (install)GetProcAddress(hInst, "SetHook");
if(InstallHook == NULL)
{
ShowMessage("Get SetHook ProcAddress Error");
return;
}
UninstallHook = (uninstall)GetProcAddress(hInst, "UnsetHook");
if(UninstallHook == NULL)
{
ShowMessage("Get UnsetHook ProcAddress Error");
return;
}
PassThis = (passself)GetProcAddress(hInst, "SetControl");
if(PassThis == NULL)
{
ShowMessage("Get SetControl ProcAddress Error");
return;
}
PassThis(this, 0);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
FreeLibrary(hInst);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N2Click(TObject *Sender)
{
InstallHook(0);
N2->Enabled = false;
N4->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N3Click(TObject *Sender)
{
InstallHook(1);
N3->Enabled = false;
N5->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N4Click(TObject *Sender)
{
UninstallHook(0);
N4->Enabled = false;
N2->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N5Click(TObject *Sender)
{
UninstallHook(1);
N5->Enabled = false;
N3->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::N7Click(TObject *Sender)
{
Close();
}
//---------------------------------------------------------------------------
Program header:
#ifndef mainH
#define mainH
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Menus.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // IDE-managed Components
TMemo *Memo1;
TMemo *Memo2;
TMainMenu *MainMenu1;
TMenuItem *N1;
TMenuItem *N2;
TMenuItem *N3;
TMenuItem *N4;
TMenuItem *N5;
TLabel *Label1;
TLabel *Label2;
TMenuItem *N6;
TMenuItem *N7;
void __fastcall FormCreate(TObject *Sender);
void __fastcall FormDestroy(TObject *Sender);
void __fastcall N2Click(TObject *Sender);
void __fastcall N3Click(TObject *Sender);
void __fastcall N4Click(TObject *Sender);
void __fastcall N5Click(TObject *Sender);
void __fastcall N7Click(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
So the program work and can hook external events, but for some dialog windows , my program will not hook the mouse events. for example when I right click the icon from taskbar Notification Area , a popup will display and if I enter mouse cursor in the popup window area then my program will not record those mouse move events. Other case is when I click About program menu in other programs, or About menu, then a window will display and if I move my cursor inside the area of that window then my program will not hook events of mouse and keyboard, why ? how to make it to hook anywhere for any window
Two very obvious problems:
The DLL will be injected into all other processes. You cannot expect to call VCL methods from a DLL that has been hooked into another process. You'll have to find another way to report diagnostics.
Because you are using a global hook, you will need to deal with 32/64 bit issues. You would need to produce both 32 and 64 bit versions of the DLL, and set hooks to them from 32 and 64 bit processes.
If you can use a low-level hook you should consider taking that option. The advantage is that there is no injection with a low-level hook. You don't need to create a DLL at all.
A few comments, hopefully will solve your problems: Use the "Low Level" hooks (WH_MOUSE_LL, WH_KEYBOARD_LL) because they are guaranteed to be only global. It feels to me that your application got only a "local" (thread) hook.
I have bad experiences with CBuilder created DLLs when using together with hooks. ... ie: the same problem exactly as you describe. I'd recommend to recompile your DLL with a Microsoft compiler (and provide a .DEF file to use).
There are chances that you will need to place the DLL in a place identified as system directory.
You don't need to place the SetHook in the DLL, that can be done from the "main" application too.
On Win 7 you can only hook messages from programs with the same or lower privileges. I.e. if your own program runs with standard privileges it will never see any Mouse or Keyboard messages targeted at a process with e.g. admin privileges. – iamjoosy

Show a list of applications like alt-tab in Win7

I am trying to print a list of running applications like alt-tab would give me. Here are what I have done so far:
1.In the beginning I tried EnumWindows, but I got hundreds of entries.
2.I found some similar questions and they led me to the blog of Raymond Chen.
http://blogs.msdn.com/b/oldnewthing/archive/2007/10/08/5351207.aspx
However it still shows more than 100 windows(window_num1 being 158 and window_num2 being 329), while alt-tab would give me only 4. What did I do wrong? Here is my code:
#include <windows.h>
#include <tchar.h>
#include <iostream>
using namespace std;
#pragma comment(lib, "user32.lib")
HWND windowHandle;
int window_num1=0;
int window_num2=0;
BOOL IsAltTabWindow(HWND hwnd)
{
if (hwnd == GetShellWindow()) //Desktop
return false;
// Start at the root owner
HWND hwndWalk = GetAncestor(hwnd, GA_ROOTOWNER);
// See if we are the last active visible popup
HWND hwndTry;
while ((hwndTry = GetLastActivePopup(hwndWalk)) != hwndTry)
{
if (IsWindowVisible(hwndTry))
break;
hwndWalk = hwndTry;
}
return hwndWalk == hwnd;
}
BOOL CALLBACK MyEnumProc(HWND hWnd, LPARAM lParam)
{
TCHAR title[500];
ZeroMemory(title, sizeof(title));
//string strTitle;
GetWindowText(hWnd, title, sizeof(title)/sizeof(title[0]));
if (IsAltTabWindow(hWnd))
{
_tprintf(_T("Value is %s\n"), title);
window_num1++;
}
window_num2++;
//strTitle += title; // Convert to std::string
if(_tcsstr(title, _T("Excel")))
{
windowHandle = hWnd;
return FALSE;
}
return TRUE;
}
void MyFunc(void) //(called by main)
{
EnumWindows(MyEnumProc, 0);
}
int main()
{
MyFunc();
cout<<endl<<window_num1<<endl<<window_num2;
return 0;
}
You failure is, that you should walk only visible windows... read the blog again.
For each visible window, walk up its owner chain until you find
the root owner. Then walk back down the visible last active popup
chain until you find a visible window. If you're back to where you're
started, then put the window in the Alt+↹Tab list.
Your code walks over every window!
Just use IsWindowVisible
BOOL CALLBACK MyEnumProc(HWND hWnd, LPARAM lParam)
{
TCHAR title[256] = {0,};
if (IsWindowVisible(hWnd) && GetWindowTextLength(hWnd) > 0)
{
window_num1++;
GetWindowText(hWnd, title, _countof(title));
_tprintf(_T("Value is %d, %s\n"), window_num1, title);
}
return TRUE;
}

Why is CWnd::CreateEx failing to create my window?

I'm working on a sporadic production issue that's occurring within our 32 bit MFC VC2010 application. The application is running on Windows Server 2008 R2 Standard SP1 64-bit.
The issue is caused by a failure to create a CWnd derived class. When the failure occurs the AfxUnhookWindowCreate method returns false within CWnd::CreateEx. This is because the pThreadState->m_pWndInit variable is not NULL. It looks like _AfxCbtFilterHook should be setting this to NULL when HCBT_CREATEWND is hooked, but it appears this is not occurring. I've logged out the CREATESTRUCT and compared it to when the failure occurs vs. doesn't occur and the parameters are essentially the same.
Does anyone have ideas on what could cause this or how I could identify the cause? Thanks!
BOOL CWnd::CreateEx(DWORD dwExStyle, LPCTSTR lpszClassName,
LPCTSTR lpszWindowName, DWORD dwStyle,
int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU nIDorHMenu, LPVOID lpParam)
{
...
if (!PreCreateWindow(cs))
{
PostNcDestroy();
return FALSE;
}
AfxHookWindowCreate(this);
HWND hWnd = ::AfxCtxCreateWindowEx(cs.dwExStyle, cs.lpszClass,
cs.lpszName, cs.style, cs.x, cs.y, cs.cx, cs.cy,
cs.hwndParent, cs.hMenu, cs.hInstance, cs.lpCreateParams);
...
if (!AfxUnhookWindowCreate())
PostNcDestroy(); // cleanup if CreateWindowEx fails too soon
...
BOOL AFXAPI AfxUnhookWindowCreate()
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
#ifndef _AFXDLL
if (afxContextIsDLL && pThreadState->m_hHookOldCbtFilter != NULL)
{
::UnhookWindowsHookEx(pThreadState->m_hHookOldCbtFilter);
pThreadState->m_hHookOldCbtFilter = NULL;
}
#endif
if (pThreadState->m_pWndInit != NULL)
{
pThreadState->m_pWndInit = NULL;
return FALSE; // was not successfully hooked
}
return TRUE;
}
LRESULT CALLBACK
_AfxCbtFilterHook(int code, WPARAM wParam, LPARAM lParam)
{
_AFX_THREAD_STATE* pThreadState = _afxThreadState.GetData();
if (code != HCBT_CREATEWND)
{
// wait for HCBT_CREATEWND just pass others on...
return CallNextHookEx(pThreadState->m_hHookOldCbtFilter, code,
wParam, lParam);
}
...
pThreadState->m_pWndInit = NULL;
I tracked the problem down to a window procedure hook that shouldn't have been executing at this time.