visual studio read office microsoft manejo example c# com excel-interop

c# - studio - Objeto COM excel excel interop clean up



microsoft.office.interop.word c# example (1)

Deberá liberar todos los objetos locales de forma manual en el ámbito donde los crea. Al usar aplicaciones de Office a través de la Automatización, no confíe en el recolector de basura para limpiar estos objetos, incluso si funciona correctamente, puede tomar tiempo para que se active y puede terminar con objetos temporales con referencias a otros objetos. que crees que ya se han ido.

Esta es una pregunta un tanto relacionada con más detalles que pueden aplicarse a usted si intenta ejecutar Excel desde su aplicación con Excel oculto.

La parte que definitivamente es relevante para ti es esta:

  • Envuelva todas las funciones que usan Excel en un bloque try..catch para capturar cualquier posible excepción.
  • Siempre libere explícitamente todos los objetos de Excel llamando a Marshal.ReleaseComObject() y luego establezca sus variables en null tan pronto como no las necesite. Siempre libere estos objetos en un bloque finally para asegurarse de que una llamada al método de Excel fallida no dará como resultado un objeto COM colgando.
  • Cuando ocurre un error, cierre la instancia de Excel que está utilizando. No es probable que pueda recuperarse de los errores relacionados con Excel y cuanto más tiempo mantenga la instancia, más tiempo usará los recursos.
  • Cuando salga de Excel, asegúrese de proteger ese código de las llamadas recursivas: si los manejadores de excepciones intentan apagar Excel mientras su código ya está en proceso de cerrar Excel, terminará con una instancia de Excel muerta.
  • Llame a GC.Collect() y GC.WaitForPendingFinalizers() inmediatamente después de llamar al método Application.Quit() para asegurarse de que .NET Framework libera todos los objetos COM de Excel inmediatamente.

Editar : esto es después de haber agregado más detalles a su pregunta.

En otherComponent no necesita liberar los objetos Workbook y Document . Estos dos objetos se crean en su primer objeto, lo que implica que el primer objeto es el propietario. Dado que es el primer objeto que posee sus objetos Excel de nivel superior (suponiendo que también tenga un objeto Application algún lugar), su primer objeto puede llamar a otherComponent , pasar en Workbook y Document y luego, al regresar, limpiarlos. Si nunca usa ninguno de estos objetos en su MainComponent , entonces debe crear los objetos relacionados con Excel dentro de otherComponent y limpiarlos allí.

Con la interoperabilidad COM, debe crear sus objetos COM lo más cerca posible del lugar donde los necesita y liberarlos explícitamente tan pronto como sea posible. Esto es especialmente cierto para las aplicaciones de Office.

Hice esta clase para facilitar el uso de objetos COM: este contenedor es desechable, por lo que puede usar el using(...) con sus objetos COM: cuando el ámbito de using está terminado, el contenedor libera el objeto COM.

using System; using System.Runtime.InteropServices; namespace COMHelper { /// <summary> /// Disposable wrapper for COM interface pointers. /// </summary> /// <typeparam name="T">COM interface type to wrap.</typeparam> public class ComPtr<T> : IDisposable { private object m_oObject; private bool m_bDisposeDone = false; /// <summary> /// Constructor /// </summary> /// <param name="oObject"></param> public ComPtr ( T oObject ) { if ( oObject == null ) throw ( new ArgumentNullException ( "Invalid reference for ComPtr (cannot be null)" ) ); if ( !( Marshal.IsComObject ( oObject ) ) ) throw ( new ArgumentException ( "Invalid type for ComPtr (must be a COM interface pointer)" ) ); m_oObject = oObject; } /// <summary> /// Constructor /// </summary> /// <param name="oObject"></param> public ComPtr ( object oObject ) : this ( (T) oObject ) { } /// <summary> /// Destructor /// </summary> ~ComPtr () { Dispose ( false ); } /// <summary> /// Returns the wrapped object. /// </summary> public T Object { get { return ( (T) m_oObject ); } } /// <summary> /// Implicit cast to type T. /// </summary> /// <param name="oObject">Object to cast.</param> /// <returns>Returns the ComPtr object cast to type T.</returns> public static implicit operator T ( ComPtr<T> oObject ) { return ( oObject.Object ); } /// <summary> /// Frees up resources. /// </summary> public void Dispose () { Dispose ( true ); GC.SuppressFinalize ( this ); } /// <summary> /// Frees up resurces used by the object. /// </summary> /// <param name="bDispose">When false, the function is called from the destructor.</param> protected void Dispose ( bool bDispose ) { try { if ( !m_bDisposeDone && ( m_oObject != null ) ) { Marshal.ReleaseComObject ( m_oObject ); m_oObject = null; } } finally { m_bDisposeDone = true; } } } }

Digamos que tengo un componente que está haciendo algo con el objeto Workbook y en algún lugar en el medio de ese cuerpo del método tengo una llamada a algún método de otra clase. Por ejemplo:

public class MainComponent { public void MyMainMethod() { OtherComponent otherComponent = new OtherComponent(); Workbook document; // some work with workbook object // working with document and worksheet objects. otherComponent.MethodCall(document); // some work with workbook object and it''s worksheets. foreach(Worksheet sheet in document.Workheets) // do something with sheet } } public class OtherComponent { public void MethodCall(Workbook document) { string worksheetNames = ""; foreach(Worksheet sheet in document.Worksheets) worksheetNames += sheet.Name; Console.WriteLine(worksheetNames); } }

Y en ese otherComponent.MethodCall (documento); Estoy usando el documento y estoy iterando a través de sus hojas de trabajo.

EDITAR para ser más concreto en la pregunta. ¿Debo llamar a ReleaseCOMObject en el documento y en las Hojas de trabajo en otherComponent.MethodCall (documento) o no?

Nunca tuve una buena explicación sobre cómo debo administrar este código no administrado. Realmente apreciaría si alguien pudiera explicarme esto.