3

我们最大的旧 VB6 应用程序之一有一些代码允许其他应用程序(包括一些 dotNET 应用程序)通过 Windows 消息将 ID 传递给它 - 然后 VB6 应用程序使用此 ID 在常规 Windows 中加载条目形式。消息挂钩在用户登录并通过身份验证后添加,并在用户注销后删除。

Public Sub HookClaimFinderCall()
    lpPrevWndProc = SetWindowLong(gHW, GWL_WNDPROC, AddressOf WindowProc)
End Sub

Public Sub UnhookClaimFinderCall()
    Dim temp As Long
    If gHW <> 0 Then temp = SetWindowLong(gHW, GWL_WNDPROC, lpPrevWndProc)
End Sub

Private Function WindowProc(ByVal hw As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    If uMsg = WM_FINDCLAIM Then
        MasterFindClaim lParam
    End If
    WindowProc = CallWindowProc(lpPrevWndProc, hw, uMsg, wParam, lParam)
End Function

但是,这有两个问题。第一个与 Visual Studio 6 相关。如果正在调试代码,并且出现错误以调出“继续结束调试帮助”对话框,则按 End 会立即退出 Visual Studio(丢失所有未保存的更改)。如果尚未激活消息挂钩,则不会发生这种情况。是什么原因造成的,除了注释掉加载钩子的代码之外,我能做些什么来阻止它?

其次,如果用户在没有正确注销的情况下(通过任何方式)退出了应用程序,那么消息挂钩会发生什么?

我希望我上面的所有条款都是正确的......

4

2 回答 2

5
  1. 如果您启动全局挂钩并尝试在 VB6 中调试,您将崩溃(或消失 VB6)。VB6 有点像模拟器,它并没有完全复制 VB6 应用程序的运行时,而挂钩是它惨遭失败的领域之一(尽管如果您了解正在发生的事情,也不能真正责怪它)。对于我们在应用程序中使用的所有全局挂钩,我们检查 VB6 是否在 IDE 模式下运行(有几种方法可以做到这一点),如果是,请不要运行全局挂钩。如果您绝对必须运行全局挂钩,请不要在调试器中停止应用程序 - 使用 debug.print 或其他方式,但不要停止应用程序,否则您将在它“消失”之前有几毫秒到几秒的时间。
  2. 尽管您应该在退出应用程序之前取消挂钩,但当消息泵命中挂钩并且发生挂钩的应用程序句柄不再存在时,忽略该挂钩是一个相当便宜的操作。现在,如果您运行该应用程序并退出数千次,它可能会建立起来,但我认为这是您最不关心的问题。
于 2009-09-08T15:40:26.020 回答
3

克里斯的回答是正确的。还有几点。

  • 严格来说,这是子类化而不是消息挂钩。
  • WindProc检测 WM_NCDESTROY 并在收到该消息时取消挂钩也是一种很好的做法。该消息意味着窗口即将被销毁 - 如果用户退出应用程序,无论他们如何执行,都应该收到它。
  • 在 Windows 2000 和更高版本中有一些 API 调用可以更轻松地管理子类化。与往常一样,Karl Peterson 在这里有一篇优秀的 VB6 代码的优秀文章。
于 2009-09-08T16:10:24.773 回答