Interoperabilidad con COM y wrappers invocables en tiempo de ejecución
Consuma componentes COM desde C# con RCW, importe bibliotecas de tipos y gestione excepciones HRESULT.
Interoperabilidad con COM y wrappers invocables en tiempo de ejecución es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 4 lecciones en total.
¿Qué es la interoperabilidad con COM?
COM (Component Object Model) es el estándar heredado de interfaz binaria de Microsoft, que todavía se usa en Office, Windows Shell, las API heredadas de DirectX y muchas herramientas empresariales. .NET puede consumir componentes COM mediante wrappers de interoperabilidad que traducen entre objetos administrados e interfaces COM.
Runtime Callable Wrappers (RCW)
Cuando accede a un objeto COM desde .NET, el CLR crea un Runtime Callable Wrapper (RCW): un proxy administrado que envuelve el objeto COM. El RCW gestiona automáticamente el recuento de referencias (AddRef/Release), los subprocesos de apartment y el marshalling entre los tipos COM y .NET.
// The RCW is created automatically when you instantiate a COM class
// via a registered ProgID or CLSID
// Example: create an Excel Application COM object
Type excelType = Type.GetTypeFromProgID("Excel.Application")!;
object excelApp = Activator.CreateInstance(excelType)!;
// excelApp is an RCW — the CLR wraps the underlying IDispatch COM object
// COM AddRef is called; CLR tracks references
Console.WriteLine(excelApp.GetType().Name); // ApplicationClassImportación de bibliotecas de tipos (TLB)
La herramienta tlbimp.exe (Type Library Importer) lee una biblioteca de tipos COM (.tlb o integrada en .dll) y genera un ensamblado de interoperabilidad de .NET con clases RCW fuertemente tipadas y definiciones de interfaces.
// From a Developer Command Prompt:
// tlbimp MyComLib.dll /out:MyComLib.Interop.dll
// Or reference via Visual Studio:
// Add Reference → COM → Microsoft Excel 16.0 Object Library
// → Generates Microsoft.Office.Interop.Excel.dll automatically
// The generated Interop assembly contains:
// - Interface types (matching COM vtable layout)
// - Co-class wrappers (implement the interfaces)
// - Enum types (from the type library)
// - Delegate types for COM event sinksUso de un objeto COM mediante un ensamblado de interoperabilidad
Una vez que hace referencia al ensamblado de interoperabilidad, los tipos COM se comportan como tipos .NET normales. Una llamada a un método se traduce mediante el RCW a un despacho a través de la vtable de COM. Libere siempre correctamente los objetos COM para evitar fugas de recursos.
using Microsoft.Office.Interop.Excel;
Application excel = new Application();
excel.Visible = false;
Workbooks books = excel.Workbooks;
Workbook wb = books.Add();
Worksheet ws = (Worksheet)wb.Sheets[1];
((Range)ws.Cells[1, 1]).Value = "Hello, COM!";
wb.SaveAs(@"C:\Temp\test.xlsx");
wb.Close();
// Release COM RCW explicitly
Marshal.ReleaseComObject(ws);
Marshal.ReleaseComObject(wb);
Marshal.ReleaseComObject(books);
excel.Quit();
Marshal.ReleaseComObject(excel);Marshal.ReleaseComObject
COM usa el recuento de referencias: AddRef/Release. El RCW llama a Release solo cuando el GC lo recopila, lo que puede ocurrir mucho más tarde. Llame a Marshal.ReleaseComObject() para reducir inmediatamente el recuento de referencias del RCW y liberar el objeto COM sin esperar al GC.
// Pattern: release COM objects in finally block
Application? excel = null;
Workbook? wb = null;
try
{
excel = new Application();
wb = excel.Workbooks.Add();
// ... do work ...
}
finally
{
if (wb != null) Marshal.ReleaseComObject(wb);
if (excel != null)
{
excel.Quit();
Marshal.ReleaseComObject(excel);
}
// Force GC to clean up any remaining RCWs
GC.Collect();
GC.WaitForPendingFinalizers();
}HRESULT y excepciones COM
Los métodos COM devuelven valores HRESULT para indicar si la operación se realizó correctamente o falló. El RCW comprueba automáticamente el HRESULT y produce una COMException (o una excepción más específica) cuando indica un error. Puede gestionarlas con un bloque try/catch normal.
try
{
// COM method that might fail
Workbook wb = excel.Workbooks.Open(@"C:\missing.xlsx");
}
catch (COMException ex) when (ex.HResult == unchecked((int)0x800A03EC))
{
// Excel-specific HRESULT for file not found
Console.WriteLine($"Excel error: {ex.Message}");
}
catch (COMException ex)
{
// General COM failure
Console.WriteLine($"COM error 0x{ex.HResult:X8}: {ex.Message}");
}Enlace tardío con dynamic
Si no dispone de una biblioteca de tipos ni de un ensamblado de interoperabilidad, puede usar la palabra clave dynamic de C# para realizar un despacho COM con enlace tardío (IDispatch). Es más lento, ya que los identificadores de despacho se resuelven en tiempo de ejecución, pero no requiere wrappers generados.
// Late-bound COM via dynamic — no interop DLL needed
Type type = Type.GetTypeFromProgID("Word.Application")!;
dynamic word = Activator.CreateInstance(type)!;
word.Visible = false;
dynamic docs = word.Documents;
dynamic doc = docs.Add();
doc.Content.Text = "Late-bound COM example";
doc.SaveAs2(@"C:\Temp\test.docx");
doc.Close();
word.Quit();
Marshal.ReleaseComObject(doc);
Marshal.ReleaseComObject(docs);
Marshal.ReleaseComObject(word);Receptores de eventos COM
Los objetos COM desencadenan eventos mediante puntos de conexión. El ensamblado de interoperabilidad genera interfaces de receptores de eventos. Suscríbase mediante delegados y eventos normales de .NET; el RCW gestiona la infraestructura COM de IConnectionPoint.
using Microsoft.Office.Interop.Excel;
Application excel = new Application();
excel.Visible = true;
// Subscribe to COM event via generated event wrapper
excel.WorkbookBeforeClose += (wb, ref cancel) =>
{
Console.WriteLine($"Closing: {wb.Name}");
// Set cancel = true to prevent close
};
excel.WorkbookOpen += (wb) =>
{
Console.WriteLine($"Opened: {wb.Name}");
};
// Open a workbook to trigger events
excel.Workbooks.Open(@"C:\Temp\test.xlsx");Apartments COM: STA frente a MTA
Muchos componentes COM, especialmente los relacionados con la interfaz de usuario, como Office, requieren un Single-Threaded Apartment (STA). Marque siempre los subprocesos que creen objetos COM STA con [STAThread] (Main) o establezca el estado del apartment del subproceso antes de iniciarlo.
// Console apps default to MTA — COM Office automation requires STA
// Option 1: Mark Main with [STAThread]
[STAThread]
static void Main()
{
var excel = new Microsoft.Office.Interop.Excel.Application();
// ...
}
// Option 2: Run on an STA thread manually
Thread staThread = new Thread(() =>
{
var excel = new Microsoft.Office.Interop.Excel.Application();
// ...
excel.Quit();
Marshal.ReleaseComObject(excel);
});
staThread.SetApartmentState(ApartmentState.STA);
staThread.Start();
staThread.Join();ComImport y declaraciones COM manuales
Puede declarar interfaces COM manualmente mediante los atributos [ComImport], [Guid] y [InterfaceType], lo que resulta útil cuando no existe una biblioteca de tipos o solo necesita un subconjunto de una API COM grande.
[ComImport]
[Guid("00000000-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IUnknown
{
void QueryInterface(ref Guid riid, out IntPtr ppvObject);
int AddRef();
int Release();
}
// Declare a specific COM interface you want to consume:
[ComImport]
[Guid("0000010C-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPersist
{
void GetClassID(out Guid pClassID);
}Comprobación rápida
¿Cuál es la finalidad de un Runtime Callable Wrapper (RCW) en la interoperabilidad de COM con .NET?
Resumen: interoperabilidad con COM y Runtime Callable Wrappers
Aspectos clave:
- RCW = proxy administrado que envuelve un objeto COM; el CLR crea uno automáticamente para cada objeto COM
- Use
tlbimp.exeo las referencias de Visual Studio para generar ensamblados de interoperabilidad fuertemente tipados - Llame a
Marshal.ReleaseComObject()para liberar inmediatamente los objetos COM (no espere al GC) - Los errores COM aparecen como
COMExceptioncon el HRESULT original dynamicpermite realizar despachos COM con enlace tardío sin un ensamblado de interoperabilidad- Los componentes COM de Office y de la interfaz de usuario requieren un subproceso STA; use
[STAThread]o establezca el estado del apartment
Preguntas frecuentes
¿La lección «Interoperabilidad con COM y wrappers invocables en tiempo de ejecución» es gratis?
Sí — el texto completo de «Interoperabilidad con COM y wrappers invocables en tiempo de ejecución» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Interoperabilidad con COM y wrappers invocables en tiempo de ejecución»?
Consuma componentes COM desde C# con RCW, importe bibliotecas de tipos y gestione excepciones HRESULT. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C# Academy?
No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.
¿Cuánto tiempo toma la lección «Interoperabilidad con COM y wrappers invocables en tiempo de ejecución»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C# Academy?
Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Fundamentos de P/Invoke
- LibraryImport y P/Invoke generado desde el código fuente
- Código no seguro, punteros y búferes fijos
- Interoperabilidad con COM y wrappers invocables en tiempo de ejecución