Click to See Complete Forum and Search --> : SetWindowsHookEx stop receivings notifications after focus lost


macabre13
January 26th, 2009, 04:17 PM
Good evening :)

I've search a lot of forums but did not found any answer to my question. So here I post it.

I'm trying to set hook to keyboard to receive all multimedia keys notification, for altering they default behavior or simply disable them. But I've run into some problem.

In my .exe file I call functions from .dll which simply sets the hook with this code

SetWindowsHookEx( WH_SHELL, ShellProc, gModule, 0 );

Then goes the handling like this

LRESULT CALLBACK ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0 )
{
switch( wParam )
{
// here I would like to handle WH_SHELL -> HSHELL_APPCOMMAND -> ie. APPCOMMAND_LAUNCH_APP2
}
} // if
return CallNextHookEx (gHookProc, nCode, wParam, lParam);
}


Everything works correctly to the moment o losing the focus, after that my application simply stops receiving the notifications. When setting the focus back to my app it start working again.
Do I need to set up sth more? Switch sth in the system? Disable sth?

I use the m$ way to link the .exe with .dll with dllimport/dllexport. No dynamic load of .dll.
My system is Vista64. I don't have any drivers for my keyboard I use the ones that comes with vista.

Please help.
J.



//EDIT: syntax error fix

Igor Vartanov
January 26th, 2009, 05:45 PM
Are you sure your code is correct? I can't see the closing brace for if statement.

macabre13
January 27th, 2009, 06:58 AM
Are you sure your code is correct? I can't see the closing brace for if statement.

Are you sure that yours answer help me somehow?

Maybe it is a mistake when ctrl+c/v but like I said it works when windows has the focus. So looks like I compiled my code before and simply paste it (with syntax error not logical) to show how am I implementing the code. And asking for solution.

/m13

Codeplug
January 27th, 2009, 08:24 AM
Perhaps gModule is NULL - or you system is running a mixture of 32bit and 64bit apps. If your hook DLL is 64bit, it will only hook other 64bit apps.

gg

macabre13
January 27th, 2009, 12:59 PM
Perhaps gModule is NULL - or you system is running a mixture of 32bit and 64bit apps. If your hook DLL is 64bit, it will only hook other 64bit apps.

gg

Hi thanks for reply.
Is there a way to hook both 32 and 64 bit? Should I implement and call SetWindowsHook from 32 and 64 bit build dll?

gModule is taken from dllMain whe .dll is being loaded. And after I check it, look likes there is proper value.

Or maybe where to look to get information how window do manage the input of multimedia keys?

Thanks!
/m13

Codeplug
January 27th, 2009, 01:22 PM
>> Should I implement and call SetWindowsHook from 32 and 64 bit build dll?
According to MSDN (http://msdn.microsoft.com/en-us/library/ms644990(VS.85).aspx), yes. And give them different names.

Don't know about MM keys...

gg

Igor Vartanov
January 27th, 2009, 02:56 PM
Are you sure that yours answer help me somehow? Now I doubt. Believe me, I never ask just for asking. Typically this kind of question makes people be more accurate in quoting and finally prevents from suffering from silly mistakes and misguiding answers. Definitely not your case.

Maybe it is a mistake when ctrl+c/v but like I said it works when windows has the focus. So looks like I compiled my code before and simply paste it (with syntax error not logical) to show how am I implementing the code. And asking for solution.

/m13Maybe. Sorry, really sorry for pointing this once again, but this only showed your code like hardly compilable, nothing more than that.

Is there a way to hook both 32 and 64 bit? Should I implement and call SetWindowsHook from 32 and 64 bit build dll?Well, MSDN answers that unambiguously:

SetWindowsHookEx Function
Remarks

SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.

macabre13
January 28th, 2009, 02:42 AM
So I did some test and:
On win xp32 with 32bit .dll my application works in 50%:
I'm able to set hook, get the message and prevent other application from receiving it. But after loosing focus my application also stops receiving the messages. So then nothing happens.


// shellhook.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"
#include "shellhook.h"
#include <tchar.h>

HINSTANCE gModule;
HHOOK gHookProc = NULL;
HWND gWindow;


BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
gModule = hModule;
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}


SHELLHOOK_API DWORD registerWindow( HWND _inHwnd )
{
DWORD dwErrId = 0;
gHookProc = SetWindowsHookEx( WH_SHELL, ShellProc, gModule, 0 );
if( NULL == gHookProc )
{
dwErrId = GetLastError( );
TCHAR errBuf[255];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, dwErrId, 0, errBuf, 255, 0 );
SetWindowText( _inHwnd, errBuf );
}
else
{
gWindow = _inHwnd;
}
return dwErrId;
}

SHELLHOOK_API DWORD unRegisterWindow( HWND _inHwnd )
{
if( NULL != gHookProc )
{
BOOL result = UnhookWindowsHookEx( gHookProc );
DWORD dwErrId = GetLastError( );
if( FALSE == result )
{
TCHAR errBuf[255];
FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, 0, dwErrId, 0, errBuf, 255, 0 );
SetWindowText( _inHwnd, errBuf );
}
else
{
gWindow = NULL;
gHookProc = NULL;
}
return dwErrId;
}
return 0;
}

