Solved

SetWindowsHookEx keep crashing the program that I'm hooking.

Posted on 2000-03-30
32
855 Views
Last Modified: 2013-12-03
I have no idea why this happens. Perhaps my codes is not safe...
The following is the hooking part of my hooker program..

In my MainProc:

case WM_CREATE:
if(hAver == NULL)
{
  hAver = FindWindow( "AfxFrameOrView42s", "Aver Remote Control");
}
 if(hAver == NULL)
{
  MessageBox(NULL, "Aver Remote is not up or not detected", "Error",   MB_OK);
}
             
dwThreadID = GetWindowThreadProcessId( hAver, NULL );
       
hook = SetWindowsHookEx( WH_CALLWNDPROC ,
                                 (HOOKPROC)CallWndProc,       
                                 hInst,      
                                 dwThreadID       
                              );
if(hook==NULL)
{
   MessageBox(NULL, "Something is wrong with SetWindowsHookEx",    "Error", MB_OK);
}
break;


And this in the CallBack Procedure of the hook...
LRESULT CALLBACK CallWndProc( int nCode, WPARAM wParam,
LPARAM lParam )
{      
    if (nCode==HC_ACTION)
    {
       if(((CWPSTRUCT *)lParam)->message==WM_GETTEXT)
       {
          MessageBox(NULL, "WM_GETTEXT is sent", "Alright Already", MB_OK);        }

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

I got the message box to appear , then the program that I'm hooking and my program freezes. At least I need to know how I can check where is the problem. By the way, if coincidentally, anyone who is using AVerMedia TVPhone, I'm actually trying to hook the remote control messages. I have seen someone done it to control winamp, I'm trying to do the same but to control another program. Please excuse my unprofessional codes.
0
Comment
Question by:redhat092798
  • 12
  • 11
  • 7
  • +2
32 Comments
 
LVL 15

Accepted Solution

by:
NickRepin earned 250 total points
Comment Utility
Never call MessageBox from inside the hook proc.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
It's safer to write the trace messages to the file.

When you call MessageBox() or other functions that create or use a window, your hook proc is called repeatedly and endlessly.
0
 
LVL 8

Expert Comment

by:gelbert
Comment Utility
if NULL == hAver then do forget to return( do not do GetWindowThreadProcessId() & SetWindowsHookEx() )
0
 

Author Comment

by:redhat092798
Comment Utility
NickReppin : You I should trace the messages by writing to a file ?
Can I do a SendMessage() to another program that will do something ? In this case , no new window is opened from within my hook proc.

gelbert : I don't quite understand what you are trying to say. I think you are saying  that if hAver == NULL, then I should do a follow-up NOT to do GetWindowThreadProcessId() & SetWindowsHookEx().
Is this right ?
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
"Avoid Calling SendMessage() Inside a Hook Filter Function"
http://support.microsoft.com/support/kb/articles/Q74/8/57.ASP

gelbert told about this:

if(hAver == NULL)
{
  MessageBox(NULL, "Aver Remote is not up or not detected", "Error",   MB_OK);
// BREAK must be here;
break;
}
   
0
 

Author Comment

by:redhat092798
Comment Utility
Thanks for the article link for not to use SendMessage within a hook proc . I understand that PostMessage() is ok to use from that article . I understand what gelbert meant now.

Ok, I almost got it all. One last question, you notice that I was trying to hook WM_GETTEXT message of that particular program.
How do I get what is the actual value that was sent with WM_GETTEXT message. Thats quite crucial to what I want to do. Thats all and I'll wrap this up.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
It's not clear what do you want to know.

As far as I understood your code,
some application sends WM_GETTEXT to Aver.

Do you want to know the address of the buffer to store the windows text and the buffer length passed via WM_GETTEXT message, or the window text itself?

The first details you can get

// buf is enpty so far.
char* buf=(char*)  (((CWPSTRUCT *)lParam)->lParam);

DWORD szbuf=(((CWPSTRUCT *)lParam)->wParam);

The window text you can get only if you install WH_CALLWNDPROCRET hook. With this hook, your proc will be called when the SendMessage returns, ie when the Aver filled the buffer with the window text.

(char*)  (((CWPSTRUCT *)lParam)->lParam)

will contains the window text.




0
 

Author Comment

by:redhat092798
Comment Utility
ok, I got the part ...

char* buf=(char*)  (((CWPSTRUCT *)lParam)->lParam);

                    DWORD szbuf=(((CWPSTRUCT *)lParam)->wParam);

But my problem is, actually seeing what is that value of lParam, which is the buf here.
I tried writing it to a file, CRASHED.
I tried sending to another program I wrote, CRASHED.

It seems that I can only do a PostMessage in a hook procedure. Everything else causes a crash on the program I'm hooking.
How do I know what is the value. Spy does give its value. It only says that WM_GETTEXT is send and received.
Please help out here. I'm so close to getting to my program to work as I want it. Thank you.
0
 

Author Comment

by:redhat092798
Comment Utility
Adjusted points from 200 to 220
0
 

Author Comment

by:redhat092798
Comment Utility
I'm increasing the points to 220 since this question is dragging.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
Here is the sample how it has to be.
Note the the hook proc must be in a DLL.

//----------
// Main.cpp
//----------

#include <windows.h>
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>

bool setHooks(DWORD threadId);
void removeHooks();

void main(int argc,char* argv[])
{
   HWND w=FindWindow(0,"MSDN Library Visual Studio 6.0");
   if(!w) {
      cout<<"Window not found"<<endl;
      return;      
   }
   DWORD threadId=GetWindowThreadProcessId(w,0);
   if(setHooks(threadId)) {
      cout<<"Press Enter to quit"<<endl;
      _getch();
   }  
   removeHooks();
}

//----------
// Hook.dll
// MUST BE COMPILED WITH /MD OPTION!
// (multithreaded DLL).
//----------
#define STRICT
#include <windows.h>
#include <fstream.h>

// Shared data segment.
#pragma data_seg(".shared")
HHOOK hHook=0;
HHOOK hHook2=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:.shared,RWS")

HINSTANCE hDll;
ofstream f;
CRITICAL_SECTION cs; // Protects the log file for multithreaded process.

void onMessage(CWPSTRUCT& msg)
{
   EnterCriticalSection(&cs);
   f<<"WM_GETTEXT sent, szbuf="<<msg.wParam<<", buf="<<
      hex<<msg.lParam<<dec<<endl;
   LeaveCriticalSection(&cs);
}

void onMessage2(CWPRETSTRUCT& msg)
{
   EnterCriticalSection(&cs);
   f<<"WM_GETTEXT processed, szbuf="<<msg.wParam<<", buf="<<
      hex<<msg.lParam<<dec<<
      ", txt="<<LPCSTR(msg.lParam)<<endl;
   LeaveCriticalSection(&cs);
}

LRESULT CALLBACK hookProc(int code,WPARAM wParam,LPARAM lParam)
{
   if(code==HC_ACTION) {
      CWPSTRUCT* msg=(CWPSTRUCT*)(lParam);
      if(msg->message==WM_GETTEXT)
         onMessage(*msg);
   }
   return CallNextHookEx(hHook,code,wParam,lParam);
}

LRESULT CALLBACK hookProc2(int code,WPARAM wParam,LPARAM lParam)
{
   if(code==HC_ACTION) {
      CWPRETSTRUCT* msg=(CWPRETSTRUCT*)(lParam);
      if(msg->message==WM_GETTEXT)
         onMessage2(*msg);
   }
   return CallNextHookEx(hHook2,code,wParam,lParam);
}

BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID)
{
   if(fdwReason==DLL_PROCESS_ATTACH) {
      hDll=hinstDLL;
      // Create different log file for each process.
      char buf[120];
      wsprintf(buf,"C:\\HOOK_%lu",GetCurrentProcessId());
      f.open(buf,ios::out | ios::app | ios::trunc);
      InitializeCriticalSection(&cs);
   }
   else if(fdwReason==DLL_PROCESS_DETACH)
      DeleteCriticalSection(&cs);
   return TRUE;
}

_declspec(dllexport) bool setHooks(DWORD threadId)
{
   if(hHook==0)
      hHook=SetWindowsHookEx(WH_CALLWNDPROC,hookProc,hDll,threadId);
   if(hHook2==0)
      hHook2=SetWindowsHookEx(WH_CALLWNDPROCRET,hookProc2,hDll,threadId);
   return hHook!=0 && hHook2!=0;
}

_declspec(dllexport) void removeHooks()
{
   if(hHook) { UnhookWindowsHookEx(hHook); hHook=0; }
   if(hHook2) { UnhookWindowsHookEx(hHook2); hHook2=0; }
}


0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
A warning:  This code will crash spectacularly if applied to a global hook because onMessage1() and onMessage2() rely on the C++ runtime library being present and initialized.
0
 

Author Comment

by:redhat092798
Comment Utility
Adjusted points from 220 to 250
0
 

Author Comment

by:redhat092798
Comment Utility
Wow, I'm studying the codes. But I think I have to increase some more points for this.
0
 

Author Comment

by:redhat092798
Comment Utility
Wow, I'm studying the codes. But I think I have to increase some more points for this.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
<<<A warning:  This code will crash spectacularly if applied to a global hook because onMessage1() and onMessage2() rely on the C++ runtime library being present and initialized>>>

NO WAY. Initialization is done by C++ runtime. Linker calls _DllMainCRTStartup which performs the initialization and then calls DllMain.

>>being present
Sorry, what does it mean? Runtime dll?
Sure, you must have runtime dll *IF* you use dynamic linking.
0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 11

Expert Comment

by:alexo
Comment Utility
Nick, my comment and your reply are totally out of phase.

The runtime library can be statically or dynamically linked but that is not the point.  The C++ RTL is linked ONLY to a program compiled by a C++ compiler.
However, a global hook will attach to ANY process.  When a hook function using C or C++ runtime library features gets invoked in the context of a VB, Delphi, assembler, etc. program - you get a crash.

As I said above, as long as you hook a thread in your process, you're fine.  Once you move to systemwide hooks or hook a thread in a process not compiled with the same brand (and probably version) of your C++ compiler, only plain API calls are safe.  (onMessage1() and onMessage2() use iostream operations)
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
Alexo, I'm not agree with you.
At least, in the case of the static linking (that's I always do). And I don't see any problem with dynamic linking so far.

Sorry, could you prove your statement?
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
Just describe at least the one problem that could be with my sample code above.
I'll pay you 200+A points for the correct answer :).
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
Dynamic linking: I'm aware that there may be the different versions of RTL, but it means that the system is not properly configured, so please don't mention this problem.
0
 

Author Comment

by:redhat092798
Comment Utility
Let me clarify somethings...(Actually I think I already know but I just wanna be sure)

1) The main.cpp and the dll is compiled separately     right ?

2) I compiled them separately. The dll compiled         perfectly.  The main.cpp has three errors. I think
    setHooks() and removeHooks() is not defined or     something. Maybe you left me to to fill up that       part myself but I thought to be  the safe side, I     better asked first.

