代码之家  ›  专栏  ›  技术社区  ›  wqw

SetWindowsSubClass正在泄漏用户对象

  •  1
  • wqw  · 技术社区  · 15 年前

    我在用 Bear 要检查用户对象,在removeWindowsSubclass上WindowProc计数永远不会减少。用户中的total也是任务管理器中的用户对象。

    我读过雷蒙德的 Safer subclassing 关于在销毁窗口之前删除子类的注释,但是我的测试完全没有销毁它。

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

    这是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 & GT;

    2 回复  |  直到 11 年前
        1
  •  2
  •   Karl E. Peterson    15 年前

    我认为称之为“泄密”有点夸张。如果为true,则在调用removeWindowsSubClass时不会还原用户对象,但在再次调用setWindowsSubClass时也不会分配另一个对象。您可以重复地设置和移除钩子,并且在流程的生命周期中,相同的用户对象似乎会被反复使用。

    我做了更多的测试,扩展了您最简单的案例场景。仅作为背景参考,具有两个命令按钮且不使用窗口挂钩的表单的每个实例 用户对象。调用setWindowsSubClass确实会消耗更多的用户对象 每个窗口类 . 也就是说,我可以加载该表单的多个实例,并为表单本身以及包含的两个命令按钮挂接消息流,并且总共使用两个用户对象。正如你所观察到的,这些物质在整个过程中不会被回收利用。

    内部设计可以更干净吗?可能。再说一遍,可能不会。我认为这根本没有什么值得关注的。更值得关注的原因是设计的应用程序 可以 关心。在这种情况下,可以对整个UI设计进行基本的重新考虑。我简直无法想象在一个进程中,什么时候您将在一个进程中子类化如此多的窗口类,以至于每个类的这个额外对象可能会很重要。

        2
  •  1
  •   Community CDub    8 年前

    这是在vb6中进行子类化的一种不寻常的方法。你可能会有更多的运气 SetWindowLong(GWL_WNDPROC) -见 this VB6 code 来自卡尔·彼得森。

    有趣的是,看起来卡尔是 experimenting right now 使用与您使用的相同的comctl32函数。编辑:是的,他是 posted an article . 编辑:哦,还有 an answer to this question :)