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

Global Keyboard Hook causes crashes in other programs.

168 views
Skip to first unread message

tyra...@gmail.com

unread,
Jan 19, 2008, 1:09:53 PM1/19/08
to
I am just trying to get started with win32 hooks, so I figured I
should start out by installing a hook that does nothing.

No errors are reported with my code, yet whenever I go to another
program (like notepad) and type any key, it stalls.

I am new to DLL's so this my have to do with other things unrelated to
the code itself...
I just need to know that this code in principle should not cause any
significant problems, and any guesses as to what may be causing it.

Three files: KeyConverter.c KeyConverterGlobalHook.h
KeyConverterGlobalHook.c (I think the problem should revolve around
the code in KeyConverterGlobalHook.c)


/* FILE: KeyConverter.c */
/* gcc KeyConverter.c -o KeyConverter KeyConverter.dll */
#include <windows.h>
#include "KeyConverterGlobalHook.h"

/* error handler */

int main(int argc, char **argv)
{
HMODULE module = LoadLibrary("KeyConverter");
FARPROC module_HookProc;

if (module == 0) {/*handle error*/}

module_HookProc = GetProcAddress(module, "HookProc@12");
if (module_HookProc == 0){/*handle error*/}

hook = (HHOOK) SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC) module_HookProc, module, 0);
if (hook == 0){/*handle error*/}

scanf("\n");
UnhookWindowsHookEx(hook);
return 0;
}


/*FILE: KeyConverterGlobalHook.h */
#ifndef _KEY_CONVERTER_GLOBAL_HOOK_H_
#define _KEY_CONVERTER_GLOBAL_HOOK_H_

#include <windows.h>

static HHOOK hook = 0;

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);

#endif

/*FILE: KeyConverterGlobalHook.c */
/* gcc KeyConverterGlobalHook.c -c -o KeyConverter.o -O0
* gcc -o KeyConverter.dll KeyConverter.o -shared
* rm KeyConverter.o -v
*/
#include "KeyConverterGlobalHook.h"

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
/*JUST RETURN! DO NOT DO ANYTHING! yet causes havok... */
return CallNextHookEx(hook, nCode, wParam, lParam);
}


Sam of California

unread,
Jan 19, 2008, 6:50:49 PM1/19/08
to
<tyra...@gmail.com> wrote in message
news:16e6eb5b-e4ab-42d6...@z17g2000hsg.googlegroups.com...

>
> No errors are reported with my code, yet whenever I go to another
> program (like notepad) and type any key, it stalls.

It amazes me how many people say that there were no compile errors. Anytime
a programmer says that I get the impression they have not done much
programming. Execution time errors are not possible if the source did not
compile. Most important, a successful compile rarely has any relevance to
successful execution.

Or maybe I am missing something. What relevance does a successful compile
have to this problem?

> I am new to DLL's so this my have to do with other things unrelated to
> the code itself...
> I just need to know that this code in principle should not cause any
> significant problems, and any guesses as to what may be causing it.

One guess is that you have not read the documentation adequately and/or you
are assuming it is not important to do what it says. Read the KeyboardProc
hook procedure documentation some more; in particular, read what it says
about the hook code (the first parameter). I don't know if that makes a
difference but you should follow the documentation as closely as possible,
especially when things don't work.

Also, I don't see where the hook handle (the first parameter of
CallNextHookEx) is provided; so ensure that is valid.

tyra...@gmail.com

unread,
Jan 20, 2008, 6:55:24 PM1/20/08
to
>> No errors are reported with my code, yet whenever I go to another
>> program (like notepad) and type any [one :-)] key, it (notepad) stalls.

>
> What relevance does a successful compile
> have to this problem?

I did not specify compile time errors. I commented out the 'error
handling'
code so that the main details of the program could be understood more
rapidly,
all that needs to be known of the error checks is that nothing was
reported
(for example: module, module_HookProc, and hook are not comparatively
equal to
null pointers). This was my intended meaning, sorry for not being
specific.

>> I am new to DLL's so this my have to do with other things unrelated to
>> the code itself...
>> I just need to know that this code in principle should not cause any
>> significant problems, and any guesses as to what may be causing it.
>
> One guess is that you have not read the documentation adequately and/or you
> are assuming it is not important to do what it says.

I may not have read the documentation correctly, and I believe that
following
standards is important.

> Read the KeyboardProc hook procedure documentation some more; in particular,
> read what it says about the hook code (the first parameter).

I believe you may be mixing up the parameters of different functions.
You refer
to "hook code (the first parameter)" if you have mixed-up the
functions you may
be referring to the actual hook id reference of SetWindowsHookEx or
CallNextHookEx.