3) I know that in the end I have to put the dll in     the same folder as the main.exe. I got that         part covered, just to reassure you I'm not so         newbie, its just that hooks is out my league.  
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
1) Yes. If you can run VC from the command line, it looks like this:

cl /LD /MD hook.cpp user32.lib kernel32.lib
cl main.cpp hook.lib user32.lib


2) You have to specify the additional library to link main.cpp with: hook.lib.
The hook.lib is auto created when you link hook.dll.

3) You can put it in the same folder, or in any system folder. Look at LoadLibrary() doc for details about paths.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
>> Alexo, I'm not agree with you.
No problem Nick, we'll just have to check which one of us is right.

>> Just describe at least the one problem that could be with my sample code above.

OK, let's make it official.

1) Compile the program + dll as presented above.

2) Substitute "MSDN Library Visual Studio 6.0" with different strings to hook the following programs:

* Any assembly program (I suggest http://grc.com/files/optout.exe)
* Any Delphy program (pick one)
* Any VB program (preferrably an old version of VB).

3) Run it and check that stuff gets written to the files.

4) email me the names of programs you used, the source and the results.

5) Allow me some time to reproduce the results on another system.

>> I'll pay you 200+A points for the correct answer :).

Ditto.  I'm even willing to raise the amount, if you wish.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
alexo,

