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

SetWindowsHookEx

123 views
Skip to first unread message

Mark Erbaugh

unread,
Nov 13, 2000, 3:00:00 AM11/13/00
to
I'm trying to use SetWindowsHookEx to allow my program to detect events in
another program. I don't need to change the behaviour of the other program,
I just need to know when the user clicks on certain buttons. I learned that
for a hook to work, it needs to be in a DLL. The code below is from my
attempt at this DLL. As long as the handle passed to InstallHook is from
the program that loads the DLL, I can get this to work (i.e. the CodeSite
viewer gets the 'Mouse' message). However, if I try to pass a handle from
another running program (the main program gets this from calls to and
callbacks from EnumWindows and EnumChildWindows), I get no messages. I'm
pretty sure that I am passing the correct handle, as the CodeSite.SendFmtMsg
call in InstallHook reports the expected WindowText. Also, I had originally
specified different parameter types to MyMouseHook (I originally had lParam
as type TMsg - which I found in the VCL source in forms.pas). With those
parameters, I consistently got an error (memory x ... can't be read)
whenever I moved my mouse into the window of the hooked program.

TIA,
Mark

var
MHook: HHOOK;
BtnHnd : hwnd;
fBuf : array[0..255] of char;
CB : TCallback;

function MyMouseHook(nCode: Integer; wParam: longint; lParam : longint):
longint; stdcall;
begin
Result := CallNextHookEx(MHook, nCode, wParam, lparam);
if (nCode = HC_ACTION) then
with PMouseHookStruct(lParam)^ do
begin
if hwnd = btnHnd then
begin
CodeSite.SendMsg('Mouse');
end;
end;
end;

procedure InstallHook(const aHandle : hwnd); stdcall;
var
thd : dword;
begin
btnHnd := aHandle;
GetWindowText(aHandle, fBuf, sizeof(fBuf));
thd := GetWindowThreadProcessId(aHandle, nil);
CodeSite.SendFmtMsg('%s - %d', [fBuf, thd]);
MHook :=
SetWindowsHookEx(WH_MOUSE, @MyMouseHook, hInstance, thd);
end;


Russell E. Holcomb

unread,
Nov 13, 2000, 3:00:00 AM11/13/00
to
You need to use a memory mapped file for your global variables. They are
not shared among the hooked apps.

Russ

Mark Erbaugh <ma...@nospam.microenh.com> wrote in message
news:8uot53$e1...@bornews.inprise.com...

Jim Kueneman

unread,
Nov 13, 2000, 3:00:00 AM11/13/00
to
> MHook :=
> SetWindowsHookEx(WH_MOUSE, @MyMouseHook, hInstance, thd);
> end;

By passing "thd" you are telling windows that the hook is only valid for that
process, ie it is in the context of that thread, , which is not even yours! It
no wonder it is choking. For a global hook you have to pass 0 to tell windows
to hook all threads and put your callback procedure in the chain.

Also save youself a lot of grief and put

initialialization
DisableThreadLibraryCalls;

in any dll that will be used in any thread but your own.

Jim


Mark Erbaugh

unread,
Nov 13, 2000, 3:00:00 AM11/13/00
to
Jim,

I'm not sure I understand global hooks. I don't want to get mouse messages
going to every app in the system, just messages going to a particular window
in a particular app. Is this not possible? If not, I guess I can filter them
in my event handler.

Thanks for the tip on DisableThreadLibraryCalls. I hadn't seen that before.

Mark

"Jim Kueneman" <ji...@azstarnet00.com> wrote in message
news:3A104186...@azstarnet00.com...

Jim Kueneman

unread,
Nov 13, 2000, 3:00:00 AM11/13/00
to

Mark Erbaugh wrote:

> Jim,
>
> I'm not sure I understand global hooks. I don't want to get mouse messages
> going to every app in the system, just messages going to a particular window
> in a particular app. Is this not possible? If not, I guess I can filter them
> in my event handler.

You may try what Russell Holcomb suggested, memory mapped files. That way the
memory is shared between apps. I have never tried to pass a handle to a window
that my process did not own in a hook.


>
> Thanks for the tip on DisableThreadLibraryCalls. I hadn't seen that before.
>

This was "discovered" several months ago here on this list by a few who where
have a hard time keeping global CBT hooks from crashing in a networking
enviroment (dialup as well). Actually it was Russell Holcomb who started it all
if I remember right.

Jim Kueneman

Mark Erbaugh

unread,
Nov 14, 2000, 12:22:13 AM11/14/00
to
Can you give me more information on memory mapped files? I'm not sure what
you mean. Are they documented in the Delphi or Windows help files? Can you
point me to some sample code?

Thanks,
Mark

"Russell E. Holcomb" <reho...@earthlink.net> wrote in message
news:3a103df1$1_1@dnews...

Jim Kueneman

unread,
Nov 14, 2000, 3:00:00 AM11/14/00
to

Mark Erbaugh wrote:

> Can you give me more information on memory mapped files? I'm not sure what
> you mean. Are they documented in the Delphi or Windows help files? Can you
> point me to some sample code?
>

Memory Mapped Files are the windows way for apps to share memory. You look
them like files. You create them, CreateFileMapping, then open them to map the
memory to your threads memory space to read the information, MapViewOfFile,
then close close it UnMapViewOfFile(Shared). These are all API calls.
What you have to remember is the dll is loaded into the memory address space of
the thread who owns the window you passed in the SetWindowsHook call. Although
you wrote that block of code it is the other program that will be executing it
so it only can access memory in its address space, which is why you are having
problems. By using a memory mapped file you can allow the other program to
store information in the memory mapped file then within a function in your
program open this file and read the contents to pass the infomation across
programs. The question is how to let you program know when hooked program has
put new information in the mapped file. One way is to possibly create a mapped
file with the handle of the of the window you use to show the results then in
the hook procedure open this file and send that window a user defined message
to signal it. It may be possible to us an Event or Mutex that is signaled when
the mapped file changes. In you program have a thread with a thread loop that
uses WaitForSingleObject to listen for the mapped file to change. These are
just a few thoughts that came to mind.

I uploaded the example going around when trying to solve the global hook
crashing problem, which I mentioned elsewhere, to the
borland.public.attachments group. It uses memory mapped files. I would like to
give credit to the individual who supplied this but his name escapes me, Paul
?????.

Jim


Craig Stuntz

unread,
Nov 14, 2000, 3:00:00 AM11/14/00
to

Jim Kueneman wrote:
>
> > Thanks for the tip on DisableThreadLibraryCalls. I hadn't seen that before.
>
> This was "discovered" several months ago here on this list by a few who where
> have a hard time keeping global CBT hooks from crashing in a networking
> enviroment (dialup as well).

Apparently Borland knows about this too since it appears in the hook
demo. I've never been able to find it documented anywhere, however,
despite spending some time searching Borland and MSDN.

From what I found on MSDN, it does seem that the notifications are
usually unnecessary and add significant overhead to the hook anyway,
which would seem to indicate that turning them off is a good idea for
global hooks even if there wasn't a stability issue.

FWIW,

-Craig

--
Craig Stuntz Vertex Systems Corporation
Senior Developer http://www.vertexsoftware.com

Delphi/InterBase weblog: http://delphi.weblogs.com

Mark Erbaugh

unread,
Nov 14, 2000, 3:00:00 AM11/14/00
to
Jim,

If the data that needs to be passed from the hooked app to the other app is
small, can it just be passed as the lparam and wparam members of an event
record without the need for a memory mapped file? In my case, all I need to
know is that the user clicked on a button in the hooked app. A simple
integer could tell me which button.

Thanks for the explanation and the upload. I've got it and will take a look.

Mark

"Jim Kueneman" <ji...@azstarnet00.com> wrote in message

news:3A114040...@azstarnet00.com...


>
>
> Mark Erbaugh wrote:
>
> > Can you give me more information on memory mapped files? I'm not sure
what
> > you mean. Are they documented in the Delphi or Windows help files? Can
you
> > point me to some sample code?
> >
>

Jim Kueneman

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to

Mark Erbaugh wrote:

> If the data that needs to be passed from the hooked app to the other app is
> small, can it just be passed as the lparam and wparam members of an event
> record without the need for a memory mapped file? In my case, all I need to
> know is that the user clicked on a button in the hooked app. A simple
> integer could tell me which button.
>

That may work. Give it a try.

Jim


Craig Stuntz

unread,
Nov 16, 2000, 3:00:00 AM11/16/00
to

Mark Erbaugh wrote:
>
> If the data that needs to be passed from the hooked app to the other app is
> small, can it just be passed as the lparam and wparam members of an event
> record without the need for a memory mapped file?

Windows has a message for this sole purpose: WM_COPYDATA.

HTH,

0 new messages