Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

GOTFOCUS and LOSTFOCUS callback message

55 views
Skip to first unread message

Gianluca

unread,
Apr 27, 2005, 6:58:11 AM4/27/05
to
Hello all,

we would like to be notified when a ApplicationWindow(Word, Notepad, ...)
got and/or lost the focus.
Till now we assume that the AppWindow with focus is the returned hWnd from
getForegroundWindow(GetFocus and GetActiveWindow seem to have some other
means).

We are trying:
procedure WMActive(var Msg: TWMACTIVATE); message WM_ACTIVATE;
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;

without any significant result.

Could you support us?
Thanks in advance
Gianluca


Peter Below (TeamB)

unread,
Apr 27, 2005, 2:04:16 PM4/27/05
to
In article <426f...@newsgroups.borland.com>, Gianluca wrote:
> we would like to be notified when a ApplicationWindow(Word, Notepad, ...)
> got and/or lost the focus.

Windows operates on the principle "every application for itself", so it does
not offer any help in this area (in short: it's none of your business what
other applications do <g>).


> Till now we assume that the AppWindow with focus is the returned hWnd from
> getForegroundWindow(GetFocus and GetActiveWindow seem to have some other
> means).

Yes, the easiest way to implement what you need is to use a timer or
background thread that checks GetForegroundWindow at regular intervals. From
the window handle you get you can figure out the windows classname
(Windows.GetClassname), its caption (send WM_GETTEXTLENGTH and WM_GETTEXT
messages to it, using GetWindowText is not recommended for windows in other
processes), the process ID of the process it belongs to
(GetWindowthreadProcessID). Getting from the process ID to a process name is
a bit more complex, basically you need to enumerate all running processes
using the Toolhelp32 API or PSAPI and look for a process with a matching ID.


--
Peter Below (TeamB)
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be


Gianluca

unread,
Apr 28, 2005, 4:52:11 AM4/28/05
to
First really thanks for the support..

Than, the last idea we would like to submit to you:
could we register to a hwnd and to be notified when its state change?
We found some code in VB where the RegisterShellHookWindow is used..
Your impression?

Thanks again
Gianluca

"Peter Below (TeamB)" <10011...@compuXXserve.com> ha scritto nel
messaggio news:VA.0000baf...@nomail.please...

Peter Below (TeamB)

unread,
Apr 28, 2005, 1:43:41 PM4/28/05
to
In article <4270a483$1...@newsgroups.borland.com>, Gianluca wrote:
> Than, the last idea we would like to submit to you:
> could we register to a hwnd and to be notified when its state change?
> We found some code in VB where the RegisterShellHookWindow is used..
> Your impression?

I consider hooks (especially global hooks) to be terrible intrusive and
definitely not good for the health of a system. I do not recommend using
them.

Gianluca

unread,
Apr 29, 2005, 11:49:14 AM4/29/05
to
We agree with you, your considerations are correct and really appreciates,
unfortunately we have at least to try this way..

We found some VB code that works properly.. we tried to convert in Delphi,
and now it does not work any more.
After the start we can see StartHook called and execute correctly, then
WindowProc(is a callback) called 2 times and finally we got an
EExternalException.

During the debugging we found some differences between the VB and Delphi
versions:
VB vers:
- when the WindowProc is called the hWnd param has the same value we pass to
StartHook.
Delphi vers:
- when the WindowProc is called the first time hWnd param has an unknown
value(we searched it into the list of all HWnd are running), the second time
it has value 0 and then crashed.

Will be really a big help your support.
Thanks in advance
Gianluca

Simple code we are using:
{--------------------------------------------------------------}
unit frmMain;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, StdCtrls, StrUtils;

type
TForm1 = class(TForm)
List1: TRichEdit;
procedure FormShow(Sender: TObject);
procedure FormHide(Sender: TObject);
private
{ Private declarations }
hWndOldActive: LongInt;
public
{ Public declarations }

procedure WindowActivated(hWnd: LongInt);
procedure WindowRedraw(hWnd:LongInt);
procedure WindowCreated(hWnd: LongInt);
procedure WindowDestroyed(hWnd: LongInt);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

uses
WinFocus;

{
'Called by the module anytime another window gains focus. Since we only
' know the hwnd of the new window, we need to keep track of the last
' window to keep focus was (and don't assume that '** ' was put in the
' caption by us (a window can have '** ' in it's caption))
}
procedure TForm1.WindowActivated(hWnd: LongInt);
begin
List1.Lines.Add(IntToStr(hWnd));
End;

{
'Called by the module whenever a window caption is changed (or atleast,
' believed to be changed)
}
procedure TForm1.WindowRedraw(hWnd:LongInt);
begin
End;

//Called by the module whenever a window is created
procedure TForm1.WindowCreated(hWnd: LongInt);
begin
End;

//Called by the module whenever a window is destroyed
procedure TForm1.WindowDestroyed(hWnd: LongInt);
begin
End;

{
'On form load, start the subclassing of the window,
' as well as the shell hook
}
procedure TForm1.FormShow(Sender: TObject);
begin
WinFocus.StartHook(self.Handle);
end;

//On form exit, stop the subclassing
procedure TForm1.FormHide(Sender: TObject);
begin
WinFocus.Unhook(self.Handle);
end;

