office .net com com-interop

office - Interoperabilidad.NET y COM: lanzar COM desde el cliente.NET



interop excel c# (2)

Supongamos que tengo un objeto COM (no administrado) y un cliente .NET.

¿Es necesario llamar desde el cliente .NET Marshal.FinalReleaseComObject método Marshal.FinalReleaseComObject para liberar el objeto COM?


No. No es necesario liberar explícitamente un objeto COM de un cliente .Net. El objeto COM se recopilará como cualquier otro objeto .Net y liberará su identificador nativo subyacente una vez que se eliminen todas las referencias a él.

El uso explícito de FinalReleaseComObject puede conducir a errores de programación. Si otro componente en su código sigue haciendo referencia al objeto COM, sacará el objeto nativo de debajo de él. Eso posiblemente conduzca a fallas en tiempo de ejecución en el futuro.


Un "Sí" modificado y un "No".

En primer lugar, tenga en cuenta que ReleaseComObject no disminuye automáticamente el recuento real de referencias de objetos COM. Más bien, disminuye el contador interno de RCW. (Cada vez que se mueve el mismo objeto COM desde COM-> NET usará el mismo RCW e incrementará el contador RCW en uno). Del mismo modo, FinalRelaseComObject también afecta al FinalRelaseComObject RCW y efectivamente lo "establece en 0". Es cuando el contador RCW va a cero que .NET disminuirá el recuento real de ref.

Entonces, "sí", pero modificado para estas reglas :

  1. Cada vez que un objeto se cruza desde COM-> NET, debe tener ReleaseComObject , pero no FinalReleaseComObject . Es decir, debe invocarse una vez por cada vez que el objeto cruza, incluso si da como resultado una referencia, es decir, RCW .
  2. El número de referencias al RCW (que es solo un contenedor proxy) no importa; solo las veces que el objeto ha cruzado el límite. Ver la regla # 1. (Es importante controlar las referencias y quién las guarda, pero lo "peor" que ocurre en este caso es una excepción al uso de un "RCW separado" que no es diferente a usar una transmisión Disposed).

Digo las reglas anteriores y no FinalReleaseComObject porque los objetos RCW se almacenan en caché en un proxy de identidad, ¡así que usar FinalReleaseComObject afectará los cruces de frontera COM-> NET que ni siquiera conocía ! (Esto es malo y, en este punto, estoy totalmente de acuerdo con la respuesta de JaredPars).

Y "no" en eso, cuando se reclama un RCW (se llama al finalizador), automáticamente "liberará" la referencia COM (efectivamente llama a FinalReleaseComObject en sí mismo). Recuerde que, dado que solo hay un objeto RCW, esto significa que nunca será reclamado mientras haya una referencia en .NET. Si se recupera el RCW, no hay problema porque, desde arriba, no hay más referencias a dicho RCW y, por lo tanto, .NET sabe que puede disminuir el recuento de referencias COM en uno (lo que puede causar la destrucción del objeto COM).

Sin embargo, dado que .NET GC es meticuloso y no determinista , confiar en este comportamiento significa que los tiempos de vida de los objetos no están controlados. Esto puede causar muchos problemas sutiles al trabajar con el Modelo de Objetos de Outlook, por ejemplo. (Puede ser menos propenso a problemas con otros servidores COM, pero el OOM realiza un "caché" divertido de objetos internamente. Es fácil obtener una excepción "El elemento ya ha sido modificado" cuando no se controlan las vidas útiles explícitamente).

En mi código tengo una clase ComWrapper que admite IDisposable . Esto me permite pasar objetos RCW obtenidos de COM-> NET con una clara propiedad de por vida . He tenido muy pocos problemas (casi ninguno, en realidad) en mi desarrollo Outlook-Addin después de cambiar a este enfoque y numerosos problemas antes de la mano. El "inconveniente" es que el límite de COM-> NET debe determinarse, pero una vez que eso ocurre, entonces internamente todas las vidas se manejan correctamente.

Feliz codificación.