De COM a WinRT: La tortuosa evolución de la interoperabilidad en Windows

Analizamos la evolución desde los objetos COM y sus ficheros IDL hasta WinRT, pasando por las simplificaciones de C# y los desafíos de la interoperabilidad en C++.

Este texto ha sido generado por Gemini 2.5/3.1 a partir del audio del autor. El contenido y las ideas son íntegramente del autor; la redacción ha sido asistida por IA.


En el audio anterior os conté todo el paripé que había que hacer para acceder a un objeto COM (Common Object Model). Hoy vamos a profundizar en esa historia, viendo cómo hemos evolucionado desde un sistema engorroso hasta las promesas de WinRT.

El engorroso mundo del COM clásico

Cuando querías usar un objeto COM, el compilador de C# se enfrentaba a un proceso complejo. Curiosamente, en su día, Borland tenía esto bastante mejor resuelto, aunque también fallaba más. Cada objeto COM venía con un fichero IDL (Interface Definition Language) que describía qué hacía, cómo cargarlo y cómo traducir las llamadas desde tu código al código nativo del objeto, que generalmente estaba en C++.

El compilador procesaba este fichero IDL y generaba una serie de clases «envolventes» para facilitar el manejo de la interfaz. Sin embargo, mucho trabajo seguía siendo manual. Tenías que llamar a IUnknown, gestionar punteros y liberar memoria explícitamente. Era un sistema lento, basado en punteros a punteros, y si se te olvidaba liberar algo, los problemas eran horrorosos. Digamos que era una solución a medio hacer.

Una de las funcionalidades interesantes era la integración de menús. Si tu aplicación Win32 o MFC tenía un menú «Archivo», el menú «Archivo» de un componente Office, como Word, podía fusionarse con el tuyo, mostrando tus opciones y las de Office. Un detalle curioso que demuestra el nivel de integración que se buscaba.

C# llega al rescate (parcialmente)

Con la llegada de C# y el framework .NET, las cosas se simplificaron enormemente. Cualquier clase de C# (o Visual Basic .NET) puede marcarse como COMVisible, y automáticamente está disponible para ser usada por otras aplicaciones. De C# a C# la integración es transparente y casi instantánea. Al añadir la referencia a tu proyecto, el sistema de reflexión te permite ver y usar todas las clases y métodos públicos sin esfuerzo.

El lenguaje se encarga de toda la fontanería por debajo, gestionando los IUnknown y las referencias por ti. Esto es una capa de abstracción potentísima que permite que tu componente funcione sin importar si se ejecuta en un servidor remoto, en un procesador ARM o en un x86. En teoría, claro, porque en la práctica siempre surgen problemas.

El problema persistente con C++ nativo

Pero, ¿qué pasaba si querías acceder a ese objeto COM hecho en C# desde C++ nativo? Volvíamos al punto de partida. Había que generar un fichero (en este caso, WinMD) que, a través de una herramienta como MIDL.exe, creaba las clases de envoltorio para C++. Y aquí empezaban los dolores de cabeza.

MIDL.exe estaba lleno de bugs. A veces, si usabas un objeto en C# que la herramienta no conocía, generaba mal las clases. El código compilaba, el IntelliSense no daba pistas, pero en tiempo de ejecución, al llamar a esa parte mal definida, el programa reventaba. Era algo muy parecido a los clásicos «Runtime Error» de Visual Basic. Si además querías usarlo desde Pascal, un COBOL moderno o JavaScript, el proceso era el mismo: crear envoltorios y cruzar los dedos.

WinRT: ¿La solución definitiva?

Aquí es donde entra en juego WinRT. Es el siguiente paso evolutivo, una interfaz COM gestionada a través de ficheros WinMD que define lo que se conoce como una ABI (Application Binary Interface) estática y bien definida. Esto es fundamental en tecnologías como .NET Core. El IUnknown sigue existiendo, pero el sistema es mucho más moderno.

Para C++, WinRT se presenta como un conjunto de plantillas en ficheros de cabecera, lo que significa que no hay sobrecarga de código. Microsoft promete que es súper rápido, que la adaptación es automática y que la liberación de memoria también es automática. Se acabaron los punteros manuales. Es, en esencia, la siguiente generación de COM, diseñada para ser súper fácil de usar.

Un paréntesis técnico: El ‘Name Mangling’

Para entender por qué una ABI estática es tan importante, hay que hablar del name mangling en C++. C++ no es un lenguaje de objetos en su ejecución final; simula la orientación a objetos pasando un puntero oculto (this) a las funciones. Si tienes un método HazPityCoreDeVoyne en la clase A y otro con el mismo nombre en la clase B, ¿cómo sabe el compilador a cuál llamar?

Lo que hace es cambiar los nombres internamente a algo como HazPityCoreDeVoyneClaseA y HazPityCoreDeVoyneClaseB. Este proceso, el name mangling, varía con cada compilador e incluso con cada versión. Si creas una DLL con Visual Studio 2017, puede que no sea compatible con una compilada con Visual Studio 2019 o con el compilador de Intel. WinRT soluciona esto al establecer una ABI fija y universal, simplificando radicalmente la interoperabilidad.

El escepticismo de siempre: El historial de Microsoft

La idea de WinRT es absolutamente genial. El problema, para mí, es que me da mucho repelús. Es el siguiente paso en la saga de las APIs para la tienda de Windows. Primero tuvimos Silverlight, luego las apps de la tienda, después UWP… y ahora WinRT. Todas las anteriores llegaron llenas de bugs y problemas.

Microsoft es famosa por tener ideas maravillosas y luego tardar años en pulir la implementación. Justo cuando algo se vuelve estable, deciden cambiarlo. Prometieron una API estática con .NET Core y creo que ya van por la tercera versión de esa promesa «para siempre». Conociéndolos, aunque digan que van a mejorar WinUI y WinRT, me temo que será más de lo mismo.

Conclusión: Una idea brillante, una implementación incierta

WinRT está diseñado para funcionar con .NET y se puede usar desde C++ nativo simplemente incluyendo una cabecera. La sintaxis puede ser un poco barroca, pero es funcional. Es importante aclarar que WinRT no sustituye a Win32; es una capa de abstracción muy rápida que corre por encima y termina haciendo llamadas a Win32.

La idea es chula, pero la práctica ya la veremos. O mejor dicho, ya se verá, porque yo personalmente no creo que lo use. Por lo menos, ahora ya sé qué es y cómo funciona. Ya veremos si esta vez Microsoft consigue una implementación robusta desde el principio.

Y con esto cerramos el capítulo de WinRT. En el próximo audio hablaremos sobre WinUI, pero eso será otra historia. ¡No olvidéis sospechosos, habitualizaros! Adiós.