From documentation of KeyboardProc
"If code is less than zero, the hook procedure must return the value
returned by
CallNextHookEx."
"If code is greater than or equal to zero, and the hook procedure did
not
process the message [which applies to me], it is highly recommended
that you
call CallNextHookEx and return the value"

So I just return the value of CallNextHookEx in all cases as I am not
processing
the message.

> Also, I don't see where the hook handle (the first parameter of
> CallNextHookEx) is provided; so ensure that is valid.

To clear things up I am compiling KeyConverterGlobalHook.c/h into a
DLL and
KeyConverter.c into a standard executable.

static HHOOK hook = 0;

of KeyConverterGlobalHook.h part of the DLL, and is set by the other
program in
KeyConverter.c. Not concerned about this aspect as the documentation
clearly
states that the parameter is ignored for "Windows NT/XP/2003" which is
my
testing platform. I was only supplying a parameter as a possible
guess as to
the cause of the crashes. The same results occur if hook is local to
KeyConverter.c and zero is passed into CallNextHookEx, which may
indicate that
the main program of KeyConverter.c does not actually change the value
of hook in
the DLL of KeyConverterGlobalHook.h from the perspective of the
operating
system, but as I already stated this should be of no difference as the
parameter
is supposedly ignored.

MSDN References:
KeyboardProc http://msdn2.microsoft.com/en-us/library/ms644984(VS.85).aspx
CallNextHookEx http://msdn2.microsoft.com/en-us/library/ms644974(VS.85).aspx
SetWindowsHookEx http://msdn2.microsoft.com/en-us/library/ms644990(VS.85).aspx
If somehow this is not the current or official standard please correct
me
immediately.

Sam of California

unread,
Jan 21, 2008, 2:03:32 AM1/21/08
to
<tyra...@gmail.com> wrote in message
news:d7c25cf8-daf6-485d...@k39g2000hsf.googlegroups.com...

>
>> Read the KeyboardProc hook procedure documentation some more; in
>> particular,
>> read what it says about the hook code (the first parameter).
> I believe you may be mixing up the parameters of different functions.
> You refer
> to "hook code (the first parameter)" if you have mixed-up the
> functions you may
> be referring to the actual hook id reference of SetWindowsHookEx or
> CallNextHookEx.

I have an old copy of the MSDN that I use; in it the first parameter of the
KeyboardProc hook procedure is called a hook code.

> From documentation of KeyboardProc
> "If code is less than zero, the hook procedure must return the value
> returned by
> CallNextHookEx."
> "If code is greater than or equal to zero, and the hook procedure did
> not
> process the message [which applies to me], it is highly recommended
> that you
> call CallNextHookEx and return the value"

Sorry; here again I was betrayed by the old copy of the MSDN that I use and
poor personal memory.

> Not concerned about this aspect as the documentation
> clearly
> states that the parameter is ignored for "Windows NT/XP/2003" which is
> my
> testing platform.

Sorry; here again I was betrayed by the old copy of the MSDN that I use and
poor personal memory.

David Jones

unread,
Jan 21, 2008, 9:14:28 AM1/21/08
to
<tyra...@gmail.com> wrote...

> No errors are reported with my code, yet whenever I go to another
> program (like notepad) and type any key, it stalls.
>
> int main(int argc, char **argv)
> {
> HMODULE module = LoadLibrary("KeyConverter");
> FARPROC module_HookProc;
>
> if (module == 0) {/*handle error*/}
>
> module_HookProc = GetProcAddress(module, "HookProc@12");
> if (module_HookProc == 0){/*handle error*/}
>
> hook = (HHOOK) SetWindowsHookEx(WH_KEYBOARD,
> (HOOKPROC) module_HookProc, module, 0);
> if (hook == 0){/*handle error*/}
>
> scanf("\n");
> UnhookWindowsHookEx(hook);
> return 0;
> }
>
> LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
> {

> return CallNextHookEx(hook, nCode, wParam, lParam);
> }

How is the value of hook getting transferred from the executable to the
DLL? Even if they share a common header, it would be two different
variables since it is in two different modules.

(Incidentally, that's why I usually put my SetWindowsHookEx /
UnhookWindowsHookEx calls in the DLL and export some wrapper functions;
that way, the HHOOK value is kept internal to the module, so there's no
need to transfer the value between the DLL and the application. It just
makes things easier that way, IMHO.)

David

tyra...@gmail.com

unread,
Jan 28, 2008, 3:46:40 PM1/28/08
to
> How is the value of hook getting transferred from the executable to the
> DLL? Even if they share a common header, it would be two different
> variables since it is in two different modules.

Right I was just randomly trying different arrangements of variable
placement until I learned that even if there is only one copy of the
dll module loaded into memory each program will have it's own copy of
the dll's global variables. However as I stated earlier that is not a
concern for me as that parameter is ignored by the win32 api's.

