48 votes

Objet COM qui a été séparé de sa RCW sous-jacente ne peut pas être utilisé

Je suis en train d'essayer d'utiliser le OpcRcw.da.dll. Si j'interopère ce dll à l'intérieur d'un projet de console de test, tout fonctionne, mais si je construis un projet de dll pour faire mon gymnastique d'interop et réfère ma bibliothèque dans mon projet de console, je reçois cette erreur :

Objet COM qui a été séparé de son RCW sous-jacent ne peut pas être utilisé.

Que faut-il faire à un projet de classe lib pour ne pas tuer la référence RCW?

78voto

Steve Sheldon Points 2398

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:

  1. Écrire une classe qui hérite de la classe Interop (également connue sous le nom de wrapper d'appel Runtime ou RCW).
  2. Remplacer DetachEventSink
  3. Remplacer Dispose
  4. Appelez votre nouvelle classe au lieu d'appeler directement la classe interop
  5. Ajouter un point d'arrêt à DetachEventSink et à Dispose
  6. 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();

37voto

AJ. Points 6588

Il est assez difficile de dire ce que fait réellement votre application, mais il semble que vous pourriez instancier l'objet COM, puis essayer d'y accéder à partir d'un autre thread, peut-être dans un événement Timer.Elapsed. Si votre application est multithreadée, vous devez instancier l'objet COM dans chaque thread que vous utiliserez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X