Keyboard logging functionality

  • Thread starter Thread starter Stephen Corey
  • Start date Start date
S

Stephen Corey

I need to write a program that launches Internet Explorer, then counts
how many <ENTER> keys are pressed inside IE. I've seen a lot of
references to the SetWindowsHookEx() API call, but all sources I found
seem to be piece-meal and incomplete. I'm using VC++ .NET, and would
rather avoid using the WinAPI, if possible. Is there an easier way
(perhaps using .NET) to do this?
 
Stephen Corey said:
I need to write a program that launches Internet Explorer,

See CreateProcess(). It will return a process identifier and a thread
identifier which will come in handy shortly.
then counts how many <ENTER> keys are pressed inside IE. I've seen a lot
of references to the SetWindowsHookEx() API call, but all sources I found
seem to be piece-meal and incomplete.

:-) Well, they probably demonstrate how to intercept keystrokes but not how
to implement your task.
I'm using VC++ .NET, and would rather avoid using the WinAPI,
if possible. Is there an easier way (perhaps using .NET) to do this?

I don't believe so.

One way to attack the problem would be with a system wide keyboard hook
which must necessarily be implemented in a DLL. You'd only be interested in
notifications where the WPARAM parameter of the notification is VK_ENTER and
where the high bit (#31) of the LPARAM parameter is 0. When that's the case
you'd call GetFocus() to find the active window (that's the destination of
the keystroke) and then GetWindowThreadProcessId() to find either the
identifier of that the owning process or thread. You'd compare either
against what you got from CreateProcess() and on a match increment your
count.

That method is not at all specific to IE but would work with any process you
create.

IE does permit itself to be extended with add-ons so there _may_ be some
easier way inside one of these extensions. You might want to search for a
group devoted to IE to see if there is some easier way.

By the way, why do you need to count the ENTER keys pressed?

Regards,
Will
 
William said:
By the way, why do you need to count the ENTER keys pressed?

Yes, I was just thinking to myself: "Whatever on earth for??" Sounds
like an interesting application.
 
Joel said:
Yes, I was just thinking to myself: "Whatever on earth for??" Sounds
like an interesting application.

Some of my users log onto a website that uses an ActiveX control to log
onto an AS/400 (within the web browser). We get charged for every
"screen" sent from the server, which happens whey they hit ENTER. To
avoid having to make them keep track of how many screens they see, I can
just count the ENTER keys.

I see that I can use WH_KEYBOARD_LL to create a global hook WITHOUT
having a separate DLL, but I can't find any examples anywhere. The only
code I see is for VB or C#. Do either of you know of any?? I'd even take
a "with the DLL" example if nothing better can be found...
 
Stephen Corey said:
I see that I can use WH_KEYBOARD_LL to create a global hook WITHOUT having
a separate DLL, but I can't find any examples anywhere.

Hmm, where do the docs say that? In the help entry for SetWindowsHookEx()
their is a table in which the WH_KEYBOARD_LL hook is listed as having only
global scope.

Then in the remarks for the HOOKPROC parameter in the call there is this

<quote>
[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or
specifies the identifier of a thread created by a different process, the
lpfn parameter must point to a hook procedure in a dynamic-link library
(DLL). Otherwise, lpfn can point to a hook procedure in the code associated
with the current process.
</quote>

Taken together that means that a DLL is required, no?
is for VB or C#. Do either of you know of any?? I'd even take a "with the
DLL" example if nothing better can be found...

There is old C code for a global hook in the file Hook.c in the Platform
SDK's directory

Samples\multimedia\gdi\WinCap32

Note its use of the hook is canonical in that the hook detects a condition
but does NOT handle it. It posts a message back to the application which
planted the hook and that application is the one that handles it. This is
the right way because

a) Global hooks should have small footprints as they bloat _every_ windowed
application
b) Their code runs in the context of the application being hooked. An errant
hook can crash an otherwise fine application

Regards,
Will
 
William said:
I see that I can use WH_KEYBOARD_LL to create a global hook WITHOUT having
a separate DLL, but I can't find any examples anywhere.


Hmm, where do the docs say that? In the help entry for SetWindowsHookEx()
their is a table in which the WH_KEYBOARD_LL hook is listed as having only
global scope.

