Link to home
Start Free TrialLog in
Avatar of toannds
toannds

asked on

System-wide hook works well in Win16 but doesn't work in Win32

Hi,

I have a system-wide hook function in DLL (Win16-based). That function sends all WM_CHAR messages to the main window of my .EXE program (Win16-based too). It works well. It sends WM_CHAR whenever I type in any application.

Yesterday, I want it supports taskbar icon notification so I change my project target (both .DLL and .EXE) to Win32 and they didn't work as before. The hook function didn't receive message when my window lost focus. In another word, it seems that hook associates only to one task (my .EXE).

For simple, I change my system-wide hook function to:
//------------------------------------------------------------------------------
LRESULT CALLBACK __export HookProc( int nCode, WPARAM Param, LPARAM lParam )
   {
            if ( nCode >= 0 ){
                  msg = * ( MSG far * ) lParam;
                  if( ((MSG far *)lParam)->message == WM_CHAR )
                        MessageBox( 0, "WM_CHAR", "Receive", MB_OK );
            }

            return CallNextHookEx( hhook, nCode, wParam, lParam);
      }

but I couldn't receive any message box when I type in other application.

Please help me. Thanks.

I have only 30 points and many questions now, please understand me! :-)
Avatar of toannds
toannds

ASKER

Edited text of question
Avatar of toannds

ASKER

Edited text of question
Do you use SetWindowsHook ? If it`s true just call SetWindowsHookEx instead.
set  DWORD  dwThreadID parameter to the 0 to set system wide hook.

Avatar of toannds

ASKER

I already used
HHOOK SetWindowsHookEx(idHook, hkprc, hinst, htask) in my program with htask = 0.

I didn't tell you another strange:

The Win32.hlp said that we don't need to use MakeProcInstance in Win32 version, we can pass directly function address to hkprc.
But if I do what it said, SetWindowsHookEx return NULL (an error) and of course, I don't receive any message at all. By the way, can you show me which function I can use to get error in this case?

GetLastError
toannds, a systemwide hook in win32 MUST reside in a DLL.
Avatar of toannds

ASKER

That's what I did: my system-wide hook resides in my DLL, it posts message to my main window.
OK, we have progress...  :-)
I have answered several hook-related questions in the past.  Here are URLs to two of them.  Please read the whole discussion (including the comments) and look at the sample code.
    https://www.experts-exchange.com/Q.10063288 (5 points)
    https://www.experts-exchange.com/Q.10069661 (4 points)

Avatar of toannds

ASKER

My already used SetWindowHooksEx in my DLL.
Avatar of toannds

ASKER

I'm so sorry. I wasn't intend to post previous message. That was a mistake. I'm reading alexo's answers in the past...
Avatar of toannds

ASKER

alexo, thank you for your answers (and I lost 9 points :-) ). Now I know hhook must be the shared data for difference tasks. I use Borland C++ 4.5 so there're some differences from your answers. My DLL project includes 3 files:

sysdata.cpp
syshook.cpp
syshook.def

The sysdata.cpp contains variables in shared data segment.
The syshook.cpp set up system-wide hook and contains hook proc.
//--------------------------------------------------------------
// sysdata.cpp
// All variables in this file are in another shared data segment besides the default DLL segment.
//--------------------------------------------------------------
#pragma option -zRSHAREDATA     //   Sets the name of the initialized data segment.
#pragma option -zSSHAREGROUP      // Sets the name of the initialized data segment group.
#pragma option -zTSHARECLASS      // Sets the name of the initialized data segment class.

#include <windows.h>

HHOOK hhook = 0;
HWND __export hwndHookReport = 0;
UINT __export wm_hookreport = 0;
MSG __export msg = {0};
//--------------------------------------------------------------
// syshook.cpp
//--------------------------------------------------------------
#include <windows.h>

HINSTANCE hInstance;
// these variables are in the shared segment
extern HHOOK hhook;
extern HWND hwndHookReport;
extern UINT wm_hookreport;
//------------------------------------------------------------------------------
LRESULT CALLBACK __export HookProc( int nCode, WPARAM Param, LPARAM lParam )
    {
        if ( nCode >= 0 ){
             if( ((MSG far *)lParam)->message == WM_CHAR )
                  MessageBox( 0, "WM_CHAR", "Receive", MB_OK );
        }
        return CallNextHookEx( hhook, nCode, wParam, lParam);
    }
//------------------------------------------------------------------------------
int far __export InstallSystemHook( HWND hwnd, UINT wm_report, int idHook )
//
//    hwnd: The window that receive wm_report every time HookProc get a message
//
    {
        FARPROC lpFunc;

        hwndHookReport = hwnd;
        wm_hookreport = wm_report;
        lpFunc = MakeProcInstance( (FARPROC) HookProc, hInstance );
        hhook = SetWindowsHookEx( idHook, (HOOKPROC) lpFunc, hInstance, 0 );
        return (int) hhook;
    }
//------------------------------------------------------------------------------
int far __export UninstallSystemHook()
    {
        return UnhookWindowsHookEx( hhook );
    }
//------------------------------------------------------------------------------
int CALLBACK LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeap, LPSTR lpszCmdLine )
    {
        hInstance = hinst;
        return 1;
    }
//--------------------------------------------------------------
// syshook.dll
//--------------------------------------------------------------
LIBRARY            SYSHOOK
DATA            MULTIPLE NONSHARED
SEGMENTS      SHAREDATA CLASS 'SHARECLASS' SHARED
//--------------------------------------------------------------

This .DLL is used only by one .EXE at a time. After sharing hhook and some other variables I couldn't resolve anything. You see: I write the line MessageBox(..) immediately after HookProc recieves WM_CHAR but the message box is showed only when the main window of my .EXE (that uses DLL) yields focus. It's likely not a system-wide hook manner but thread hook although the last parameter of SetWIndowsHookEx is NULL.

Ok, I'll try more research...

Avatar of toannds

ASKER

Alexo,

Thank you very much. I change to VC++ 5 and work well. However I need to change your code. I couldn't understand why I need to export functions & definition of share data section in .DEF, otherwise (use dllexport at function prototype) my hook function didn't work! Do you have any idea?
I want to give you points, please post your answer instead of comment :-) ...

ASKER CERTIFIED SOLUTION
Avatar of alexo
alexo
Flag of Antarctica image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of toannds

ASKER

Alexo, you're right! Now my DLL catch any WM_CHAR.
I want to ask you more :-)

I declare a variable of MSG type in shared section and export it in EXPORTS section of .DEF of my .DLL. Every time when my hook function receives a message it copies message to this shared variable and informs my .EXE by SendMessage(). My .EXE receive message and check the share variable. However my .EXE always receives correct wParam, lParam but not *(MSG far *)lParam.




Avatar of toannds

ASKER

Alexo, you're right! Now my DLL catch any WM_CHAR.
I want to ask you more :-)

I declare a variable of MSG type in shared section and export it in EXPORTS section of .DEF of my .DLL. Every time when my hook function receives a message it copies message to this shared variable and informs my .EXE by SendMessage(). My .EXE receive message and check the share variable. However my .EXE always receives correct wParam, lParam but not *(MSG far *)lParam.




>> my .EXE always receives correct wParam, lParam but not *(MSG far *)lParam.
Huh???