Sign in to follow this  
LlamaFood

Hook Proc

Recommended Posts

I made a global hook and to get the information, I'm writing to a file. Here's the proc function, contained in the DLL:
extern "C" __declspec(dllexport) LRESULT __cdecl KBHkPrc(int code,WPARAM wParam,LPARAM lParam)  {
	ofstream file("C:\\hooktest.txt",std::ios::out|std::ios::app);
	if(!(code < 0))  {
		file << code << "_" << wParam << "_" << lParam << "_\n";
	}
	file.close();
	return CallNextHookEx(0,code,wParam,lParam);
}
But for some reason, whenever I run the app, type something, nothing gets written in the text file. I run the app again, and I get this (in the file): 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ 0_0_1309964_ It's like the hook is messed up or something. No matter what I type in either instance of the program, it always shows this... It's confusing.

Share this post


Link to post
Share on other sites
Hmm... how am I supposed to return the HHOOK when the proc function is in a DLL, as I'm trying to make a global hook? Anyway, here's from my WM_CREATE message:
HOOKPROC KBhkprc; 
static HINSTANCE DLL;
DLL=LoadLibrary((LPCTSTR)("c:\\hook.dll"));
KBhkprc=(HOOKPROC)GetProcAddress(DLL,"KBHkPrc");
kbhook=SetWindowsHookEx(WH_SYSMSGFILTER,KBhkprc,DLL,0);


EDIT:: Actually, from MSDN:
"hhk
Ignored."
So if it's "Ignored" then why do I need to put anything?

Share this post


Link to post
Share on other sites
Older entries for CallNextHookEx say:

hhk
[in] Handle to the current hook. An application receives this handle as a result of a previous call to the SetWindowsHookEx function.


To make the HHOOK variable accessible, put it in the shared data segment. MSVC will only store initialized variables in a data_seg, so set the HHOOK variable to NULL.

Is there a reason why you declare KBHkPrc as __cdecl? The docs that I have for KeyboardProc note that is uses the CALLBACK calling convention, aka __stdcall.

Share this post


Link to post
Share on other sites
i am not totally sure, but when installing a global hook, i believe that the dll is not injected in all the processes at hook instalation time, but when the target app is activated.

after setting the hook, you could try to send an activation message to the target app in order to force the dll injection without delay.

Share this post


Link to post
Share on other sites
If I declare the proc as CALLBACK then GetProcAddress Returns NULL; if the newer docs say its not needed, then doesn't that mean that I can leave it out?

EDIT:: So to make it work should I put init and release functions in the dll to handle the hook?

Share this post


Link to post
Share on other sites
Quote:
Original post by LlamaFood
If I declare the proc as CALLBACK then GetProcAddress Returns NULL;

That's surprising. GetProcAddress returns FARPROC. FARPROC for 32 bit x86 is defined thusly

typedef int (FAR WINAPI *FARPROC)();

FAR evaluates to the empty string. WINAPI evaluates to stdcall. int is the same as LRESULT.

It's easier to cast the call to GetProcAddress as a void pointer anyway.

pfnVariable = (void*)GetProcAddress(dll, "TargetFunkName");

If you're getting NULL, then perhaps there is a problem with exporting the function. Perhaps the 'extern C' should preface the prototype. Check out the dll with depends (dependencywalker.com). The problem might have to do with name mangling.

Quote:
Original post by LlamaFood
if the newer docs say its not needed, then doesn't that mean that I can leave it out?

Do you mean the hook parameter? If you want the hook to work on older operating systems - W98, W2K - then you shouldn't leave it out. If you only care about WXP,W2003, then leave it out. Then again, the newers docs might be wrong.

Quote:
Original post by LlamaFood
EDIT:: So to make it work should I put init and release functions in the dll to handle the hook?


It depends on how you want to architect the dll. In the code that I use as a pattern, the calls to SetWindowsHookEx and UnhookWindowsHookEx, are wrapped in export functions in the dll.

Share this post


