Mouse and Keyboard system Global Hook - c++

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

Related

How to pass IWebBrowser2::Navigate2 arguments?

I want to implement Internet Explorer webview control on my window.
I found this answer, on how to do that.
There is a problem: Navigate2 method from the answer is different from the headers I have. In the posters’s code, seems it has only one argument, and maybe others are by default, but I have 5 arguments with the stupidest thing I have ever met - VARIANT type variables (also, in poster’s code it is _variant_t which is undefined for me).
Probably I will never understand the sEiFe logic, why to make instead of Navigate2(wchar_t *,...) cool stuff VARIANT * (I know about Navigate method), but can anyone provide an example of calling that method.
This full code
#include <Windows.h>
#include <Ole2.h>
#include "resource.h"
#include <iostream>
#include <atlbase.h> //activex
#include <atlwin.h> //windows
#include <atlcom.h>
#include "exdisp.h"
#include <comutil.h>
#pragma comment(lib, "comsuppw.lib")
//This will load the browser dll then library and will generate headers
//All the declarations will be in the namespace SHDocVw
//#import "shdocvw.dll"
using namespace std;
class CMyDialog : public CAxDialogImpl<CMyDialog>
{
public:
enum { IDD = IDD_DIALOG1 };
BEGIN_MSG_MAP(CMyDialog)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_HANDLER(IDCANCEL, BN_CLICKED, OnBnCancel)
COMMAND_HANDLER(IDOK, BN_CLICKED, OnBnOk)
END_MSG_MAP()
CComPtr<IWebBrowser2> ctrl;
LRESULT OnInitDialog(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
// Do some initialization code
HRESULT hr;
//IDC_EXPLORER_TEST is the ID of your control
GetDlgControl(IDC_EXPLORER_TEST, __uuidof(ctrl), (void**)&ctrl);
VARIANT address;
address.vt = VT_BSTR;
address.bstrVal = SysAllocString(L"google.com");
VARIANT empty;
empty.vt = VT_EMPTY;
hr = ctrl->Navigate2(&address, &empty, &empty, &empty, &empty);
SysFreeString(address.bstrVal);
/*
Also fails
_variant_t a = SysAllocString(L"google.com");
VARIANT f;
f.vt = VT_I2;
f.iVal = navBrowserBar;
_variant_t fr = SysAllocString(L"_self");
_variant_t h = SysAllocString(L" ");
hr = ctrl->Navigate2(&a, &f, &fr, &h, &h);
*/
LRESULT res = CAxDialogImpl<CMyDialog>::OnInitDialog(uMsg, wParam, lParam, bHandled);
return 0;
}
public:
LRESULT OnBnCancel(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDCANCEL);
return 0;
}
LRESULT OnBnOk(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
EndDialog(IDOK);
return 0;
}
};
CComModule _Module;
int WINAPI WinMain(HINSTANCE,HINSTANCE,LPSTR,int)
{
CMyDialog dlg;
dlg.DoModal();
return 0;
}
Returns an exception at method call because of 0x0 read violation.
It appears that you failed to check if GetDlgControl succeeded. When it fails, ctrl has an unspecified value and might be null.
Of course, that leaves the question why it would fail, but that's another issue.

Direct Show Video capture performance