LRESULT CALLBACK ShellProc(int nCode, WPARAM wParam, LPARAM lParam)
{

if (HSHELL_APPCOMMAND == nCode )
{
switch( GET_APPCOMMAND_LPARAM(lParam) )
{
case APPCOMMAND_VOLUME_MUTE:
SetWindowText( gWindow, _T("APPCOMMAND_VOLUME_MUTE"));
break;
// similar for other cases
}
return 1;
}
return CallNextHookEx (gHookProc, nCode, wParam, lParam);
}


Does the code looks ok? I mean the hooking.


@Igor: no hard feelings ;)

Thanks!
/m13

Codeplug
January 28th, 2009, 07:35 AM
>> my application also stops receiving the messages
Probably because gWindow is NULL. A global/system hook means that your DLL is loaded into the address space of other processes. You will have to use some sort of IPC for your DLL to communicate with the DLL instance in the process that called registerWindow().

gg

Igor Vartanov
January 28th, 2009, 08:37 AM
Try this:
#pragma comment(linker, "/section:HOOKDAT,RWS")
#pragma data_seg( "HOOKDAT" )
HWND gWindow = NULL; // !! must be initialized !!
#pragma data_seg()


@Igor: no hard feelingsSure.

macabre13
January 29th, 2009, 02:33 AM
Ok.
Now it works with this #pragma's. I don't know how and why this works. But I will investigate this. Any way thanks a lot.

Igor Vartanov
January 29th, 2009, 03:13 AM
With these code lines your dll obtains a very special section HOOKDAT that is shared among all the dll instances in all processes that did load it. While loading dll a loader never allocates process-specific memory pages for shared sections but maps already existing ones (if any).

Your hook runner loads dll and initializes the section variable. After installing hook the dll emerges in victim process - and has the gWindow variable already initialized with the valid window handle. Exactly this point was missed in your original design - when your dll got injected to victim, gWindow had just a garbage in it.

macabre13
January 29th, 2009, 07:13 AM
The problem was that I was unable to understand why some other loads my .dll.
But I have think it over and now I do understand this way:

*) I register my hookProc in system and let it run.
*) someone pushes the MULTIMEDIA_BUTTON_X
*) sytem handle it and send the message through the hooks chain
*) my .dll is being loaded and hookProc called with proper MULTIMEDIA_BUTTON_X value
*) calling/not calling CallNextHookEx(...)
*) .dll is unloaded ?
End of processing the message.

Am I right?

/m13

Igor Vartanov
January 29th, 2009, 08:09 AM
Afraid not (but I'm not sure).

After installing a global hook a dll is loaded into every process that comply with hook specifics (immediately or at first event). And it will be unloaded only after unhook is called. BTW, Richter's Programming Applications... has (as far as I remember) a good chapter about dll injection you may refer to.

And you easily can do some logging in DllMain and see the process flow.

macabre13
January 29th, 2009, 01:20 PM
OK. I will look for that book. Thanks!

/m13

YvesHenri
September 11th, 2011, 03:25 PM
Hello everyone,
I know this tread is 2 years old and I deeply hope you guys are still around!!!
Its been almost 6 months of research since I started looking for a solution to my problem and after this time I finally found something that is really close to my problem.
Instead of a WM_SHELL hook, Im trying to set up a keyboard and mouse hook. Here we go...
The following code works untill it loses the focus, just like macabre13 has mentioned, so I made what Igor Vartanov said:

#pragma data_seg("HENRIHOOK")
HWND server = NULL;
#pragma data_seg()
But still, the same old problem. Here is the .cpp file [1]: http://pastebin.com/xnvKeAdZ

The only way I got it to work, was putting a FindWindow in the DLL_PROCESS_ATTACH, however, it will not work properly if the user opens more than 1 instance of my program. Example: Only 1 window will receive both messages, from the program 1 and program 2, because FindWindow gets the handle of the first window found from the given params.
Thats when I had the idea to make a function that retrieves the HWND of the target dll caller window but then it leads me to the "focus lost" problem. Here is the .cpp file [2]: http://pastebin.com/5VmeXUMC

NOTES: When I say it does not work, thats because the onHook is not being called somewhy. I realized this debugging, using MessageBox's, GetLastError's and such.
I am using Borland C++ Builder with Windows 7 professional.
Ignore any sintaxe error.
I have used ChangeWindowMessageFilterEx to allow my application to receive the messages from my dll.
Thanks for answering.
Henri

Igor Vartanov
September 12th, 2011, 02:05 AM
Compare the two:
1. Your real code on pastebin
#pragma data_seg( "HENRIHOOK" )
HWND server; // Window to receive the dll messages
#pragma data_seg()
2. "...what Igor Vartanov said:"
#pragma data_seg("HENRIHOOK")
HWND server = NULL;
#pragma data_seg()See any difference?