2009-10-27 7 views
4

Je m'excuse d'avance; C'est une longue question. J'ai essayé de simplifier autant que je peux mais c'est encore un peu plus long que ce que je voudrais voir.VB6 Collection Supprimer Ne pas déclencher Class_Terminate

Dans certains codes hérités, nous avons une collection VB6. Cette collection ajoute des objets via la méthode .Add et les supprime via la méthode .Remove. Cependant, via le traçage, je peux voir que parfois lorsque le .Remove est appelé, il apparaît que la classe terminée pour l'objet n'est pas appelée. Mais ce n'est pas cohérent. cela n'arrive que rarement et je ne peux pas isoler les circonstances dans lesquelles il ne parvient pas à terminer la classe.

Tenir compte du code de démonstration suivante:

Option Explicit 
Private Const maxServants As Integer = 15 
Private Const className As String = "Master" 
Private Sub Class_Initialize() 
    Debug.Print className & " class constructor " 
    Set g_coll1 = New Collection 
    Dim i As Integer 
    For i = 1 To maxServants 
     Dim m_servant As Servant 
     Set m_servant = New Servant 
     m_servant.InstanceNo = i 
     g_coll1.Add Item:=m_servant, Key:=CStr(i) 
     Debug.Print "Adding servant " & m_servant.InstanceNo 
    Next 
End Sub 
Private Sub Class_Terminate() 
    Dim i As Integer 

    For i = maxServants To 1 Step -1 
     g_coll1.Remove (CStr(i)) 
    Next 

    Debug.Print className & " class terminator " 
    Set g_coll1 = Nothing 
    Exit Sub 

End Sub 

et

Option Explicit 
Private Const className As String = "Servant" 
Private m_instanceNo As Integer 
Private Sub Class_Initialize() 
    m_instanceNo = 0 
    Debug.Print className & " class constructor " 
End Sub 
Public Property Get InstanceNo() As Integer 
    InstanceNo = m_instanceNo 
End Property 
Public Property Let InstanceNo(newInstanceNo As Integer) 
    m_instanceNo = newInstanceNo 
End Property 
Private Sub Class_Terminate() 
    Debug.Print className & " class terminator for " & CStr(Me.InstanceNo) 
End Sub 

ce qui est le code de harnais de test:

Option Explicit 
Global g_coll1 As Collection 
Public Sub Main() 
    Dim a As Master 
    Set a = New Master 
End Sub 

Maintenant, pour chaque course, le Class_Terminate du Serviteur est toujours invoqué. Et je ne vois rien dans le code de production qui devrait garder l'objet dans la collection référencée.

1.) Y a-t-il un moyen de forcer la fin de la classe sur le Remove? Autrement dit, puis-je appeler Obj.Class_Terminate et être assuré qu'il fonctionnera à chaque fois? 2. Sur mon code de production (et ma petite application de test) les classes sont marquées "Instancing - 5 MultiUse". Je réalise que cela peut être une sorte de problème de threading; Existe-t-il un moyen efficace de prouver (ou réfuter) que le multi-threading est la cause de ce problème - une sorte de traçage que je pourrais ajouter ou un autre type de test que je pourrais effectuer?


EDIT: Par des commentaires perspicaces de MarkJ ci-dessous, je dois ajouter que le test affiché ci-dessus et le code de production sont les deux exe's ActiveX - une partie de la raison pour laquelle je demande à propos de mulit-threading.

+2

Vous pouvez vérifier si l'objet est toujours référencé après l'avoir retiré de la collecte en consultant son compte de référence à l'aide d'un hack: http://www.vb-helper.com/howto_get_reference_count.html –

+0

@Pavel, merci pour le lien . –

Répondre

3

Nous avions un problème similaire, mais où nous pouvions tracer la non-terminaison des objets à descendre vers une instance détenue ailleurs dans notre application.

En fin de compte, nous avons dû écrire notre méthode de terminaison comme ceci:

Private Sub Class_Terminate() 
    Terminate 
End Sub 

Public Sub Terminate() 
    'Do real termination in here' 
End Sub 

Donc chaque fois que vous vouliez vraiment la classe à fin (lorsque vous appelez g_coll1.Remove), vous pouvez également appeler Terminate sur l'objet retenu.

Je pense que vous pourriez aussi rendre Class_Terminate public, mais c'est un peu moche à mon avis. En ce qui concerne votre point (2), je pense qu'il est très improbable que ce soit un problème de threading, mais je ne peux pas penser à une bonne preuve/test au sommet de ma tête. Je suppose que vous pouvez considérer une chose très simple: utilisez-vous manuellement le thread dans votre application? VB6 ne filetage pas beaucoup faire automatiquement ... (voir ci-dessous modifier) ​​

[Modifier ] MarkJ nous dit que, apparemment, la construction comme une application ActiveX signifie que VB6 ne automatiquement effectuer le filetage. Quelqu'un d'autre devra explorer les implications de cela, puisque je ne le connaissais pas!

+0

@Ant, la raison pour laquelle je pose la question à propos du multi-thread est parce que les logs de trace semblent avoir plusieurs threads d'exécution. –

+0

@Ant, Onorio. Une question importante est de savoir si l'application est un exe ActiveX? Si c'est le cas, alors VB6 ** ** procédera automatiquement au filetage, et l'option "MultiUse" signifie que différents clients pourraient partager les mêmes objets. Cela pourrait causer des complications. – MarkJ

+0

@MarkJ, Bingo. Oui, je devrais ajouter cela à ma description ci-dessus. Oui, l'application en question est un exe ActiveX. –

Questions connexes