I originally started out looking for an example of how I can use FFMPEG in c++ builder to create an application to record from usb capture device and playback video because of apparrent poor performance
I tried Mitov components, Datastead, FFMPEGVCL and winsoft camera which use directshow but their capture performance seemed poor.
I need to capture 1920x1080 at up to 60fps into a compressed format and play this back later at both normal speed and slow speed.
What I found was that DirectShow itself has a number of limitations which can be improved by adding things like FFMPEG, but ultimately PC hardware, in particular the HDD and processor limit capture capability.
1920x1080 60fps is basically the upper end for DirectShow so you need to have best performing hardware in order to achieve this sort of performance #Spektre kindly gave me examples of DirectShow using the API direct which were good for comparison with the purchased components.
Using this and comparing to the components I found that MITOV has a major issue with regards the larger video sizes and frame rates. Using this 1920x108 30fps and 60fps can be previewed but they have a massive delay between video feed and preview (5 or 6 seconds). The other components performed similar to the API direct method with only minor variations in performance. None were able to capture and record 1920x108 60fps with any sort of compression filter without large frame drops and very jerky preview.
I do not think your problem is in video capture component itself nor FFMPEG. The main problem is that Directshow and VFW API to obtain image from camera is relatively slow. The speed can be improved by setting proper format of the image like:
smaller resolution
different color encoding (RGB 24bpp is not a good idea)
using camera JPEG format (not all cameras support it)
Without JPEG output format I never got pass 15 fps even on small resolutions. Also my experience shows that DirectShow is slightly slower then VFW (at least for my cameras). However not all cameras provide a VFW driver :( anymore.
Also be sure to ensure USB bandwidth by using proper version of USB port and do not diminish its bandwidth with other devices on the same HUB !!!
This is what I use for camera capture (VFW I coded years ago) in Borland/Embarcadero BDS 2006 C++:
VideoCaptureVFW.h:
//---------------------------------------------------------------------------
//--- VFW Video Capture ver: 2.0 --------------------------------------------
//---------------------------------------------------------------------------
#ifndef _VideoCaptureVFW_h
#define _VideoCaptureVFW_h
//---------------------------------------------------------------------------
#include <vfw.h>
#include <jpeg.hpp>
#include <Clipbrd.hpp>
//---------------------------------------------------------------------------
const int _vfw_callbach_onframe=1; // bit mask for each callback
//---------------------------------------------------------------------------
#ifndef _TDirectMemoryStream
#define _TDirectMemoryStream
class TDirectMemoryStream:TMemoryStream // just for accessing protected SetPointer
{
public:
void SetMemory(BYTE *ptr,DWORD siz) { SetPointer(ptr,siz); Position=0; };
};
#endif
//---------------------------------------------------------------------------
#ifndef _avgfps
#define _avgfps
class avgfps
{
public:
int N,N2;
int frame,frame0;
double fps,t0,t1,dt,Ts;
avgfps()
{
N=40; N2=N<<1;
fps=0.0; t0=0.0; frame=0; frame0=0;
LARGE_INTEGER i;
QueryPerformanceFrequency(&i); Ts=1.0/double(i.QuadPart);
}
~avgfps() {}
void update()
{
double t;
LARGE_INTEGER i;
QueryPerformanceCounter(&i); t=double(i.QuadPart)*Ts; dt=t-t0;
if (frame<=0)
{
t0=t; t1=t;
dt=0.0;
frame=0;
frame0=0;
}
if (dt>1e-6) fps=double(frame0)/dt; else fps=0.0;
frame++; frame0++;
if (frame0==N ) t1=t;
if (frame0==N2) { t0=t1; t1=t; frame0=N; }
}
};
#endif
//---------------------------------------------------------------------------
class VideoCaptureVFW
{
private:
HWND hcap,hown; // video capture window
public:
int ins_ix,ins_use; // instance index and usage for callbacks class reference
CAPDRIVERCAPS driver_cp; // driver capabilities
CAPTUREPARMS capture; // capture setup
CAPSTATUS state;
BITMAPINFO format;
// on frame callback
avgfps fps; // average fps
TMemoryStream *mem; // just for loading jpg from memory without copy
Graphics::TBitmap *bmp; // grabbed frame
VideoCaptureVFW();
~VideoCaptureVFW();
void ins_rst();
void ins_inc();
void ins_dec();
void set_owner(HWND _hown);
AnsiString get_video_drivers();
void set_video_driver(int ix);
void dlg_source() { if(driver_cp.fHasDlgVideoSource) capDlgVideoSource(hcap); }
void dlg_format() { if(driver_cp.fHasDlgVideoFormat) capDlgVideoFormat(hcap); get_state(); get_format(); }
void dlg_display(){ if(driver_cp.fHasDlgVideoDisplay)capDlgVideoDisplay(hcap);}
void dlg_compress() { capDlgVideoCompression(hcap); }
void get_capabil(){ capDriverGetCaps (hcap,&driver_cp,sizeof(CAPDRIVERCAPS)); }
void get_setup() { capCaptureGetSetup(hcap,&capture,sizeof(CAPTUREPARMS)); }
void set_setup() { capCaptureSetSetup(hcap,&capture,sizeof(CAPTUREPARMS)); }
void get_state() { capGetStatus (hcap,&state,sizeof(CAPSTATUS)); }
void get_format() { capGetVideoFormat (hcap,&format,sizeof(BITMAPINFO)); }
void preview_start(){ capPreview(hcap,TRUE ); }
void preview_stop() { capPreview(hcap,FALSE); }
void grab_start() { set_callback_on_frame(); capGrabFrameNoStop(hcap); }
void grab_stop() { res_callback_on_frame(); }
void copy_to_clipboard() { capEditCopy(hcap); }
void set_callback_on_frame();
void res_callback_on_frame();
LRESULT _on_frame(HWND hwnd,LPVIDEOHDR hdr);
void (*on_frame)(VideoCaptureVFW &cap);
};
//---------------------------------------------------------------------------
// on frame
const int _VideoCaptureVFW_ins=32;
void* VideoCaptureVFW_ins[_VideoCaptureVFW_ins]=
{
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
};
int VideoCaptureVFW_ins_get()
{
for (int i=0;i<_VideoCaptureVFW_ins;i++)
if (VideoCaptureVFW_ins[i]==NULL) return i;
return -1;
}
LRESULT PASCAL VideoCaptureVFW00_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 0]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW01_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 1]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW02_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 2]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW03_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 3]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW04_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 4]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW05_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 5]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW06_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 6]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW07_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 7]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW08_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 8]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW09_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[ 9]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW10_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[10]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW11_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[11]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW12_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[12]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW13_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[13]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW14_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[14]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW15_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[15]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW16_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[16]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW17_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[17]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW18_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[18]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW19_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[19]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW20_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[20]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW21_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[21]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW22_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[22]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW23_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[23]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW24_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[24]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW25_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[25]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW26_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[26]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW27_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[27]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW28_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[28]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW29_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[29]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW30_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[30]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL VideoCaptureVFW31_on_frame(HWND hwnd,LPVIDEOHDR hdr) { return ((VideoCaptureVFW*)(VideoCaptureVFW_ins[31]))->_on_frame(hwnd,hdr); }
LRESULT PASCAL(*VideoCaptureVFW_on_frame[_VideoCaptureVFW_ins])(HWND hwnd,LPVIDEOHDR hdr)=
{
VideoCaptureVFW00_on_frame,
VideoCaptureVFW01_on_frame,
VideoCaptureVFW02_on_frame,
VideoCaptureVFW03_on_frame,
VideoCaptureVFW04_on_frame,
VideoCaptureVFW05_on_frame,
VideoCaptureVFW06_on_frame,
VideoCaptureVFW07_on_frame,
VideoCaptureVFW08_on_frame,
VideoCaptureVFW09_on_frame,
VideoCaptureVFW10_on_frame,
VideoCaptureVFW11_on_frame,
VideoCaptureVFW12_on_frame,
VideoCaptureVFW13_on_frame,
VideoCaptureVFW14_on_frame,
VideoCaptureVFW15_on_frame,
VideoCaptureVFW16_on_frame,
VideoCaptureVFW17_on_frame,
VideoCaptureVFW18_on_frame,
VideoCaptureVFW19_on_frame,
VideoCaptureVFW20_on_frame,
VideoCaptureVFW21_on_frame,
VideoCaptureVFW22_on_frame,
VideoCaptureVFW23_on_frame,
VideoCaptureVFW24_on_frame,
VideoCaptureVFW25_on_frame,
VideoCaptureVFW26_on_frame,
VideoCaptureVFW27_on_frame,
VideoCaptureVFW28_on_frame,
VideoCaptureVFW29_on_frame,
VideoCaptureVFW30_on_frame,
VideoCaptureVFW31_on_frame,
};
//---------------------------------------------------------------------------
VideoCaptureVFW::VideoCaptureVFW()
{
hcap=NULL;
hown=NULL;
ins_ix=-1; ins_use=0;
on_frame=NULL;
mem=new TMemoryStream();
bmp=new Graphics::TBitmap;
}
//---------------------------------------------------------------------------
VideoCaptureVFW::~VideoCaptureVFW()
{
capDriverDisconnect(hcap);
res_callback_on_frame();
if (mem) delete mem;
if (bmp) delete bmp;
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_owner(HWND _hown)
{
hown=_hown;
hcap=capCreateCaptureWindow("",WS_CHILD|WS_VISIBLE,0,0,1,1,hown,1);
}
//---------------------------------------------------------------------------
AnsiString VideoCaptureVFW::get_video_drivers()
{
const int _size=256;
char drv_name[_size];
char drv_ver[_size];
char dev_name[_size];
AnsiString s0,s1,list;
int i;
list="";
for (i=0;;i++)
{
if (!capGetDriverDescription(i,drv_name,_size,drv_ver,_size)) break;
s0=drv_name;
s1=drv_ver;
list+=s0+" "+s1+"\n";
}
return list;
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_video_driver(int ix)
{
if (hcap==NULL) return;
capDriverConnect(hcap,ix);
capDriverGetCaps(hcap,&driver_cp,sizeof(CAPDRIVERCAPS));
capCaptureGetSetup(hcap,&capture,sizeof(CAPTUREPARMS));
// capture.dwRequestMicroSecPerFrame=10; // 1/fps [us]
capCaptureSetSetup(hcap,&capture,sizeof(CAPTUREPARMS));
capPreviewRate(hcap,1); // set preview [ms]
capPreviewScale(hcap,FALSE); // stretching off
//preview_start();
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::set_callback_on_frame()
{
if (ins_ix<0) ins_ix=VideoCaptureVFW_ins_get();
if (ins_ix<0) return;
VideoCaptureVFW_ins[ins_ix]=this;
ins_use|=_vfw_callbach_onframe;
capSetCallbackOnFrame(hcap,(void*)(VideoCaptureVFW_on_frame[ins_ix]));
}
//---------------------------------------------------------------------------
void VideoCaptureVFW::res_callback_on_frame()
{
if (ins_ix<0) return;
if (int(ins_use&_vfw_callbach_onframe))
{
ins_use^=_vfw_callbach_onframe;
capSetCallbackOnFrame(hcap,NULL);
}
if (ins_use) return;
VideoCaptureVFW_ins[ins_ix]=NULL;
ins_ix=-1;
}
//---------------------------------------------------------------------------
LRESULT VideoCaptureVFW::_on_frame(HWND hwnd,LPVIDEOHDR hdr)
{
fps.update();
int e=0;
if (hdr->dwBytesUsed<16) return 0; // ignore too small images
((TDirectMemoryStream*)(mem))->SetMemory(hdr->lpData,hdr->dwBytesUsed);
if ((hdr->lpData[6]=='J') // JPEG signature
&&(hdr->lpData[7]=='F')
&&(hdr->lpData[8]=='I')
&&(hdr->lpData[9]=='F'))
{
e=1;
TJPEGImage *jpg=new TJPEGImage;
jpg->LoadFromStream(mem);
bmp->Assign(jpg);
delete jpg;
} else
if ((hdr->lpData[0]=='B') // BMP signature
&&(hdr->lpData[1]=='M'))
{
e=1;
bmp->LoadFromStream(mem);
}
else{ // others
e=1;
copy_to_clipboard();
try {
bmp->LoadFromClipboardFormat(CF_BITMAP,Clipboard()->GetAsHandle(CF_BITMAP),NULL);
}
catch(char *str)
{
e=0;
int hnd=FileCreate("unsuproted_format.dat");
FileWrite(hnd,hdr->lpData,hdr->dwBytesUsed);
FileClose(hnd);
}
}
if (e)
{
if (on_frame) on_frame(*this);
}
return 0;
}
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
I have a small test app with this source code:
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
// select API:
#define _capture_VFW
// #define _capture_DirectShow
//---------------------------------------------------------------------------
#ifdef _capture_VFW
#include "VideoCaptureVFW.h"
#endif
#ifdef _capture_DirectShow
#include "DirectX92\\VideoCaptureDirectShow.cpp"
#endif
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graphics::TBitmap *bmp=new Graphics::TBitmap;
int _callback=0;
int _frame=0;
int _update=false;
//---------------------------------------------------------------------------
#ifdef _capture_VFW
VideoCaptureVFW vfw;
void on_frame_VFW(VideoCaptureVFW &cap)
{
if (_callback) Form1->Canvas->Draw(0,26,cap.bmp);
else if (!_frame) { bmp->Assign(cap.bmp); _frame=1; }
}
#endif
//---------------------------------------------------------------------------
#ifdef _capture_DirectShow
VideoCaptureDirectShow dsh;
void on_frame_DirectShow(VideoCaptureDirectShow &cap)
{
if (_callback) Form1->Canvas->Draw(0,26,cap.bmp);
else if (!_frame) { bmp->Assign(cap.bmp); _frame=1; }
}
#endif
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
#ifdef _capture_VFW
pan_VFW->Visible=true;
vfw.set_owner(this->Handle);
cb_driver->Items->Clear();
cb_driver->Items->Text=vfw.get_video_drivers();
cb_driver->ItemIndex=0;
vfw.on_frame=on_frame_VFW;
vfw.set_video_driver(cb_driver->ItemIndex);
vfw.grab_start();
#endif
#ifdef _capture_DirectShow
pan_DirectShow->Visible=true;
cb_device->Items->Clear();
cb_device->Items->Text=dsh.get_devices();
dsh.on_frame=on_frame_DirectShow;
_update=1;
cb_device->ItemIndex=0;
_update=0;
cb_device->OnChange(this);
/*
dsh.Select(0);
dsh.Start();
dsh.Stop();
*/
#endif
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
#ifdef _capture_VFW
vfw.grab_stop();
#endif
#ifdef _capture_DirectShow
dsh.Stop();
#endif
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
if ((!_callback)&&(_frame)) { Canvas->Draw(0,26,bmp); _frame=0; }
#ifdef _capture_VFW
Caption=AnsiString().sprintf("frame: %2i fps: %2.1lf",vfw.fps.frame,vfw.fps.fps);
#endif
#ifdef _capture_DirectShow
Caption=AnsiString().sprintf("frame: %2i fps: %2.1lf",dsh.fps.frame,dsh.fps.fps);
#endif
}
//---------------------------------------------------------------------------
//--- VFW -------------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::bt_dialog_sourceClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_source();
#endif
}
void __fastcall TForm1::bt_dialog_formatClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_format();
#endif
}
void __fastcall TForm1::bt_dialog_displayClick(TObject *Sender)
{
#ifdef _capture_VFW
vfw.dlg_display();
#endif
}
void __fastcall TForm1::cb_driverChange(TObject *Sender)
{
#ifdef _capture_VFW
vfw.set_video_driver(cb_driver->ItemIndex);
vfw.grab_start();
#endif
}
//---------------------------------------------------------------------------
//--- DirectShow ------------------------------------------------------------
//---------------------------------------------------------------------------
void __fastcall TForm1::cb_deviceChange(TObject *Sender)
{
#ifdef _capture_DirectShow
if (_update) return;
_update=1;
dsh.Select(cb_device->ItemIndex);
cb_format->Items->Clear();
cb_format->Items->Text=dsh.get_formats();
if (cb_format->Items->Count)
cb_format->ItemIndex=0;
_update=0;
cb_format->OnChange(this);
#endif
}
//---------------------------------------------------------------------------
void __fastcall TForm1::cb_formatChange(TObject *Sender)
{
#ifdef _capture_DirectShow
if (_update) return;
_update=1;
dsh.set_format(cb_format->Text);
_update=0;
#endif
}
//---------------------------------------------------------------------------
Its single form app with few buttons and combo box lists for dialog boxes and configuration (you can mimic them or ignore them). Did not share the DirectShow as its too big for 30K limit and slower anyway (but ist just a header + lib file no 3th party components). I have these VCL components on the form:
TTimer *Timer1; // 10ms info text update
TPanel *pan_VFW; // just to hold the components for VFW
TSpeedButton *bt_dialog_source; // these 3 buttons configure VFW ...
TSpeedButton *bt_dialog_format;
TSpeedButton *bt_dialog_display;
TComboBox *cb_driver; // this selects VFW device
TPanel *pan_DirectShow; // just to hold DirectShow components
TComboBox *cb_device; // this selects DirectShow device
TComboBox *cb_format; // this selects DirectShow format
I encapsulated the VFW and DirectShow stuff into configuration #define so you can ignore the DirectShow stuff completely.
Now when you use this you can play with resolution and formats to compare the fps to your DirectShow component grabber.
As you can see I do not use any 3th party components to grab image data from camera the VideoCaptureVFW.h is the only stuff you need.
[Edit1]
Here is the link to the Demo containing both VFW and DirectShow examples (source and win32 binaries) in Embarcadero BDS2006 C++.
[Edit2] your unsupported format
The file size is exactly 1920*1080*3 Bytes which hints raw 24bpp RGB feed. When I tried to visualize it it works (and yes Y is flipped) see tyhe code (no components on form this time):
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
Graphics::TBitmap *bmp=NULL;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner):TForm(Owner)
{
int xs=1920,ys=1080,x,y,a,hnd,siz;
BYTE *p,*dat=NULL;
// load frame
hnd=FileOpen("maybe_RGB24.dat",fmOpenRead);
siz=FileSeek(hnd,0,2); dat=new BYTE[siz];
FileSeek(hnd,0,0);
FileRead(hnd,dat,siz);
FileClose(hnd);
// convert RGB24 to 32bpp bitmap
bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
bmp->SetSize(xs,ys);
for (a=0,y=ys-1;y>=0;y--) // flip y
{
p=(BYTE*)bmp->ScanLine[y];
for (x=0;x<xs;x++)
{
p[0]=dat[a]; a++;
p[1]=dat[a]; a++;
p[2]=dat[a]; a++;
p[3]=0;
p+=4;
}
}
delete dat;
// resize form
ClientWidth=xs;
ClientHeight=ys;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if (bmp) delete bmp; bmp=NULL;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormPaint(TObject *Sender)
{
Canvas->Draw(0,0,bmp);
}
//---------------------------------------------------------------------------
And resulting screen:
beware I renamed the filename to maybe_RGB24.dat. You could decode this file-format by the frame size alone but its info should be somewhere like in the
AM_MEDIA_TYPE* mt;
structure but do not ask me where exactly I have no clue as I did code this a long time ago and do not use DirectX since (as all my attempts in the past reveals its inferiority to other apis does not matter if its sound or gfx or grabbing...)

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!

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

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