End.


{--------------------------------------------------------------}
unit WinFocus;

interface
uses Windows, frmMain;

//Windows API
Function CallWindowProc(lpPrevWndFunc: LongInt; hWnd: LongInt; msg:
LongInt;
wParam: LongInt; lParam: LongInt): LongInt;
stdcall;
Function GetProcAddress(hModule: LongInt; lpProcName: String): LongInt;
stdcall;
Function LoadLibrary(lpLibFileName: String): LongInt; stdcall;
Function RegisterWindowMessage(lpString: String): LongInt; stdcall;
Function SetWindowsHookEx(idHook: LongInt; lpfn: LongInt;
hmod: LongInt; dwThreadId: LongInt): LongInt;
stdcall;
Function SetWindowLong(hWnd: LongInt;nIndex: LongInt; dwNewLong: LongInt):
LongInt; stdcall;
Function RegisterShellHookWindow(hWnd: LongInt): LongInt; stdcall;


Procedure StartHook(hWnd: LongInt);
Procedure Unhook(hWnd: LongInt);


//Constants for Windows API
Const
WM_NCDESTROY = $00000082;

//Variables
var
lpPrevWndProc: LongInt; // Address of previos window proc
msgShellHook: LongInt; // Msg number of "SHELLHOOK" message

implementation
Function CallWindowProc; external 'user32.dll' name 'CallWindowProcA';
Function GetProcAddress; external 'kernel32.dll';
Function RegisterShellHookWindow; external 'user32.dll'

Function LoadLibrary; external 'kernel32.dll' name 'LoadLibraryA';
Function RegisterWindowMessage; external 'user32.dll' name
'RegisterWindowMessageA';
Function SetWindowsHookEx; external 'user32.dll' name 'SetWindowsHookExA';

Function SetWindowLong; external 'user32.dll' name 'SetWindowLongA';

//Stop the subclasing of the window
Procedure Unhook(hWnd: LongInt);
Begin
SetWindowLong(hWnd, Windows.GWL_WNDPROC, lpPrevWndProc);
End;

//Subclassing procedure, look for "SHELLHOOK" messages and process
Function WindowProc(hWnd: LongInt; uMsg: LongInt; wParam: LongInt; lParam:
LongInt): LongInt;
Begin

// If we receive this message, unhook our subclassing
// routing, to prevent crashing the app as it closes
if uMsg = WM_NCDESTROY then
Unhook(hWnd)

// This is the message generated from Shell32's
// ShellHookProc, decode it, and send the results up to the From1's
handlers
else if uMsg = msgShellHook then
begin
Case wParam of
Windows.HSHELL_WINDOWACTIVATED:
Form1.WindowActivated(lParam);
End;
End;

Result := CallWindowProc(lpPrevWndProc, hWnd, uMsg, wParam, lParam);
End;

//Start the subclassing of the window
procedure Hook(hWnd: LongInt);
Begin
lpPrevWndProc := Windows.SetWindowLongA(hWnd, GWL_WNDPROC,
LongInt(@WindowProc));
End;

// Main Entry point. Setup the system wide WH_SHELL hook, and start the
// subclassing of the form to view messages.
procedure StartHook(hWnd: LongInt);
var
hLibShell: LongInt;
lpHookProc: LongInt;
begin

//This is the message that Shell32's ShellHookProc sends us whenever
// a shell hook occurs
msgShellHook := Windows.RegisterWindowMessageA('SHELLHOOK');

//Load the Shell32 library, and find the ShellHookProc so we can pass
// it to SetWindowsHookEx to create the Shell Hook
hLibShell := LoadLibrary('shell32.dll');
lpHookProc := GetProcAddress(hLibShell, 'ShellHookProc');

//Initialize ShellHookProc
RegisterShellHookWindow(hWnd);

SetWindowsHookEx(WH_SHELL, lpHookProc, hLibShell, 0);

//Start the subclassing of the window so we get the "SHELLHOOK"
// messages generated from ShellHookProc
Hook(hWnd);
End;

End.


Peter Below (TeamB)

unread,
Apr 29, 2005, 1:45:24 PM4/29/05
to
In article <4272...@newsgroups.borland.com>, Gianluca wrote:
> We agree with you, your considerations are correct and really appreciates,
> unfortunately we have at least to try this way..
>
> We found some VB code that works properly.. we tried to convert in Delphi,
> and now it does not work any more.

A global hook has to sit in a DLL and this DLL will get mapped into the address
space of every process on the system. Every one of these "instances" will have
its own data section, so you cannot use normal (global) variables to access
data that you set in one of these instances (e.g. when installing the hook)
from one of the other instances. Such data has to be kept in a named
memory-mapped file each of the instances opens when its hook proc is called the
first time.

Only thread-specific hooks for threads in your own application can be
implemented in your EXEs code. The DLL has to communicate with the exe by
sending it messages. Believe me, you are *much* better off just checking the
foreground window in a timer 5 times a second or so. That will put less of a
burden on the system than a WH_CALLWNDPROC hook (which you would need to catch
the messages that indicate a move of focus from one app to another) and is way
easier to implement (and less dangerous for the system).

0 new messages