48 votes

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

J'essaie d'utiliser la dll 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 que je réfère ma bibliothèque dans mon projet de console, j'obtiens cette erreur :

L'objet COM qui a été séparé de son TCR 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 plusieurs raisons, les principales que je connais sont les suivantes.

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 garder une référence forte au délégué de callback. Voici un exemple de la manière correcte de procéder et de la manière incorrecte de le faire : La raison en est qu'une référence forte doit être conservée au délégué, si elle sort de la portée, le wrapper libérera le compte de référence pour l'interface et de mauvaises choses se produiront.

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 à un wrapper d'appel du Runtime disposé

Le wrapper a été éliminé et des appels sont effectués après son élimination. Cela peut se produire si un contrôle utilise un contrôle Activex ou un objet COM et que le contrôle Dispose() est appelé dans le désordre.

  • Un formulaire est appelé Close().
  • System.Windows.Forms.Close() appellera Dispose()
  • La fonction Dispose() virtuelle de votre formulaire sera appelée, ce qui, espérons-le, appellera 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 ceux des contrôles enfants.
  • Si le contrôle qui possède un objet COM est explicitement éliminé après base.Dispose() et s'il appelle des méthodes sur son objet COM, celles-ci échoueront 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 façon de déboguer ce problème est de faire ce qui suit :

  1. Écrivez une classe qui hérite de la classe Interop (également connue sous le nom de Runtime Callable Wrapper ou RCW).
  2. Remplacer DetachEventSink
  3. Annulation Dispose
  4. Appelez votre nouvelle classe au lieu d'appeler directement la classe d'interopérabilité.
  5. Ajouter un point d'arrêt à DetachEventSink et Dispose
  6. Voir qui appelle ces méthodes dans le désordre

Une autre chose

Cela n'a rien à voir avec ce problème, mais tant que nous sommes sur le sujet, à moins que vous ne sachiez autre chose, pensez toujours à vérifier que le thread à partir duquel vos objets COM sont utilisés est marqué STA. Vous pouvez le faire en ouvrant le débogueur et en vérifiant la valeur renvoyée par :

Thread.CurrentThread.GetApartmentState();

37voto

AJ. Points 6588

Il est difficile de savoir ce que fait votre application, mais il semble que vous instanciez l'objet COM et que vous essayiez d'y accéder depuis 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 où vous l'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