tags:

views:

315

answers:

2

I'm using Bear to inspect user objects and the WindowProc count is never decreasing upon RemoveWindowSubclass. So does the total in USER which is the User Objects in Task Manager.

I read Raymond's Safer subclassing comment on removing subclassing before destroying the window but my test is done w/o destroying it at all.

The same subclassing API is used internally by the comctl's tooltip class for TTF_SUBCLASS'ed tools, so more leaks occur if you are using non-cooperative tooltips.

Here is the VB6 code

'--- 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

If any can leave a comment what's going on and how to resolve the leaks will be great.

Anyone else be warned if you're doing intensive subclassing with SetWindowSubclass API.

cheers,
</wqw>

+1  A: 

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 :)

MarkJ
I did migrate everything to GWL_WNDPROC but comctl tooltips are using the new subclassing internally and it is leaking... 10x for the links.
wqw
+2  A: 

I think calling this a "leak" is a bit hyperbolic. True, the user object isn't restored when RemoveWindowSubclass is called, but neither is another one allocated when you call SetWindowSubclass again. You can repeatedly set and remove the hook, and that same user object appears to be reused over and over again for the life of the process.

I did a few more tests that expanded on your simplest-case scenario. Just for background reference, each instance of your form with two command buttons and no window hooks consumes six User objects. Calling SetWindowSubclass does indeed consume one more User object per window class. That is, I can load multiple instances of that form, and hook the message stream for the form itself as well as both contained command buttons, and consume a total of two User objects. These, as you observe, are not recycled for the life of the process.

Could the internal design be cleaner? Possibly. Then again, possibly not. I don't see this as much cause for concern, at all. A greater cause for concern would be an application designed such that this might be concerning. In that case, a fundamental reconsideration of the overall UI design may be in order. I simply cannot imagine when you would be subclassing so many window classes in a single process that this extra object for each class could possibly matter.

Karl E. Peterson
The overall number of subclassed windows at any point in time may be not so high. It's the period of couple of days while forms are loaded/subclassed/unloaded that these leaks accumulate. Most of the GDI leaks are like this, slowly poisoning the process until the VB runtime complains "Can not load control" or "Out of memory".
wqw
Try what I did. Load, subclass, unload, repeat. You take the hit on the initial window class, not on each window. How many window classes do you plan to subclass? (You know what a window class is, right?)
Karl E. Peterson