Frage

Ich habe eine Bewerbung, die Office Interop -Versammlungen verwendet. Mir ist der von der Laufzeit verwaltete "Laufzeit Callable Wrapper (RCW)" bewusst. Aber ich bin mir nicht sicher, wie die Referenzzahl inkrementiert wird. MSDN sagt,

RCW führt nur einen Verweis auf das verpackte COM -Objekt, unabhängig von der Anzahl der verwalteten Clients, die es nennen.

Wenn ich es richtig verstehe, am folgenden Beispiel,

using Microsoft.Office.Interop.Word;

static void Foo(Application wrd)
{
    /* .... */
}

static void Main(string[] args)
{
    var wrd = new Application();
    Foo(wrd);
    /* .... */
}

Ich bestehe die Instanz wrd zu einer anderen Methode. Dies erhöht jedoch nicht die interne Referenzzahl. Ich frage mich also, welche Szenarien die Referenzzahl inkrementiert wird? Kann jemand auf ein Szenario hinweisen, in dem die Referenzzahl inkrementiert wird?

Außerdem habe ich ein Blog gelesen, in dem es darum geht, Doppelpunkte beim Programmieren mit COM -Objekten zu verwenden. Etwas wie, wrd.ActiveDocument.ActiveWindow. Der Autor behauptet, dass Compiler separate Variablen erstellt, um die Werte zu halten, die den Referenzzähler erhöhen. IMHO, das ist falsch und das erste Beispiel beweist dies. Ist das korrekt?

Jede Hilfe wäre großartig!

War es hilfreich?

Lösung

Ich habe auch diese Frage untersucht und an einer COM/NET-Interop-zentrierten Anwendung gearbeitet, gegen Lecks, Hänge und Abstürze kämpft.

Kurze Antwort: Jedes Mal, wenn das COM -Objekt von COM -Umgebung an .NET übergeben wird.

