SetWindowSubclass正在泄漏用户对象

时间:2009-07-13 15:55:27

标签: vb6 subclass memory-leaks

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

我在阅读Raymond的Safer subclassing评论中删除了子类,然后销毁了窗口,但我的测试完全没有破坏它。

同样的子类API由comctl的工具提示类在内部用于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>

2 个答案:

答案 0 :(得分:2)

我认为称之为“泄密”有点夸张。是的,当调用RemoveWindowSubclass时,不会恢复用户对象,但是当您再次调用SetWindowSubclass时,也不会分配另一个用户对象。您可以重复设置和删除挂钩,并且相同的用户对象似乎在进程的整个生命周期中反复使用。

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

内部设计能否更清洁?有可能。然后,可能不是。我根本不认为这是令人担忧的原因。更值得关注的是设计的应用程序,以便可能关注。在这种情况下,可以按顺序重新考虑整体UI设计。我简直无法想象当你在一个进程中继承这么多窗口类时,每个类的额外对象可能都很重要。

答案 1 :(得分:1)

这是在VB6中进行子类化的一种不寻常的方式。你可能会有更多的运气SetWindowLong(GWL_WNDPROC) - 请参阅卡尔彼得森的this VB6 code

有趣的是,看起来Karl experimenting right now具有与您正在使用的相同的comctl32函数。编辑:是的,他是posted an article。编辑:哦,和an answer to this question:)