L’object 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 dll pour faire ma gymnastique d’interopérabilité et refaire ma bibliothèque dans mon projet de console, j’obtiens cette erreur:

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

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

Il est difficile de savoir ce que fait votre application, mais il semblerait que vous instanciez l’object COM et que vous tentiez d’y accéder depuis un autre thread, peut-être dans un événement Timer.Elapsed. Si votre application est multithreadée, vous devez instancier l’object COM dans chaque thread dans lequel vous l’utiliserez.

Cela peut arriver pour quelques raisons, les grandes que je connais 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’object com sans conserver une référence forte au délégué de rappel. Voici un exemple de la façon de procéder correctement et de ne pas le faire: la raison pour laquelle une référence forte doit être conservée pour le délégué, si elle est hors de scope, le wrapper publiera le compte de référence pour l’interface et les 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 à un wrapper appelable à l’exécution à l’exécution

Le wrapper a été éliminé et les appels sont en cours après son élimination. Un moyen courant peut arriver si un contrôle utilise un contrôle activex ou un object COM et que les contrôles Dispose () sont appelés hors service.

  • Un formulaire obtient Close () appelé.
  • System.Windows.Forms.Close () appellera Dispose ()
  • Vos formulaires virtuels Dispose () seront appelés et appellent heureusement base.Dispose () quelque part. Systems.Windows.Forms.Dispose () libère tous les objects COM et les événements synchronisés sur le formulaire, même à partir des contrôles enfants.
  • Si le contrôle qui possède un object com est explicitement disposé après base.Dispose () et s’il appelle des méthodes sur son object COM, celles-ci échoueront et vous obtiendrez l’erreur “Un object COM 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 consiste à effectuer les opérations suivantes:

  1. Ecrivez une classe qui hérite de la classe Interop (également appelée wrapper ou RCW).
  2. Ignorer DetachEventSink
  3. Remplacer
  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 hors d’usage

Une autre chose

Ceci n’est pas lié à ce problème, mais pendant que nous sums sur le sujet, à moins que vous ne sachiez le contraire, n’oubliez pas de vérifier que le thread à partir duquel vos objects COM sont utilisés est marqué STA. Vous pouvez le faire en décomposant le débogueur et en vérifiant la valeur renvoyée par:

 Thread.CurrentThread.GetApartmentState();