well, I'm pretty sure that the code above will work fine as system-wide hook.

I just tested it on my NT with your assembler program, Cbuilder, VB 6, Cbuilder and VB projects running at the same time. No problems at all.

To convert my sample to the global hook, replace
  setHooks(threadId)
with
  setHooks(0).

To make the code absolutely bullet-proof, it's better to remove the following, because some programs may send NULL buffer or may handle WM_GETTEXT incorrectly:

 ", txt="<<LPCSTR(msg.lParam)<<

To compile from the command-line:

cl /LD /MD hook.cpp user32.lib kernel32.lib
cl main.cpp hook.lib user32.lib
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Nick, I'll check it out and get back to you...
0
 

Author Comment

by:redhat092798
Comment Utility
alexo, none of the links work. Thanks anyway.
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
0
 

Author Comment

by:redhat092798
Comment Utility
Is it possible that a WM_GETTEXT is not sending any value ? Because in the hook_4539827 file that the dll makes, its empty. Nothing. So I'm just wondering. Anyway, I think I have asked enough on this topic for anyone to tolerate. Thank you very much.
0
 
LVL 15

Expert Comment

by:NickRepin
Comment Utility
The hook_*** files are created anyway regardless of whether window received the WM_GETTEXT message or not.
If the file is empty, then the window had not received WM_GETTEXT message.

