我在程序内挂了个线程钩子,勾取MOUSEMOVE消息,结果我发现,只要我截获这个消息,程序过几秒后绝对假死。
而我截获其他消息,如LBUTTONDOWN/UP啊,就没事。
说下我的程序流程:
窗体A自CDialog派生,A里包含一个与窗体大小相等的第三方控件,称为X
窗体B派生自A程序启动后,窗体B会弹出,因为本窗体包含一个大小与窗体一样的第三方插件X,所以,本窗体的所有鼠标操作都被X给挡住了,比如,我想处理鼠标按下窗体的消息,也被X给挡住了。
所以,我给线程挂钩,截取鼠标在第三方插件X上的任何鼠标操作,然后把消息发给窗体B,让B执行相应的操作。
因为B派生自A,所以,B的函数执行完毕后,还要调用A的函数,来执行某些操作。整个过程就是如此,下面是关键代码。
关键代码整理如下:
//钩子的勾取消息的代码如下:
LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
{
int x,y;
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lparam;
if (nCode>=0)
{
switch ( (UINT)wparam )
{
case WM_LBUTTONUP:
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
case WM_LBUTTONDOWN:
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break; ////////////////////////////////////////////////////////////
//当我把截取MOUSEMOVE消息注释掉时,程序不会假死
//但是,当我一勾引这个消息,程序运行后没几秒立刻假死
//////////////////////////////////////////////////////////////
case WM_MOUSEMOVE:
ScreenToClient(glhDisplayWnd, &(pMouseHook->pt) );
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_MOUSEMOVE, wparam, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
}
}
return CallNextHookEx(glhHook,nCode,wparam,lparam);
} class A : public CDialog
{
//省略无关代码,函数参数省略,语法没错误,只看流程
void OnLButtonDown(......)
{
//做些不会让程序假死的操作
CDialog::OnLButtonDown(....);
}
void OnMouseMove(.....)
{
//做些不会让程序假死的操作
CDialog::OnMouseMove(....);
}
void OnSizing(....)
{
//做些不会让程序假死的操作
CDialog::OnSizing(....);
}
}
class B: public A
{
//省略无关代码
BOOL OnInitDialog()
{
//挂起线程内钩子,勾鼠标消息
}
LRESULT OnDestroy(WPARAM wParam,LPARAM lParam)
{
//卸载钩子
}
void OnLButtonDown(......)
{
//做些不会让程序假死的操作
A::OnLButtonDown(....); //执行父类的消息处理函数
}
void OnLButtonUp(......)
{
//做些不会让程序假死的操作
A::OnLButtonUp(....);
}
BOOL PreTranslateMessage(MSG* pMsg)
{ switch (pMsg->message)
{
case WM_MOUSELEAVE:
//做点计算
break; case WM_MOUSEHOVER:
//
break;
case WM_MOUSEMOVE:
//这里加了点代码,处理MOUSEMOVE时,在本窗体内要做的事情
//然后
//再产生以上两个消息
TRACKMOUSEEVENT trmouse;
trmouse.cbSize = sizeof(TRACKMOUSEEVENT);
trmouse.dwFlags = TME_LEAVE | TME_HOVER;
trmouse.dwHoverTime = 2000;
trmouse.hwndTrack = pMsg->hwnd;
if(!_TrackMouseEvent(&trmouse))
return FALSE; break; }
return CDialog::PreTranslateMessage(pMsg);
}}
而我截获其他消息,如LBUTTONDOWN/UP啊,就没事。
说下我的程序流程:
窗体A自CDialog派生,A里包含一个与窗体大小相等的第三方控件,称为X
窗体B派生自A程序启动后,窗体B会弹出,因为本窗体包含一个大小与窗体一样的第三方插件X,所以,本窗体的所有鼠标操作都被X给挡住了,比如,我想处理鼠标按下窗体的消息,也被X给挡住了。
所以,我给线程挂钩,截取鼠标在第三方插件X上的任何鼠标操作,然后把消息发给窗体B,让B执行相应的操作。
因为B派生自A,所以,B的函数执行完毕后,还要调用A的函数,来执行某些操作。整个过程就是如此,下面是关键代码。
关键代码整理如下:
//钩子的勾取消息的代码如下:
LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
{
int x,y;
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lparam;
if (nCode>=0)
{
switch ( (UINT)wparam )
{
case WM_LBUTTONUP:
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_LBUTTONUP, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
case WM_LBUTTONDOWN:
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_LBUTTONDOWN, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break; ////////////////////////////////////////////////////////////
//当我把截取MOUSEMOVE消息注释掉时,程序不会假死
//但是,当我一勾引这个消息,程序运行后没几秒立刻假死
//////////////////////////////////////////////////////////////
case WM_MOUSEMOVE:
ScreenToClient(glhDisplayWnd, &(pMouseHook->pt) );
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_MOUSEMOVE, wparam, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
}
}
return CallNextHookEx(glhHook,nCode,wparam,lparam);
} class A : public CDialog
{
//省略无关代码,函数参数省略,语法没错误,只看流程
void OnLButtonDown(......)
{
//做些不会让程序假死的操作
CDialog::OnLButtonDown(....);
}
void OnMouseMove(.....)
{
//做些不会让程序假死的操作
CDialog::OnMouseMove(....);
}
void OnSizing(....)
{
//做些不会让程序假死的操作
CDialog::OnSizing(....);
}
}
class B: public A
{
//省略无关代码
BOOL OnInitDialog()
{
//挂起线程内钩子,勾鼠标消息
}
LRESULT OnDestroy(WPARAM wParam,LPARAM lParam)
{
//卸载钩子
}
void OnLButtonDown(......)
{
//做些不会让程序假死的操作
A::OnLButtonDown(....); //执行父类的消息处理函数
}
void OnLButtonUp(......)
{
//做些不会让程序假死的操作
A::OnLButtonUp(....);
}
BOOL PreTranslateMessage(MSG* pMsg)
{ switch (pMsg->message)
{
case WM_MOUSELEAVE:
//做点计算
break; case WM_MOUSEHOVER:
//
break;
case WM_MOUSEMOVE:
//这里加了点代码,处理MOUSEMOVE时,在本窗体内要做的事情
//然后
//再产生以上两个消息
TRACKMOUSEEVENT trmouse;
trmouse.cbSize = sizeof(TRACKMOUSEEVENT);
trmouse.dwFlags = TME_LEAVE | TME_HOVER;
trmouse.dwHoverTime = 2000;
trmouse.hwndTrack = pMsg->hwnd;
if(!_TrackMouseEvent(&trmouse))
return FALSE; break; }
return CDialog::PreTranslateMessage(pMsg);
}}
发现程序就正常了,如果不注释,程序就会死我就迷糊了,我勾到一个消息,程序不会有问题,但是我给某窗体POST个消息,该窗体慢慢就死了??这是怎么回事???迷糊
PostMessage:
函数功能:该函数将一个消息放入(寄送)到与指定窗口创建的线程相联系消息队列里,不等待线程处理消息就返回。消息队列里的消息通过调用GetMessage和PeekMessage取得。函数原型:B00L PostMessage(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam);参数hWnd:其窗口程序接收消息的窗口的句柄。可取有特定含义的两个值:HWND.BROADCAST:消息被寄送到系统的所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口。消息不被寄送到子窗口。NULL:此函数的操作和调用参数dwThread设置为当前线程的标识符PostThreadMessage函数一样。Msg:指定被寄送的消息。wParam:指定附加的消息特定的信息。IParam:指定附加的消息特定的信息。返回值:如果函数调用成功,返回非零值:如果函数调用失败,返回值是零。若想获得更多的错误信息,请调用GetLastError函数。备注:需要以 HWND_BROADCAST方式通信的应用程序应当用函数 RegisterwindwosMessage来获得应用程序间通信的独特的消息。如果发送一个低于WM_USER范围的消息给异步消息函数(PostMessage.SendNotifyMessage,SendMesssgeCallback),消息参数不能包含指针。否则,操作将会失败。函数将再接收线程处理消息之前返回,发送者将在内存被使用之前释放。
-------------首先查查你传递的窗口句柄对不对,其次要检查你的消息循环的,很有可能是一直在调用你的消息,没有接受消息机制引起,多调试一下,我之前也遇到过这些问题的
究竟怎么回事呢??我不用钩子就没事。
{
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lparam;
if (nCode>=0)
{
switch ( (UINT)wparam )
{
case WM_LBUTTONUP:
PostMessage(glhDisplayWnd, WM_LBUTTONUP_U/*仅供窗体B使用的自定义消息,等于BUTTONUP*/, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
case WM_LBUTTONDOWN:
PostMessage(glhDisplayWnd, WM_LBUTTONDOWN_U/*仅供窗体B使用的自定义消息,等于BUTTONUP*/, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
}}
return CallNextHookEx(glhHook,nCode,wparam,lparam); }可是改完了,程序依然会死。
//钩子函数的实现:
LRESULT WINAPI MouseProc(int nCode,WPARAM wparam,LPARAM lparam)
{
static int n = 0;
LPMOUSEHOOKSTRUCT pMouseHook=(MOUSEHOOKSTRUCT FAR *)lparam;
if (nCode>=0)
{
switch ( (UINT)wparam )
{
case WM_LBUTTONUP:
TRACE("PostMessage M UP %d\n", n++);
PostMessage(glhDisplayWnd, WM_LBUTTONUP_U, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;
case WM_LBUTTONDOWN:
PostMessage(glhDisplayWnd, WM_LBUTTONDOWN_U, MK_LBUTTON, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break; }
}
return CallNextHookEx(glhHook,nCode,wparam,lparam);
//继续传递消息
}
这是钩子的循环,当我在第三方插件(WEBBROWSER2)上点击一个连接时,因为鼠标抬起,会收到一个WM_LBUTTONUP消息,于是,我给窗体B发送自定义的WM_LBUTTONUP_U消息结果更严重的问题出来了:我在WEBBROWSER的空白区域【双击】(注意,不是单击)时,我发现TRACE 输出的数字猛然间增加到了8000多,然后程序就不动了,那肯定不动了啊,瞬间就居然Post了近万条消息,而且在不停的发我就纳闷了,为什么会这样呢??这个WEBBROWSER真头疼
case WM_MOUSEMOVE:
ScreenToClient(glhDisplayWnd, &(pMouseHook->pt) );
PostMessage(glhDisplayWnd/*往窗体B发消息*/, WM_MOUSEMOVE, wparam, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
break;这个PostMessage把WM_MOUSEMOVE发到哪里去?反复循环获得WM_MOUSEMOVE消息造成程序死循环。
你试试自定义消息来PoseMessage,比如PostMessage(glhDisplayWnd/*往窗体B发消息*/, MY_WM_MOUSEMOVE, wparam, MAKELPARAM((pMouseHook->pt.x), (pMouseHook->pt.y)) );
虽然还是找不到原因,但先结贴了,我把钩子里发送消息的方式,由PostMessage全部改成SendMessage,问题就不会出现了,而且在也不会出现瞬间产生大量消息的问题,程序也就不会死了