web-dev-qa-db-fra.com

L'objet COM qui a été séparé de son RCW sous-jacent ne peut pas être utilisé

J'essaie d'utiliser le OpcRcw.da.dll. Si j'interopère cette DLL dans un projet de console de test, tout fonctionne, mais si je construis un projet de DLL pour faire ma gymnastique d'interopérabilité et ajouter ma bibliothèque dans mon projet de console, j'obtiens cette erreur:

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

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

45
kevin marchand

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

35
AJ.

Cela peut se produire pour plusieurs raisons, les plus importantes que je connaisse sont ci-dessous.

Gestionnaires d'événements sans références fortes au délégué

Un appelant s'abonne à un événement sur l'objet com sans conserver une référence forte au délégué de rappel. Voici un exemple de la façon de le faire correctement et de ne pas le faire: La raison en est qu'une référence forte doit être conservée au délégué, si elle sort du domaine, le wrapper publiera le nombre de références pour l'interface et de mauvaises choses vont arriver.

public class SomeClass
{
    private Interop.ComObjectWrapper comObject;
    private event ComEventHandler comEventHandler;

    public SomeClass()
    {
        comObject = new Interop.ComObjectWrapper();

        // NO - BAD!
        comObject.SomeEvent += new ComEventHandler(EventCallback);

        // YES - GOOD!
        comEventHandler = new ComEventHandler(EventCallback);
        comObject.SomeEvent += comEventHandler
    }

    public void EventCallback()
    {
        // DO WORK
    }
}

Appels vers un wrapper Runtime Callable Wrapper

L'encapsuleur a été supprimé et les appels sont effectués après qu'il a été supprimé. Cela peut se produire généralement si un contrôle utilise un contrôle ActiveX ou un objet COM et que les contrôles Dispose () sont appelés dans le désordre.

  • Un formulaire est appelé Close ().
  • System.Windows.Forms.Close () appellera Dispose ()
  • Vos formulaires virtuels Dispose () seront appelés, ce qui, espérons-le, appelle quelque part base.Dispose (). Systems.Windows.Forms.Dispose () libérera tous les objets COM et les synchronisations d'événements sur le formulaire, même à partir des contrôles enfants.
  • Si le contrôle qui possède un objet com est explicitement supprimé après base.Dispose () et s'il appelle des méthodes sur son objet COM, celles-ci échoueront maintenant et vous obtiendrez l'erreur "L'objet COM qui a été séparé de son RCW sous-jacent ne peut pas être utilisé".

étapes de débogage

Un bon moyen de déboguer ce problème est de procéder comme suit:

  1. Écrivez une classe qui hérite de la classe Interop (autrement connue sous le nom de wrapper appelable à l'exécution ou RCW).
  2. Remplacer DetachEventSink
  3. Ignorer l'élimination
  4. Appelez votre nouvelle classe au lieu d'appeler directement la classe interop
  5. Ajouter un point d'arrêt à DetachEventSink et éliminer
  6. Voir qui appelle ces méthodes hors service

ne autre chose

Ce n'est pas lié à ce problème, mais tant que nous sommes sur le sujet, sauf indication contraire, n'oubliez pas de vérifier que le thread à partir duquel vos objets COM sont utilisés est marqué STA. Vous pouvez le faire en interrompant le débogueur et en vérifiant la valeur renvoyée par:

Thread.CurrentThread.GetApartmentState();
78
Steve Sheldon