To see all messages:

void onMessage(CWPSTRUCT& msg)
{
   EnterCriticalSection(&cs);
   f<<"Msg="<<msg.message<<" is sent, wParam="<<msg.wParam<<", lParam="<<
      hex<<msg.lParam<<dec<<endl;
   LeaveCriticalSection(&cs);
}

void onMessage2(CWPRETSTRUCT& msg)
{
   EnterCriticalSection(&cs);
   f<<"Msg="<<msg.message<<" is processed, wParam="<<msg.wParam<<", lParam="<<      hex<<msg.lParam<<dec<<", result="<<msg.lResult<<endl;
   LeaveCriticalSection(&cs);
}

LRESULT CALLBACK hookProc(int code,WPARAM wParam,LPARAM lParam)
{
   if(code==HC_ACTION) {
      CWPSTRUCT* msg=(CWPSTRUCT*)(lParam);
      onMessage(*msg);
   }
   return CallNextHookEx(hHook,code,wParam,lParam);
}

LRESULT CALLBACK hookProc2(int code,WPARAM wParam,LPARAM lParam)
{
   if(code==HC_ACTION) {
      CWPRETSTRUCT* msg=(CWPRETSTRUCT*)(lParam);
      onMessage2(*msg);
   }
   return CallNextHookEx(hHook2,code,wParam,lParam);
}
0
 
LVL 11

Expert Comment

by:alexo
Comment Utility
Nick,
After some thought I came to the conclusion that you were right and I was confused.  There should be no problems since the DLL probably initializes the C++ RTL.

Go to http://www.experts-exchange.com/jsp/qShow.jsp?ta=winprog&qid=10323651  for your 'A'.
0
 

Expert Comment

by:rahimb
Comment Utility
Hi there,
I am trying to retrieve data from a control of class type AfxFrameOrView42s. This control is in some other application.

The tool I am using is VB. Can we do it through Sendmessage.

If anyone is aware of the solution please do let me know.

Cheers
Rahim
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

This tutorial is about how to put some of your C++ program's functionality into a standard DLL, and how to make working with the EXE and the DLL simple and seamless.   We'll be using Microsoft Visual Studio 2008 and we will cut out the noise; that i…
For a while now I'v been searching for a circular progress control, much like the one you get when first starting your Silverlight application. I found a couple that were written in WPF and there were a few written in Silverlight, but all appeared o…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now