I compile KeyConverter.c into KeyConverter.exe
and KeyConverterGlobalHook.c into KeyConverterGlobalHook.dll
Now my code simply registers a hook that does nothing but create a
file and write to it and immediately close it.
However, upon running the program and registering the hook from the
executable if find that the file is never created, which indicates to
me that the hook is never called in the first place (or that there are
file io issues (which I consider unlikely)).
When registering the hook as type WH_KEYBOARD it causes another
program such as Notepad to stall upon a key being entered (with
notepad currently in focus), but if I register it as WH_KEYBOARD_LL
Notepad will operate normally with only a delay in keyboard processing
(but still no file creation). So what I really need to know is:
should this work, why won't it work, and does it work for you?

I think it would be far less time consuming if someone else could
compile my code and see if it causes any of the problems I have
described. Do not worry about crashing the console, any keyboard
input into the console that is running KeyConverter.exe has never
stalled. However, please do not test this program with anything
except non-essential programs, eg. don't test this on your unsaved
final project for school.)

What this program should do is possibly cause some minor delays to
typing in Notepad, and cause the creation of the file C:\hi.bin.

Also you may need to alter
module_HookProc = GetProcAddress(module, "HookProco@12");
to what ever your compiler outputs as the external name of the hook in
the dll.

This time no code has been commented out.

/* KeyConverter.c */
/* gcc KeyConverter.c -o KeyConverter -L./ -lKeyConverterGlobalHook


*/
#include <windows.h>
#include "KeyConverterGlobalHook.h"

#include <stdio.h>

char* getWin32SystemError()
{
DWORD ec = GetLastError();
char* em = malloc(sizeof(char)*(FORMAT_MESSAGE_MAX_WIDTH_MASK+1));
if (0==FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM
|FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, ec, 0, em,
FORMAT_MESSAGE_MAX_WIDTH_MASK+1, 0)) {
sprintf(em, "%xlx", ec);
return em;
} else {
return em;
}
}


int main(int argc, char **argv)
{

HMODULE module = LoadLibrary("KeyConverterGlobalHook");
FARPROC module_HookProc;
HHOOK hook;

if (module == 0)
{
char* em = getWin32SystemError();
printf("Error loading libary: [%s]\a\n", em);
free(em);
return 1;
}

module_HookProc = GetProcAddress(module, "HookProco@12");
if (module_HookProc == 0)
{
char* em = getWin32SystemError();
printf("Error loading function from libary: [%s]\a\n", em);
free(em);
return 1;
}

hook = (HHOOK) SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)
module_HookProc, module, 0);
if (hook == 0)
{

char* em = getWin32SystemError();
printf("Win32 keyboard hook failed: [%s]\a\n", em);
free(em);
return 1;
}

printf("Win32 keyboard hooks setup. press ENTER/RETURN to quit.\a
\n");


scanf("\n");
UnhookWindowsHookEx(hook);
return 0;
}


/* KeyConverterGlobalHook.h */
#ifndef _KEY_CONVERTER_GLOBAL_HOOK_H_
#define _KEY_CONVERTER_GLOBAL_HOOK_H_

#include <windows.h>

LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam);

#endif


/* KeyConverterGlobalHook.c */
/* gcc KeyConverterGlobalHook.c -o KeyConverterGlobalHook.dll -O0 -
shared
*/
#include "KeyConverterGlobalHook.h"
#include <stdio.h>

LRESULT CALLBACK HookProco(int nCode, WPARAM wParam, LPARAM lParam)
{
FILE* ipc;
/*TODO;*/
ipc = fopen("C:/hi.bin", "ab");/* file is never created*/
fwrite("???", sizeof(char), 4, ipc);
fflush(ipc);
fclose(ipc);
return CallNextHookEx(0, nCode, wParam, lParam);
}

tyra...@gmail.com

unread,
Jan 28, 2008, 4:01:44 PM1/28/08
to
I just noticed that the function name is different in
KeyConverterGlobalHook.h
HookProc should be HookProco as it is in KeyConverterGlobalHook.c

This should not matter as the header file is of no use in this type of
program (either way I corrected that just now and I still get the same
problems).

David Jones

unread,
Jan 28, 2008, 9:21:34 PM1/28/08
to
(Sorry if this is a repost, but my ISP threw an error on my previous
post.)
<tyra...@gmail.com> wrote...

> No errors are reported with my code, yet whenever I go to another
> program (like notepad) and type any key, it stalls.
>
> I just need to know that this code in principle should not cause any
> significant problems, and any guesses as to what may be causing it.

This code works for me (and I've verified the hook gets called by
inserting a MessageBox(MB_OK) call before CallNextHookEx).

dll:

#include <windows.h>

extern "C"


LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)

{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}

app:

#include <windows.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
HMODULE module = LoadLibrary("hookdll");
if (module != NULL)
{
HOOKPROC proc = (HOOKPROC)GetProcAddress(module, "HookProc");
if (proc != NULL)
{
HHOOK hook = SetWindowsHookEx(WH_KEYBOARD, proc, module, 0);
if (hook)
{
scanf("\n");
UnhookWindowsHookEx(hook);
}
}
}

return GetLastError();
}

I can't think of anything that would cause the problems you're seeing.
Everything I can think of would also cause your initial LoadLibrary to
fail. Sorry.

I'd check the dependencies on your DLL using Dependency Viewer just to
be sure there's nothing weird. If that's all that's in the DLL, the
most you should have is USER32 and possibly KERNEL32.

David

David Jones

unread,
Jan 29, 2008, 7:53:37 AM1/29/08
to
<tyra...@gmail.com> wrote...

> > How is the value of hook getting transferred from the executable to the
> > DLL? Even if they share a common header, it would be two different
> > variables since it is in two different modules.
>
> Right I was just randomly trying different arrangements of variable
> placement until I learned that even if there is only one copy of the
> dll module loaded into memory each program will have it's own copy of
> the dll's global variables. However as I stated earlier that is not a
> concern for me as that parameter is ignored by the win32 api's.

You are correct. Old habits die hard -- at one point, that parameter
meant something, and older versions of the MSDN documentation didn't say
it was ignored. I think we're grasping at straws since your code is so
simple it seems like it should work.

Since it affects other applications, it's almost certainly something
caused by injecting that DLL into other running processes, but just
calling CallNextHookEx is about the safest thing you can do.

You might try posting a link to a binary form of your DLL instead of
source code. (But where you're only calling CallNextHookEx, not with
the file I/O.) That way we can see what your environment is doing to
break what should be a simple function call.

Also, I've uploaded the binary I compiled at:

http://www.tadmas.com/hookdll.dll

It calls MessageBeep(MB_OK) and then CallNextHookEx. If you switch your
calls to LoadLibrary/GetProcAddress to use my version and everything
works, then at least you know the problem is in the DLL.

HTH,

David

Sam of California

unread,
Jan 30, 2008, 3:42:43 AM1/30/08
to
<tyra...@gmail.com> wrote in message
news:b1fba5cd-0ec3-46c5...@l1g2000hsa.googlegroups.com...
>
> scanf("\n");

That seems to be a problem, but I don't know why. I think that the crash
occurs here, but not in other applications. I do get a crash when I press
enter. If I don't use scanf and use Sleep instead, there is no crash and the
hook works (after making the following corrections).

> LRESULT CALLBACK HookProco(int nCode, WPARAM wParam, LPARAM lParam)

You don't export the function so I really don't understand how this could
work. The linker should not create a DLL since there are no exported
functions.

> ipc = fopen("C:/hi.bin", "ab");/* file is never created*/

The filename you have will certainly not work. Change "C:/hi.bin" to
"C:\\hi.bin". Note the backslash and that it is escaped.

David Jones

unread,
Jan 30, 2008, 8:29:17 AM1/30/08
to
Sam of California <sam...@social.rr.com_change_social_to_socal> wrote...

> <tyra...@gmail.com> wrote in message
> news:b1fba5cd-0ec3-46c5...@l1g2000hsa.googlegroups.com...
> >
> > scanf("\n");
>
> That seems to be a problem, but I don't know why. I think that the crash
> occurs here, but not in other applications. I do get a crash when I press
> enter. If I don't use scanf and use Sleep instead, there is no crash and the
> hook works (after making the following corrections).

When I tested it, I used the scanf("\n") and it didn't crash either the
hooking or hooked application.

It could be an invalid crt call -- I pretty much never use scanf -- but
that's not the issue. The most that could do is cause problems in the
application calling scanf. It's not like WH_KEYBOARD_LL: global
WH_KEYBOARD is injected.


> > LRESULT CALLBACK HookProco(int nCode, WPARAM wParam, LPARAM lParam)
>
> You don't export the function so I really don't understand how this could
> work. The linker should not create a DLL since there are no exported
> functions.

And if he didn't export the function, GetProcAddress would fail, so the
hook would never be set. Plus, you can have DLLs with no exported
functions, such as resource-only DLLs.

David

Sam of California

unread,
Feb 1, 2008, 12:20:50 PM2/1/08
to
"David Jones" <nc...@tadmas.com> wrote in message
news:MPG.220a37964...@news.suddenlink.net...

>
> The most that could do is cause problems in the
> application calling scanf.

That is what I said.

> And if he didn't export the function, GetProcAddress would fail, so the
> hook would never be set.

Exactly my point. I agree the code as posted would not work, at least not to
the extent indicated.

0 new messages