Link to post
Share on other sites
Ok another question - when I put the create and release functions in the dll to be called by my program, will the dll be released by other programs (MSDN said something to the effect that it isn't normally)? If not, then is there any way I can get the other programs to release it other than closing them?


EDIT:: Also, during the call to the SetWindowsEx function inside the dll, MSDN says that instead of using the LoadLibrary function to get the DLL handle, the DLL can supply it. How do I get the handle to a DLL in a function in that DLL? And if I use the second option of global hooking as described here:
Quote:

An alternative method for installing a global hook procedure is to provide an installation function in the DLL, along with the hook procedure. With this method, the installing application does not need the handle to the DLL module. By linking with the DLL, the application gains access to the installation function. The installation function can supply the DLL module handle and other details in the call to SetWindowsHookEx. The DLL can also contain a function that releases the global hook procedure; the application can call this hook-releasing function when terminating.

then how am I to call the create and release functions from the EXE without LoadLibrary? Static link?

[Edited by - LlamaFood on November 28, 2004 12:38:31 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by LlamaFood
Ok another question - when I put the create and release functions in the dll to be called by my program, will the dll be released by other programs (MSDN said something to the effect that it isn't normally)? If not, then is there any way I can get the other programs to release it other than closing them?

EDIT:: Also, during the call to the SetWindowsEx function inside the dll, MSDN says that instead of using the LoadLibrary function to get the DLL handle, the DLL can supply it. How do I get the handle to a DLL in a function in that DLL? And if I use the second option of global hooking as described here:
Quote:

An alternative method for installing a global hook procedure is to provide an installation function in the DLL, along with the hook procedure. With this method, the installing application does not need the handle to the DLL module. By linking with the DLL, the application gains access to the installation function. The installation function can supply the DLL module handle and other details in the call to SetWindowsHookEx. The DLL can also contain a function that releases the global hook procedure; the application can call this hook-releasing function when terminating.

then how am I to call the create and release functions from the EXE without LoadLibrary? Static link?


One of the parameters to DllMain is the HMODULE for the dll. Since you know the eventual name of the dll, you can also use GetModuleHandle to obtain the HMODULE. For dll's that you know are already loaded - eg Kernel32.dll, Ntdll.dll, user32.dll - it makes more sense to use GetModuleHandle rather than LoadLibrary, because there is no need to call FreeLibrary on the handle returned by GetModuleHandle. This would also include the hook dll (self) because the code in the dll wouldn't be running if it wasn't already loaded into the address space of the process.

It's easiest to declare a global variable in the dll for the HMODULE and then assign the DllMain parameter to it.

Why microsoft wrote that overview using LoadLibrary escapes me. Maybe because they thought it would be smart to illustrate how not to approach the issue! More likely they might have thought it was a good way to lead into the unloading issue. At any rate, it's somewhat misleading.

It's ok to use LoadLibrary in the exe. The exe is "your thread", you can call FreeLibrary on the dll it when you're done with it.

The short answer to your last question is yes. They are suggesting that the exe pass the HMODULE to the create function in the dll. I haven't done it that way before. I don't think it's that big of a deal if the hook dll remains loaded into the address space of the target process - but that doesn't happen in my experience. Grab a copy of Process Explorer from sysinternals.com. It will help you track if your hook dll loads into other processes.


Share this post


Link to post
Share on other sites
Still a bit confused but thank you for your time- I'm still confused about linking the DLL to the EXE. I guess a rephrase of the question would be- what would/do you use? static or what? And when using static linking, would other apps implicitly call LoadLibrary?

Share this post


Link to post
Share on other sites
I would dynamically link the dll to the exe. That way, if for some reason the exe and the dll become separated, the exe will still run - at least long enough to issue a message that the dll can't be found. How the dll is linked to the exe shouldn't have any bearing on how other process load the dll into their address space.

Here is some C code that I put together a while back to demonstrate how to set up a GlobalMessageHook. It uses memory mapping to establish shared memory rather than a data_seg pragma. It's not written for MSVC, and it's not perfect, but I think it gets the major ideas across.

Share this post


Link to post
Share on other sites
Quote:
Original post by LlamaFood
I feel stupid. Really really stupid. I was using the wrong type of hook (via the first parameter to SetWindowsHookEx). Lots of tasty information that prevented possible bugs, though. Thx.


Don't feel too stupid, hooks aren't that easy the first time through and even later on transfering data back to the launching process can present problems. As for the rest, no problem.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this