Any ideas? Am I doing something wrong?
Delphi code...
private
procedure WndProcTest(var Msg: TWMActivate); message WM_ACTIVATE;
procedure TForm1.WndProcTest(var Msg: TWMActivate);
begin
case Msg.Msg of
WM_ACTIVATE:
begin
case Msg.Active of
WA_ACTIVE, WA_CLICKACTIVE: // Do something with Msg.ActiveWindow
end;
end;
end;
end;
> The following code should allow the identification of a window
> which has been activated by capturing the WM_ACTIVATE
> message - however Msg.ActiveWindow always seems to
> return 0 (null).
That is perfectly valid for it to do. Have a look at the documentation for
WM_ACTIVATE:
hwndPrevious
Value of lParam. Identifies the window being activated or deactivated,
depending on the value of the fActive parameter. If the value of fActive is
WA_INACTIVE, hwndPrevious is the handle of the window being activated. If
the value of fActive is WA_ACTIVE or WA_CLICKACTIVE, hwndPrevious is the
handle of the window being deactivated. This handle can be NULL.
Look at the last sentence.
> private
> procedure WndProcTest(var Msg: TWMActivate); message WM_ACTIVATE;
>
> procedure TForm1.WndProcTest(var Msg: TWMActivate);
> begin
> case Msg.Msg of
You do not need to use a 'case' statement inside a message handler. The
function is already guaranteed to be called by only the specified message,
so you don't need to check it a second time.
Gambit
You are correct as usual, however the WA_CLICKACTIVE message does not seem
to be correctly captured (at least on my Vista system). WA_CLICKACTIVE does
not fire when a window is activated by a click although WA_ACTIVE and
WA_INACTIVE function correctly.
Regards,
Alex Gregory
"Remy Lebeau (TeamB)" <no....@no.spam.com> wrote in message
news:46e5c238$3...@newsgroups.borland.com...
How do I capture WM_ACTIVATE messagessystem-wide? I have a rough idea, see
below. Not good enough to function though ;)
procedure TForm1.FormCreate(Sender: TObject);
begin
Hook := SetWindowsHookEx(WH_CBT, @HookProc, hInstance,
GetCurrentThreadID);
if Hook = 0 then
MessageDlg('Hook not started.', mtError, [mbOK], 0);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnhookWindowsHookEx(Hook);
end;
function HookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT;
stdcall;
begin
if Code < 0 then
CallNextHookEx(Hook, Code, wParam, lParam);
if Code = WM_ACTIVATE then
case LoWord(wParam) of
WA_CLICKACTIVE:
Form1.Memo1.Lines.Add('WA_CLICKACTIVE: ' + IntToStr(lParam));
WA_ACTIVE:
Form1.Memo1.Lines.Add('WA_ACTIVE: ' + IntToStr(lParam));
WA_INACTIVE:
Form1.Memo1.Lines.Add('WA_ACTIVE: ' + IntToStr(lParam));
end;
Result := CallNextHookEx(Hook, Code, wParam, lParam);
end;
Regards,
Alex.
"Alex Gregory" <in...@blue-aura.co.uk> wrote in message
news:46e6858e$2...@newsgroups.borland.com...
> How do I capture WM_ACTIVATE messagessystem-wide?
System-wide hooks must be implemented inside a DLL. A process cannot hook
another process. A DLL is needed so that the hook can be injected into each
process individually.
The code you showed is hooking your own process only, not other processes.
> if Code = WM_ACTIVATE then
> case LoWord(wParam) of
That will not work, as that is not how messages are delivered to a CBT hook.
If you want to use a CBT hook, then you have to look for the HCBT_ACTIVATE
notification instead, and process its CBTACTIVATESTRUCT structure, ie:
function HookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM):
LRESULT; stdcall;
var
CurActiveWindow: HWND;
WindowBeingActivated: HWND;
WasByMouse: BOOL;
begin
if Code = HCBT_ACTIVATE then
begin
CurActiveWindow := PCBTActivateStruct(lParam)^.hWndActive;
WasByMouse := PCBTActivateStruct(lParam)^.fMouse;
WindowBeingActivated := HWND(wParam);
// send a notification to your app to process the activation
end;
Result := CallNextHookEx(Hook, Code, wParam, lParam);
end;
Otherwise, to handle the actual WM_ACTIVATE message, you need to use a
WH_CALLWNDPROC or WH_GETMESSAGE hook instead.
Gambit