8 votes

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

Dans mon application WinForms .NET 3.5 C#, j'ai une classe qui comporte cinq méthodes. Chaque méthode utilise différents ensembles d'interfaces COM C++. J'utilise Marshal.FinalReleaseCOMObject pour nettoyer ces objets COM. Ce code fonctionne sans problème sur cette plate-forme .NET. Mais lorsque je passe cette application à .NET 4.0, je commence à obtenir cette erreur dans l'une de ces méthodes, à une ligne où j'extrais une variable de ICOMInterface1 a ICOMInterface2 , c'est-à-dire :

ICOMInterface1  myVar= obj as ICOMInterface2; 

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

Et si je supprime la ligne où j'utilise Marshal.FinalReleaseCOMObject Je n'obtiens pas cette erreur.

Qu'est-ce qui m'échappe ? Et comment nettoyer ces objets COM non gérés de la mémoire sur la plate-forme .NET 4.0 ?

15voto

Jason Malinowski Points 6493

La réponse est simple jamais utilice Marshal.FinalReleaseComObject sauf en cas de nécessité absolue. Et si vous le faites, vous devez respecter certaines règles supplémentaires.

Lorsqu'un objet COM est utilisé dans .NET, le moteur d'exécution crée ce que l'on appelle un "RCW" ou "runtime callable wrapper" pour cet objet. Ce RCW est un objet normal qui contient une référence COM sur l'objet. Lorsque cet objet est ramassé, il appelle IUnknown::Release() sur l'objet COM, comme on peut s'y attendre. Cela signifie qu'à moins que votre objet COM exige que le dernier Release() est effectué à un moment bien précis, il suffit de laisser le garbage collector s'en charger. De nombreux objets COM tombent dans ce cas, il faut donc absolument vérifier que vous doit gérer avec soin l'appel à Release().

Ainsi, lorsque vous appelez FinalReleaseComObject, il s'agit essentiellement de décrémenter la référence que le TCR a sur l'objet COM jusqu'à ce qu'elle atteigne zéro et que le TCR libère l'objet COM. À ce stade, ce RCW est maintenant zombifié, et toute utilisation de celui-ci produira l'exception que vous avez vue. Le CLR (par défaut) ne crée qu'un seul RCW pour tout objet COM sous-jacent, ce qui signifie que si l'API COM que vous utilisez a renvoyé le même objet deux fois, il n'aura qu'un seul RCW. L'appel à FinalReleaseComObject signifierait que soudainement tous Les utilisations de ce RCW sont grillées.

La seule façon de garantir que vous avez un Marshal.GetUniqueObjectForIUnknown unique, ce qui empêche tout partage de RCW. Mais comme je l'ai dit plus haut, dans la plupart des API COM, il n'est pas nécessaire de le faire en premier lieu, alors ne le faites pas.

Paul Harrington a rédigé un bon article de blog sur [Final]ReleaseComObject et ses méfaits. C'est une arme dangereuse qui, si elle n'est pas utilisée, ne fera que vous blesser. Puisque vous posez cette question, je soupçonne que vous n'avez pas besoin de l'appeler du tout :-)

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