1

我正在使用Bear来检查用户对象,并且在 RemoveWindowSubclass 上 WindowProc 计数永远不会减少。USER 中的总数也是任务管理器中的用户对象。

我阅读了 Raymond 的关于在销毁窗口之前删除子类的更安全的子类化评论,但我的测试完全没有破坏它。

comctl 的工具提示类在内部使用相同的子类化 API 用于 TTF_SUBCLASS 的工具,因此如果您使用非协作工具提示,则会发生更多泄漏。

这是VB6代码

'--- Form1.frm '
Option Explicit

Private Declare Function SetWindowSubclass Lib "comctl32" (ByVal hwnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long, ByVal dwRefData As Long) As Long
Private Declare Function DefSubclassProc Lib "comctl32" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function RemoveWindowSubclass Lib "comctl32" (ByVal hwnd As Long, ByVal pfnSubclass As Long, ByVal uIdSubclass As Long) As Long

Private Sub Command1_Click()
    Call SetWindowSubclass(hwnd, AddressOf RedirectTabPaneEditWndProc, 10, ObjPtr(Me))
End Sub

Private Sub Command2_Click()
    Call RemoveWindowSubclass(hwnd, AddressOf RedirectTabPaneEditWndProc, 10)
End Sub

Friend Function frWndProc(ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    frWndProc = DefSubclassProc(hwnd, wMsg, wParam, lParam)
End Function

'--- Module1.bas '
Option Explicit

Public Function RedirectTabPaneEditWndProc( _
            ByVal hwnd As Long, _
            ByVal wMsg As Long, _
            ByVal wParam As Long, _
            ByVal lParam As Long, _
            ByVal uIdSubclass As Long, _
            ByVal This As Form1) As Long
    #If uIdSubclass Then '--- touch args
    #End If
    RedirectTabPaneEditWndProc = This.frWndProc(hwnd, wMsg, wParam, lParam)
End Function

如果有人可以发表评论,那么发生了什么以及如何解决泄漏将会很棒。

如果您使用 SetWindowSubclass API 进行密集的子类化,其他任何人都会被警告。

干杯,
</wqw>

4

2 回答 2

2

我认为称其为“泄漏”有点夸张。确实,调用 RemoveWindowSubclass 时不会恢复用户对象,但再次调用 SetWindowSubclass 时也不会分配另一个对象。您可以反复设置和移除挂钩,并且在整个过程的生命周期中,相同的用户对象似乎被一遍又一遍地重用。

我又做了一些测试,扩展了您最简单的情况。仅作为背景参考,带有两个命令按钮且没有窗口挂钩的表单的每个实例都会消耗六个User 对象。调用 SetWindowSubclass 确实会为每个窗口类多消耗一个 User 对象。也就是说,我可以加载该表单的多个实例,并为表单本身以及包含的两个命令按钮挂钩消息流,并使用总共两个用户对象。正如您所观察到的,这些在整个过程的生命周期内都不会被回收。

内部设计可以更清洁吗?可能。再说一次,可能不是。我根本不认为这有太多值得关注的理由。更令人担忧的原因是设计的应用程序可能会引起关注。在这种情况下,可能需要对整体 UI 设计进行根本性的重新考虑。我简直无法想象什么时候你会在一个进程中子类化这么多窗口类,以至于每个类的这个额外对象可能很重要。

于 2009-07-23T17:40:29.140 回答
1

That's an unusual way to do subclassing in VB6. You might have more luck with SetWindowLong(GWL_WNDPROC) - see this VB6 code from Karl Peterson.

Interestingly, it looks like Karl is experimenting right now with the same comctl32 functions that you're using. EDIT: yes, he's posted an article. EDIT: oh, and an answer to this question :)

于 2009-07-14T09:14:27.210 回答