2010-04-02 13 views
6

Bis vor kurzem glaubte ich, dass die .NET-Laufzeit nur die Referenzanzahl von COM-Objekten um 1 erhöht, wenn eine runtime-callable wrapper erstellt, und dass nur ein solcher Laufzeitaufruf Wrapper für ein bestimmtes COM-Objekt erstellt wird.Wann enthält die .NET-Laufzeit einen Referenzzähler> 1 für COM-Objekte?

Wenn ich mich nicht irre, impliziert das obige, dass Marshal.FinalReleaseComObject und Marshal.ReleaseComObject in der Praxis dasselbe tun.

Allerdings schrieb ich heute einige Tests, um zu überprüfen, dass COM-Objekte ordnungsgemäß von meinem Code freigegeben werden. Ich mache das, indem ich das vermeintlich freigegebene Objekt anrufe und auf die erwarteten InvalidComObjectException überprüfe. Es stellt sich heraus, dass es Fälle gibt, in denen die Ausnahme nach einer FinalReleaseComObject ausgelöst wird, aber nicht nach einer ReleaseComObject.

Bedeutet dies, dass die .NET 2.0-Laufzeit mehr als einen Verweis auf ein COM-Objekt enthalten kann? Wenn ja, wann tut es das?

Antwort

5

Hier gibt es eine zusätzliche Ebene der Indirektion. Ja, der RCW behält eine einzige Referenzzählung auf den nativen COM-Schnittstellenzeigern bei. Aber der RCW hat auch einen Referenzzähler, er wird jedesmal erhöht, wenn ein COM-Schnittstellenzeiger dem RCW zugeordnet wird. Dies kann passieren, wenn eine COM-Methode einen Schnittstellenzeiger zurückgibt. Der Finalizer der entsprechenden .NET-Wrapper-Klasse dekrementiert ihn.

Sie können mit dieser Referenzzählung direkt durch Marshal.ReleaseComObject(), die es um eins wie der Finalizer dekrementiert, und Marshal.FinalReleaseComObject(), die es auf Null zappt, und garantiert, dass die IUnknown :: Release () Methode wird aufgerufen. Sie fallen natürlich in die Kategorie "Besser wissen, was du tust". Wenn man es falsch macht, entsteht die hässliche und nicht entdeckbare "COM-Objekt-Ausnahme von der zugrundeliegenden RCW" -Ausnahme.