2012-04-11 4 views
7

Ich habe eine Klasse in meiner .NET 3.5 C# WinForms-Anwendung, die fünf Methoden hat. Jede Methode verwendet verschiedene Gruppen von C++ - COM-Schnittstellen. Verwenden Sie Marshal.FinalReleaseCOMObject zum Bereinigen dieser COM-Objekte. Dieser Code funktioniert problemlos auf dieser .NET-Plattform. Aber wenn ich diese Anwendung auf .NET 4.0 bewegen, fange ich in einem dieser Verfahren auf einer Linie diesen Fehler, wo ich ICOMInterface1-ICOMInterface2 eine Variable gegossen, das heißt:"COM-Objekt, das von seinem zugrunde liegenden RCW getrennt wurde, kann nicht verwendet werden" mit .NET 4.0

ICOMInterface1 myVar= obj as ICOMInterface2; 

COM-Objekt, das hat wurde von seinem zugrunde liegenden RCW getrennt kann nicht verwendet werden.

Und wenn ich die Zeile entfernen, wo ich Marshal.FinalReleaseCOMObject verwende, bekomme ich diesen Fehler nicht.

Was fehlt mir hier? Und wie bereinige ich diese nicht verwalteten COM-Objekte aus dem Speicher auf .NET 4.0-Plattform?

Antwort

13

Die einfache Antwort ist nie Verwenden Sie Marshal.FinalReleaseComObject, es sei denn, Sie müssen unbedingt. Und wenn Sie dies tun, müssen Sie einige zusätzliche Regeln beachten.

Wenn ein COM-Objekt in .NET verwendet wird, erstellt die Laufzeitumgebung ein so genanntes "RCW" oder "Runtime Callable Wrapper" für dieses Objekt. Dieser RCW ist nur ein normales Objekt, das eine COM-Referenz für das Objekt enthält. Wenn dieses Objekt Garbage Collected ist, wird IUnknown :: Release() für das COM-Objekt wie erwartet aufgerufen. Was das bedeutet ist, es sei denn, Ihr COM-Objekt erfordert, dass die letzte Release() zu einem sehr bestimmten Zeitpunkt durchgeführt wird, nur den Müllsammler kümmern sich darum kümmern. Viele COM-Objekte fallen in diesen Fall, also vergewissern Sie sich unbedingt, dass Sie den Aufruf von Release() sorgfältig verwalten müssen.

Wenn Sie also FinalReleaseComObject aufrufen, dekrementiert das im Wesentlichen den Verweis der RCW auf das COM-Objekt, bis es Null erreicht und der RCW das COM-Objekt dann freigibt. An diesem Punkt ist dieser RCW jetzt zombiert, und jeder Gebrauch davon wird die Ausnahme geben, die Sie gesehen haben. Die CLR (standardmäßig) erstellt nur einen einzelnen RCW für ein zugrunde liegendes COM-Objekt. Das heißt, wenn die von Ihnen verwendete COM-API dasselbe Objekt zweimal zurückgibt, wird nur ein einzelner RCW verwendet. Ein Aufruf von FinalReleaseComObject bedeutet, dass plötzlich alle Nutzungen dieses RCW Toast sind.

Der einzige Weg, um zu garantieren, dass Sie eine einzigartige Marshal.GetUniqueObjectForIUnknown haben, die RCW Freigabe verhindert. Aber wie ich bereits sagte, ist dies in den meisten COM-APIs nicht notwendig, also tun Sie es einfach nicht.

Paul Harrington schrieb eine gute blog post über [Final] ReleaseComObject und es ist Übel. Es ist eine gefährliche Waffe, die dich nur verletzt, wenn sie nicht gebraucht wird. Da du diese Frage stellst, würde ich vermuten, dass du sie überhaupt nicht anrufen musst. :-)

+0

Danke Jason für deine Eingaben.Diese Erklärung gilt auch für ReleaseCOMObject-Methode? Weil, wenn ich es anstelle von FinalReleaseCOMObject verwende, sehe ich immer noch das gleiche Verhalten ... ie.it funktioniert auf 3.5 aber nicht on 4.0.Warum wurde gefragt, was die .net-Framework-Version mit diesem Verhalten zu tun hatte? Liegt es daran, dass die Funktionsweise von GC jetzt in 4.0 geändert wird? – user74042

+1

Also RCWs selbst haben eine Refcount, die dekrementiert wird, wenn Sie Marshal.ReleaseComObject aufrufen. "FinalReleaseComObject" ruft das nur auf, bis der Refcount null erreicht. –

+1

Was sich in der CLR geändert hat, was das verursacht hat ...Es ist schwer ohne Debugger zu sagen. –

Verwandte Themen