C++ CallWindowProc在退出时崩溃
为了钩住C++ CallWindowProc在退出时崩溃,c++,winapi,C++,Winapi,为了钩住wndproc,我编写了wndprochook并使用SetWindowLong: wndproc=(WNDPROC)GetWindowLong(hwnd_1,GWL_WNDPROC); SetWindowLong(hwnd_1,GWL_WNDPROC,(LONG)wndprochook); 现在我必须在wndproc中执行一些操作,在函数末尾,我调用原始的wndproc: return wndproc(hwnd, uMsg, wParam, lParam); return CallW
wndproc
,我编写了wndprochook
并使用SetWindowLong
:
wndproc=(WNDPROC)GetWindowLong(hwnd_1,GWL_WNDPROC);
SetWindowLong(hwnd_1,GWL_WNDPROC,(LONG)wndprochook);
现在我必须在wndproc
中执行一些操作,在函数末尾,我调用原始的wndproc
:
return wndproc(hwnd, uMsg, wParam, lParam);
return CallWindowProc(wndproc, hwnd, uMsg, wParam, lParam);
它失败了,但感谢上帝,我发现CallWindowProc
:
return wndproc(hwnd, uMsg, wParam, lParam);
return CallWindowProc(wndproc, hwnd, uMsg, wParam, lParam);
现在它开始工作了。所以问题1:为什么我们必须使用CallWindowProc
?简单调用wndproc
时缺少什么?
钩子运行良好,但当我退出程序时,它崩溃了。当然,所有的事情都已经完成了,这次事故实际上并没有影响到任何事情。但看到撞车还是很糟糕。
因此问题2:这里可能发生了什么以及如何解决它?
很抱歉,我没有关于原始程序如何自行关闭的信息,因为我所做的只是挂接
wndproc
以捕获一些消息。因此,我只希望有足够经验的人能够提供帮助,他们以前遇到过类似的情况。来自CallWindowProc
的文档:
return wndproc(hwnd, uMsg, wParam, lParam);
return CallWindowProc(wndproc, hwnd, uMsg, wParam, lParam);
“如果此值是通过调用GetWindowLong
函数获得的,并且nIndex
参数设置为GWL\u WNDPROC
或DWL\u DLGPROC
,则它实际上是窗口或对话框过程的地址,或者一个仅对CallWindowProc
有意义的特殊内部值。”
您不能调用“特殊内部值”,除非执行与CallWindowProc
相同的操作,最简单的方法是调用CallWindowProc
顺便说一句,看看
SetWindowSubclass
,它可能会让您轻松一些。来自CallWindowProc
的文档:
return wndproc(hwnd, uMsg, wParam, lParam);
return CallWindowProc(wndproc, hwnd, uMsg, wParam, lParam);
“如果此值是通过调用GetWindowLong
函数获得的,并且nIndex
参数设置为GWL\u WNDPROC
或DWL\u DLGPROC
,则它实际上是窗口或对话框过程的地址,或者一个仅对CallWindowProc
有意义的特殊内部值。”
您不能调用“特殊内部值”,除非执行与CallWindowProc
相同的操作,最简单的方法是调用CallWindowProc
顺便说一句,看看SetWindowSubclass
,它可能会让您轻松一些。关于问题2:
从对另一个答案的评论中,听起来您的子类wndprochook位于注入到进程中的DLL中。如果是这种情况,那么在退出期间,您的DLL可能会被卸载,而窗口仍有消息等待处理。因此窗口的类仍然指向wndproc,但该代码被卸载,因此它会崩溃
最安全的做法可能是在关闭之前还原原始wndproc。例如,当您的子类看到WM_DESTROY或WM_NCDESTROY时,您基本上颠倒了对窗口进行子类化时所执行的步骤:在使用该消息执行CallWindowProc之前,还原window类中的原始wndproc字段。您的代码将不再被调用,即使该窗口还会有几条消息出现。关于问题2:
从对另一个答案的评论中,听起来您的子类wndprochook位于注入到进程中的DLL中。如果是这种情况,那么在退出期间,您的DLL可能会被卸载,而窗口仍有消息等待处理。因此窗口的类仍然指向wndproc,但该代码被卸载,因此它会崩溃
最安全的做法可能是在关闭之前还原原始wndproc。例如,当您的子类看到WM_DESTROY或WM_NCDESTROY时,您基本上颠倒了对窗口进行子类化时所执行的步骤:在使用该消息执行CallWindowProc之前,还原window类中的原始wndproc字段。您的代码将不再被调用,即使该窗口中还有几条消息。谢谢阿德里安·麦卡锡
Private Function WndProc(ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case MSG
Case WM_CUT, WM_PASTE, WM_CLEAR
WndProc= 1
Case WM_DESTROY, WM_NCDESTROY
Call UnHookRKey(hWnd)
Case Else
WndProc= CallWindowProc(lngPrevWndProc, hWnd, MSG, wParam, lParam)
End Select
结束功能感谢阿德里安·麦卡锡
Private Function WndProc(ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case MSG
Case WM_CUT, WM_PASTE, WM_CLEAR
WndProc= 1
Case WM_DESTROY, WM_NCDESTROY
Call UnHookRKey(hWnd)
Case Else
WndProc= CallWindowProc(lngPrevWndProc, hWnd, MSG, wParam, lParam)
End Select
结束函数wow!这真的解释了…你能给出问题2的一些答案吗?问题2:尝试通过调试器运行它,看看它在哪里中断。在最坏的情况下,将所有内容都放在Try/catch中。@fritzone好吧,问题是我无法通过调试器运行目标程序…我所做的只是在它开始时插入一个dll。wow!t问题2:试着通过调试器运行它,看看它在哪里坏了。在最坏的情况下,把所有的东西都放在一个Try/catch中。@fritzone好吧,问题是我不能通过调试器运行目标程序…我所做的就是在它开始时注入一个dll。我不确定。看到了吗ms表示dll是在目标exe模块之后卸载的。此外,windows肯定应该在实例之前卸载。我说的对吗?但我认为你的回答仍然是值得的,虽然有时可能会分离dll,并且应该尽可能保持所有内容的干净。我不确定。似乎dll是在后面卸载的呃目标exe模块。另外,windows肯定应该在实例之前卸载。我说的对吗?但是我认为你的答案仍然是值得的,也许有时候dll可以分离,应该尽可能保持一切干净。