Lange Antwort:

  1. Für jedes COM -Objekt gibt es ein RCW -Objekt [Test 1] [Ref 4
  2. Die Referenzzahl wird jedes Mal inkrementiert, wenn das Objekt innerhalb des COM -Objekts angefordert wird (Aufruf von Eigenschaften oder Methode auf COM -Objekt, die COM -Objekt zurückgeben, wird die zurückgegebene COM -Objektreferenzzahl durch eins erhöht) [Test 1
  3. Die Referenzzahl wird nicht erhöht, indem auf andere COM -Schnittstellen des Objekts gegossen oder die RCW -Referenz um [Test 2] verschoben wird.
  4. Die Referenzzahl wird jedes Mal inkrementiert, wenn ein Objekt als Parameter in Ereignis übergeben wird, das von COM [Ref 1] angesprochen wird [Ref 1

Nebennäher: Sie sollten STETS Befreie COM -Objekte, sobald du sie benutzst. Wenn Sie diese Arbeit dem GC überlassen, kann dies zu Lecks, unerwarteten Verhaltensweisen und Ereignis -Deadlocks führen. Dies ist zehnmal wichtiger, wenn Sie auf Objekt zugreifen, nicht auf dem STA -Thread, auf dem er erstellt wurde. [Ref 2] [Ref 3] [Schmerzhafte persönliche Erfahrung

Ich hoffe, ich habe alle Fälle abgedeckt, aber Com ist ein harter Keks. Prost.

Test 1 - Referenzzahl

private void Test1( _Application outlookApp )
{
    var explorer1 = outlookApp.ActiveExplorer();
    var count1 = Marshal.ReleaseComObject(explorer1);
    MessageBox.Show("Count 1:" + count1);

    var explorer2 = outlookApp.ActiveExplorer();
    var explorer3 = outlookApp.ActiveExplorer();
    var explorer4 = outlookApp.ActiveExplorer();

    var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer4);
    var count2 = Marshal.ReleaseComObject(explorer4);
    MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 6, Equals: True

Test 2 - Referenzzahl Forts.

private static void Test2(_Application outlookApp)
{
    var explorer1 = outlookApp.ActiveExplorer();
    var count1 = Marshal.ReleaseComObject(explorer1);
    MessageBox.Show("Count 1:" + count1);

    var explorer2 = outlookApp.ActiveExplorer();

    var explorer3 = explorer2 as _Explorer;
    var explorer4 = (ExplorerEvents_10_Event)explorer2;
    var explorerObject = (object)explorer2;
    var explorer5 = (Explorer)explorerObject;

    var equals = explorer2 == explorer3 && ReferenceEquals(explorer2, explorer5);
    var count2 = Marshal.ReleaseComObject(explorer4);
    MessageBox.Show("Count 2:" + count2 + ", Equals: " + equals);
}
Output:
Count 1: 4
Count 2: 4, Equals: True

Quellen, auf die ich zusätzlich zu meinen Erfahrungen und Testen weiterleite:

1. Johannes Passings - RCW Referenzzählregeln! = Com Referenzzählregeln

2. ERAN SANDLER - LIVERTIME CALLABLE Wrapper Interna und gemeinsame Fallstricke

3. Eran Sandler - Marschall.ReleascomObject und CPU Spinning

4. MSDN - Laufzeit Callable Wrapper

Andere Tipps

Ich habe den Code für den RCW nicht gesehen - nicht einmal sicher, ob er Teil des SSCLI ist -, aber ich musste ein ähnliches System für die Verfolgung der Lebensdauer von COM -Objekten in Slimdx implementieren und musste einiges an den RCW recherchieren. Ich erinnere mich, dass es mir hoffentlich einigermaßen genau ist, aber mit einem Hauch von Salz.

Wenn das System zum ersten Mal einen COM -Schnittstellenzeiger sieht, geht es einfach zu einem Cache, um festzustellen, ob ein RCW für diesen Schnittstellenzeiger vorhanden ist. Vermutlich würde der Cache schwache Referenzen verwenden, um die Abschluss und die Sammlung des RCW nicht zu verhindern.

Wenn es einen Live -Wrapper für diesen Zeiger gibt, gibt das System den Wrapper zurück - wenn die Schnittstelle in einer Weise erhalten wurde, die die Referenzzahl der Schnittstelle erhöhte, würde das RCW -System zu diesem Zeitpunkt vermutlich Release () aufrufen. Es hat einen lebenden Wrapper gefunden, so dass Wrapper eine einzige Referenz ist und genau eine Referenz beibehalten möchte. Wenn es keinen Live -Wrapper im Cache gibt, erzeugt es einen neuen und gibt es zurück.

Der Wrapper -Aufruf wird auf dem zugrunde liegenden COM -Schnittstellenzeiger aus dem Finalizer veröffentlicht.

Der Wrapper befindet sich zwischen Ihnen und dem COM -Objekt und behandelt das gesamte Parametermarschall. Dies ermöglicht es auch, das Rohgebnis jeder Schnittstellenmethode zu erhalten, die selbst ein weiterer Schnittstellenzeiger ist, und diesen Zeiger durch das RCW -Caching -System auszuführen, um festzustellen, ob er noch vorhanden ist, bevor Sie den umwickelten Schnittstellenzeiger zurückgeben.

Leider habe ich kein gutes Verständnis dafür, wie das RCW -System die Erzeugung der Proxy -Objekte verarbeitet, um Dinge über Anwendungsdomänen oder Thread -Apartments hinweg zu senden. Es war kein Aspekt des Systems, das ich für SlimDX kopieren musste.

Sie sollten keine besondere Behandlung benötigen. Die Laufzeit hält nur einen Verweis auf das COM -Objekt. Der Grund dafür ist, dass der GC alle verwalteten Referenzen verfolgt. Wenn der RCW also aus dem Spielraum geht und gesammelt wird, wird die COM -Referenz veröffentlicht. Wenn Sie eine verwaltete Referenz übergeben, verfolgt das GC sie für Sie - dies ist einer der größten Vorteile einer GC -basierten Laufzeit gegenüber dem alten AddREF/Release -Schema.

Sie müssen Marschall nicht manuell anrufen.

Das Akzeptierte Lösung ist gültig, aber hier sind einige zusätzliche Hintergrundinformationen.

Ein RCW enthält eine oder mehrere native COM -Objekt -Schnittstelle intern für sein COM -Objekt.

Wenn ein RCW sein zugrunde liegendes COM -Objekt freigibt, entweder aufgrund des Sammelns von Müll oder aufgrund Marshal.ReleaseComObject() Wenn es darauf angerufen wird, veröffentlicht es alle intern gehaltenen COM -Objektoberflächen.

Hier gibt es tatsächlich viele Referenzzählungen - eine bestimmt, wann .NETs RCW seine zugrunde liegenden COM -Objektoberflächen veröffentlichen sollte, und dann hat jede dieser rohen COM -Schnittstellen eine eigene Referenzzahl wie in regulärem COM.

Hier ist Code, um Raw com zu erhalten IUnknown Schnittstellenreferenzzahl:

int getIUnknownReferenceCount(object comobject)
{
    var iUnknown = Marshal.GetIUnknownForObject(comObject);
    return Marshal.Release(iUnknown);
}

Und Sie können dasselbe für die anderen COM -Schnittstellen des Objekts verwenden Marshal.GetComInterfaceForObject().

Zusätzlich zu den in der aufgeführten Wegen Akzeptierte Lösung, Wir können auch die .NET -RCW -Referenzzahl künstlich erhöhen, indem wir etwas anrufen wie Marshal.GetObjectForIUnknown().

Hier ist der Beispiel Code, der diese Technik verwendet, um die RCW -Referenzzahl eines bestimmten COM -Objekts zu erhalten:

int comObjectReferenceCount(object comObject)
{
    var iUnknown = Marshal.GetIUnknownForObject(comObject);
    Marshal.GetObjectForIUnknown(iUnknown);
    Marshal.Release(iUnknown);
    return Marshal.ReleaseComObject(comObject);
}

Sie müssen anrufen Marshal.ReleaseComObject Auf Ihrer WRD -Variablen, um Ihre Referenz auf die Word -Anwendung zu veröffentlichen.

Auf diese Weise, wenn die Nachricht nicht sichtbar ist und Sie Ihre Anwendung schalten, wird das EXE ebenfalls entladen, es sei denn, Sie haben es dem Benutzer sichtbar gemacht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top