Question

J'ai une application qui utilise les ensembles de bureau. Je suis conscient de la « Runtime Callable Wrapper (RCW) » géré par le moteur d'exécution. Mais je ne suis pas très sûr de savoir comment le nombre de références s'incrémenté. MSDN dit,

  

RCW conserve juste une référence au   enveloppé objet COM quelle que soit la   nombre de clients gérés appeler.

Si je comprends bien, sur l'exemple suivant,

using Microsoft.Office.Interop.Word;

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

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

Je passe l'instance wrd à une autre méthode. Mais cela n'incrémente pas le compteur de référence interne. Je me demande donc sur quels scénarios le nombre de références s'incrémente? Point de tout le monde peut un scénario où le nombre de références s'incrémente?

Aussi je lis certains blog qui dit éviter d'utiliser des doubles points lors de la programmation avec des objets COM. Quelque chose comme, wrd.ActiveDocument.ActiveWindow. L'auteur prétend que le compilateur crée des variables distinctes pour contenir les valeurs qui incrémenter le compteur de référence. À mon humble avis, cela est faux et le premier exemple le prouve. Est-ce exact?

Toute aide serait génial!

Était-ce utile?

La solution

J'ai fait des recherches sur cette question aussi, travailler sur une application COM / .NET Interop-centrée, les fuites de combat, et bloque les accidents.

Réponse courte: Chaque fois que l'objet COM est passé de l'environnement COM .NET

.

Réponse longue:

  1. Pour chaque objet COM il y a un objet RCW [Test 1] [Ref 4]
  2. Nombre de référence est incrémenté à chaque fois que l'objet est demandée à l'intérieur de l'objet COM (appelant propriété ou méthode sur l'objet COM qui retournent un objet COM, le compteur de référence de l'objet COM retourné sera augmenté d'une unité) [Test 1]
  3. comptage de référence n'a pas été incrémenté par coulée à d'autres interfaces COM de l'objet ou le déplacement de la référence de RCW environ [Essai 2]
  4. comptage de référence est incrémenté à chaque fois qu'un objet est passé en paramètre en cas soulevé par COM [Ref 1]

Sur une note latérale: Vous devez toujours libération des objets COM dès que vous avez fini de les utiliser. Laissant ce travail à la GC peut conduire à des fuites, un comportement inattendu et blocages événement. Ceci est dix fois plus important si vous accédez à objet non sur le thread STA il a été créé. [Ref 2] [Réf 3] [expérience Douloureux]

Je suis espère avoir couvert tous les cas, mais COM est un cookie difficile. Vive.

Test 1 - comptage référence

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 -. Comptage référence suite

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

Sources I relais sur, en plus de mon expérience et de test:

1. Johannes Passage de - RCW référence Règles de comptage = COM comptage de référence Règles

2. Eran Sandler - Runtime Callable Wrapper Internes et pièges

3. Eran Sandler - Marshal.ReleaseComObject et CPU Spinning

4. MSDN - Runtime Callable Wrapper

Autres conseils

Je n'ai pas vu le code de la BRF - même pas sûr partie de ce de la SSCLI - mais je devais mettre en place un système similaire pour le suivi de la vie de l'objet COM dans SlimDX et a dû faire un peu de juste de la recherche en le RCW. Voilà ce que je me souviens, je l'espère c'est assez précise, mais le prendre avec une touche de sel.

Lorsque le système voit d'abord un pointeur d'interface COM, il va juste un cache pour voir s'il y a un RCW pour ce pointeur d'interface. On peut supposer que le cache serait d'utiliser des références faibles, afin de ne pas empêcher la finalisation et la collecte des BRF.

S'il y a un wrapper en direct pour ce pointeur, le système retourne l'emballage - si l'interface a été obtenue d'une manière qui incrémente le compteur de référence de l'interface, sans doute le système de RCW appellerait Release () à ce stade. Il a trouvé un emballage en direct, il sait que wrapper est une référence unique et il veut maintenir exactement une référence. S'il n'y a pas wrapper en direct dans le cache, il crée un nouveau et retourne.

L'enveloppe appelle de presse sur le pointeur d'interface COM sous-jacente (s) du finaliseur.

L'enveloppe se trouve entre vous et l'objet COM, et gère tous les paramètres marshaling. Cela permet également de lui permettre de prendre le résultat brut d'une méthode d'interface qui lui-même est un autre pointeur d'interface et d'exécuter ce pointeur à travers le système de mise en cache de RCW pour voir si elle existe encore avant de retourner le pointeur d'interface enveloppé.

Malheureusement, je ne dispose pas d'une bonne compréhension de la façon dont les poignées du système de RCW génération d'objets proxy pour envoyer des trucs dans des domaines d'application ou des appartements de fil; il n'a pas été un aspect du système que je avais besoin de copier pour SlimDX.

Vous ne devriez pas avoir besoin d'un traitement spécial. Le moteur d'exécution conserve une seule référence à l'objet COM. La raison est que le GC suit toutes les références gérées, de sorte que lorsque le RCW est hors de portée et est recueillie, la référence COM est libéré. Lorsque vous passez autour d'une référence gérée, la GC est-il suivi pour vous -. C'est l'un des plus grands avantages d'une exécution en fonction de GC-sur l'ancien AddRef / Release Scheme

Vous n'avez pas besoin d'appeler manuellement Marshal.ReleaseComObject sauf si vous voulez version plus déterministe.

Le solution acceptée est valide, mais voici quelques informations de base supplémentaires.

RCW contient une ou plusieurs références d'interface native d'objet COM interne pour objet COM.

Quand un RCW publie son objet COM sous-jacente, soit en raison d'obtenir des déchets collectés ou en raison de Marshal.ReleaseComObject() s'appelé, il libère toutes ses interfaces objet COM détenues en interne.

Il y a en fait beaucoup de chefs d'accusation de référence ici - une détermination quand RCW de .NET devrait libérer ses interfaces sous-jacentes de l'objet COM, puis chacune de ces interfaces COM premières a son propre compte de référence comme dans COM régulière

.

Code est ici pour obtenir le nombre de référence de l'interface COM IUnknown brut:

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

Et vous pouvez obtenir la même chose pour les autres interfaces COM à l'aide Marshal.GetComInterfaceForObject() de l'objet.

En plus des moyens indiqués dans le compte solution acceptée, nous pouvons également augmenter la référence RCW .NET artificiellement par appeler quelque chose comme Marshal.GetObjectForIUnknown().

Code exemple de l'utilisation ici la fabrication de cette technique pour obtenir le nombre de références de RCW d'un objet COM donné:

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

Vous devez appeler Marshal.ReleaseComObject sur votre variable wrd pour libérer votre référence à l'application de texte.

De cette façon, si Word n'est pas visible et vous fermez votre application, l'exe déchargera ainsi à moins que vous avez visible à l'utilisateur.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top