2009-07-13 6 views
1

J'utilise Bear pour inspecter des objets utilisateur et le nombre de WindowProc ne diminue jamais lors de RemoveWindowSubclass. Tout comme le total dans USER qui est les objets utilisateur dans le Gestionnaire des tâches.SetWindowSubclass fuit des objets utilisateur

J'ai lu le commentaire Safer subclassing de Raymond sur la suppression de la sous-classe avant de détruire la fenêtre, mais mon test est fait sans la détruire du tout.

La même API de sous-classe est utilisée en interne par la classe d'info-bulles de comctl pour les outils TTF_SUBCLASS, ce qui entraîne d'autres fuites si vous utilisez des info-bulles non coopératives.

Voici le code 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 

Si peut laisser un commentaire ce qui se passe et comment résoudre les fuites sera grande. N'importe qui d'autre être averti si vous faites un sous-classement intensif avec l'API SetWindowSubclass

acclamations,
</wqw >

Répondre

2

Je pense que l'appeler une "fuite" est un peu hyperbolique. True, l'objet utilisateur n'est pas restauré lorsque RemoveWindowSubclass est appelée, mais aucun autre n'est alloué lorsque vous appelez SetWindowSubclass à nouveau. Vous pouvez définir et supprimer le hook de manière répétée, et ce même objet utilisateur semble être réutilisé encore et encore pendant toute la durée du processus. J'ai effectué quelques autres tests qui ont été développés sur votre scénario le plus simple. Juste pour la référence d'arrière-plan, chaque instance de votre formulaire avec deux boutons de commande et aucun crochets de fenêtre consomme six objets utilisateur. L'appel de SetWindowSubclass consomme en effet un autre objet utilisateur par classe de fenêtre. C'est-à-dire, je peux charger plusieurs instances de ce formulaire, et accrocher le flux de messages pour le formulaire lui-même ainsi que les deux boutons de commande contenus, et consommer un total de deux objets utilisateur. Ceux-ci, comme vous le constatez, ne sont pas recyclés pendant toute la durée du processus.

La conception interne pourrait-elle être plus propre? Peut-être. Puis encore, peut-être pas. Je ne vois pas cela comme une source de préoccupation, du tout. Une plus grande préoccupation serait une application conçue de telle sorte que ce pourrait être concerné. Dans ce cas, un réexamen fondamental de la conception globale de l'interface utilisateur peut être nécessaire. Je ne peux tout simplement pas imaginer quand vous sous-classeriez autant de classes de fenêtres dans un seul processus que cet objet supplémentaire pour chaque classe pourrait éventuellement avoir de l'importance.

+0

Le nombre total de fenêtres sous-classées à tout moment peut ne pas être si élevé. C'est la période de quelques jours pendant laquelle les formulaires sont chargés/sous-classés/déchargés que ces fuites s'accumulent. La plupart des fuites de GDI sont comme ceci, empoisonnant lentement le processus jusqu'à ce que l'exécution de VB se plaint "ne peut pas charger le contrôle" ou "mémoire insuffisante". – wqw

+0

Essayez ce que j'ai fait. Charger, sous-classe, décharger, répéter.Vous prenez le hit sur la classe de fenêtre initiale, pas sur chaque fenêtre. Combien de classes de fenêtres envisagez-vous de sous-classer? (Vous savez ce qu'est une classe de fenêtre, n'est-ce pas?) –

+0

Cet emplacement de sous-classe filtré ne correspond pas à la classe de la fenêtre, comme vous le supposez, mais à l'adresse wndproc. Donc, si vous utilisez PushParamThunk de Matt Curland qui génère un stub d'assemblage pour sous-classer un formulaire (nouveau stub sur chaque instance de sous-classe) et quelqu'un (comme les info-bulles comctl32) utilisez SetWindowSubclass pour sous-classer le même hwnd, même si le nom de la classe ne change pas ('ThunderRT6Form') un emplacement de sous-classement est alloué parce que l'adresse wndproc ne peut être trouvée dans aucun emplacement précédent. Je suis positif sur mes observations (Bear' et accidents) mais vous aurez besoin de quelqu'un de MS pour confirmer mon explication. – wqw

1

C'est une façon inhabituelle de faire subclassing en VB6. Vous pourriez avoir plus de chance avec SetWindowLong(GWL_WNDPROC) - voir this VB6 code de Karl Peterson. Il est intéressant de noter que Karl ressemble à experimenting right now avec les mêmes fonctions que celles utilisées par comctl32. EDIT: oui, il est posted an article. EDIT: oh, et an answer to this question :)

+0

J'ai tout fait migrer vers GWL_WNDPROC mais les info-bulles de comctl utilisent le nouveau sous-groupe en interne et il fuit ... 10x pour les liens. – wqw