Then in the remarks for the HOOKPROC parameter in the call there is this

<quote>
[in] Pointer to the hook procedure. If the dwThreadId parameter is zero or
specifies the identifier of a thread created by a different process, the
lpfn parameter must point to a hook procedure in a dynamic-link library
(DLL). Otherwise, lpfn can point to a hook procedure in the code associated
with the current process.
</quote>

Taken together that means that a DLL is required, no?

is for VB or C#. Do either of you know of any?? I'd even take a "with the
DLL" example if nothing better can be found...


There is old C code for a global hook in the file Hook.c in the Platform
SDK's directory

Samples\multimedia\gdi\WinCap32

Note its use of the hook is canonical in that the hook detects a condition
but does NOT handle it. It posts a message back to the application which
planted the hook and that application is the one that handles it. This is
the right way because

a) Global hooks should have small footprints as they bloat _every_ windowed
application
b) Their code runs in the context of the application being hooked. An errant
hook can crash an otherwise fine application

Regards,
Will

In experts exchange, as well as a few other sites, people mentioned that
with that hook, you didn't have to have your code in a separate DLL.

So, the main code to be managed, and I guess the DLL code needs to be
unmanaged?? What type of a project is the DLL?

Is there no code that is designed for VC++ .NET?
 
Stephen Corey said:
William DePalo [MVP VC++] wrote:
In experts exchange, as well as a few other sites, people mentioned that
with that hook, you didn't have to have your code in a separate DLL.

Hmm. To hook a process other than the one in which the SetWindowsHookEx()
call is made. Sounds hokey to me.
So, the main code to be managed, and I guess the DLL code needs to be
unmanaged?? What type of a project is the DLL?

The DLL would be native. If you are using VS.Net 2003 you first select C++
projects and then click on the Win32 icon. Then click Application Settings
and choose the DLL option. A
Is there no code that is designed for VC++ .NET?

As far as I know, no. Realize that I don't claim to be a .Net expert.

Regards,
Will
 
William said:
William DePalo [MVP VC++] wrote:
In experts exchange, as well as a few other sites, people mentioned that
with that hook, you didn't have to have your code in a separate DLL.


Hmm. To hook a process other than the one in which the SetWindowsHookEx()
call is made. Sounds hokey to me.

So, the main code to be managed, and I guess the DLL code needs to be
unmanaged?? What type of a project is the DLL?


The DLL would be native. If you are using VS.Net 2003 you first select C++
projects and then click on the Win32 icon. Then click Application Settings
and choose the DLL option. A

Is there no code that is designed for VC++ .NET?


As far as I know, no. Realize that I don't claim to be a .Net expert.

Regards,
Will

Ok, well with the callback code in a separate DLL, how will I get the
"ENTER count" back into my managed code?
 
Stephen Corey said:
Ok, well with the callback code in a separate DLL, how will I get the
"ENTER count" back into my managed code?

You adopt some interprocess communication mechanism between the DLL (which
runs in the applications being hooked) and your application which planted
the hook (presumably via some form of interop). The sample to which I
pointed posts a WM_COMMAND message. You code do that.

Of course, that begs the question as to how you retrieve the message on the
managed side. It's not something that I've done so I can't offer any advice.
IMO, what you are trying to do is best done natively, anyway.

Regards,
Will
 
Yes, I was just thinking to myself: "Whatever on earth for??" Sounds
Some of my users log onto a website that uses an ActiveX control to log
onto an AS/400 (within the web browser). We get charged for every "screen"
sent from the server, which happens whey they hit ENTER. To avoid having
to make them keep track of how many screens they see, I can just count the
ENTER keys.

You may consider another approach to handle this case (case of using ActiveX
in the Internet Explorer):
1. Create alternative ActiveX, which mimics interface of the original
ActiveX and forwards all requests to it.
2. Implement there your tracing logic.
3. Register ActiveX substitution for the Internet Explorer in the registry:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\ActiveX
Compatibility\{original guid}]
"AlternateCLSID"="{substitution guid}"
"Compatibility Flags"=dword:00000000
 
Back
Top