Cela peut se produire pour quelques raisons, les principales que je connais sont ci-dessous.
Gestionnaires d'événements sans références solides au délégué
Un appelant s'abonne à un événement sur l'objet com sans conserver de référence forte au délégué de rappel. Voici un exemple de comment le faire correctement et comment ne pas le faire: La raison en est qu'une référence forte doit être conservée vers le délégué, si elle sort de portée, l'enveloppe libérera le décompte des références pour l'interface et des choses regrettables se produiront.
public class SomeClass
{
private Interop.ComObjectWrapper comObject;
private event ComEventHandler comEventHandler;
public SomeClass()
{
comObject = new Interop.ComObjectWrapper();
// NON - MAUVAIS !
comObject.SomeEvent += new ComEventHandler(EventCallback);
// OUI - BIEN !
comEventHandler = new ComEventHandler(EventCallback);
comObject.SomeEvent += comEventHandler
}
public void EventCallback()
{
// FAIRE LE TRAVAIL
}
}
Appels à un Wrapper d'appel Runtime disposé
L'enveloppe a été disposée et des appels sont effectués après sa disposition. Une manière courante que cela puisse se produire est si un contrôle utilise un contrôle activex ou un objet COM et que le Dispose() des contrôles est appelé de manière désordonnée.
- Un formulaire reçoit Close() appelé.
- System.Windows.Forms.Close() appellera Dispose()
- Votre Dispose() virtuel des formulaires sera appelé, ce qui, espérons-le, appelle base.Dispose() quelque part. Systems.Windows.Forms.Dispose() libérera tous les objets COM et les synchronisations d'événements sur le formulaire, même de la part des contrôles enfants.
- Si le contrôle qui possède un objet com est explicitement disposé après base.Dispose() et s'il appelle des méthodes sur son objet COM, ceux-ci échoueront maintenant et vous obtiendrez l'erreur "L'objet COM qui a été séparé de son RCW sous-jacent ne peut être utilisé".
Étapes de débogage
Une bonne manière de déboguer ce problème est de faire ce qui suit:
- Écrire une classe qui hérite de la classe Interop (également connue sous le nom de wrapper d'appel Runtime ou RCW).
- Remplacer DetachEventSink
- Remplacer Dispose
- Appelez votre nouvelle classe au lieu d'appeler directement la classe interop
- Ajouter un point d'arrêt à DetachEventSink et à Dispose
- Voir qui appelle ces méthodes de manière désordonnée
Une autre chose
Ce n'est pas lié à ce problème mais tant que nous en parlons, à moins que vous ne sachiez autrement, n'oubliez jamais de vérifier que le thread à partir duquel vos objets COM sont utilisés est marqué STA. Vous pouvez le faire en arrêtant le débogueur et vérifiant la valeur retournée depuis:
Thread.CurrentThread.GetApartmentState();