In a Delphi XE application I am trying to set up a global hook to monitor focus changes. The hook is created in a dll:
focusHook := SetWindowsHookEx( WH_CBT, @FocusHookProc, HInstance, 0 );
// dwThreadId (the last argument) set to 0 should create a global hook
In the same dll I have the hook procedure that posts a message to the host app window:
function FocusHookProc( code : integer; wParam: WPARAM; lParam: LPARAM ) : LResult; stdcall;
begin
if ( code < 0 ) then
begin
result := CallNextHookEx( focusHook, code, wParam, lParam );
exit;
end;
result := 0;
if ( code = HCBT_SETFOCUS ) then
begin
if ( hostHWND <> INVALID_HANDLE_VALUE ) then
PostMessage( hostHWND, cFOCUSMSGID, wParam, lParam );
end;
end;
This works, but the host only receives notifications on focus changes within the application itself. There is a memo and a few TButtons on the main form, and switching focus between them produces the expected message. However, any focus changes outside the application itself are never reported.
I suppose it has something to do with multiple instances of the DLL getting injected into other processes. There is a similar question with an accepted reply here, but it is for C, and I can't quite see how I can do the same in a Delphi dll (e.g. the pragma statements to set up shared memory).
(This is mostly a proof of concept, but I'd still like to get it to work. I need to know what window was active just before my app got activated by way of clicking, alt+tab, activation hotkey etc. The problem is that if the mouse or alt+tab is used, GetForegroundWindow always returns my own app's window handle, no matter how early I put it, such as by hooking the application's main message queue. So the hook seems like the only viable solution, though I don't really like the idea.)