{"id":169,"date":"2026-04-12T14:56:07","date_gmt":"2026-04-12T14:56:07","guid":{"rendered":"https:\/\/rfog.es\/?p=169"},"modified":"2026-04-12T14:56:07","modified_gmt":"2026-04-12T14:56:07","slug":"de-com-a-winrt-evolucion-interoperabilidad-windows","status":"publish","type":"post","link":"https:\/\/rfog.es\/?p=169","title":{"rendered":"De COM a WinRT: La tortuosa evoluci\u00f3n de la interoperabilidad en Windows"},"content":{"rendered":"<p><small><em>Este texto ha sido generado por Gemini 2.5\/3.1 a partir del audio del autor. El contenido y las ideas son \u00edntegramente del autor; la redacci\u00f3n ha sido asistida por IA.<\/em><\/small><\/p>\n<hr \/>\n<p>En el audio anterior os cont\u00e9 todo el parip\u00e9 que hab\u00eda que hacer para acceder a un objeto COM (Common Object Model). Hoy vamos a profundizar en esa historia, viendo c\u00f3mo hemos evolucionado desde un sistema engorroso hasta las promesas de WinRT.<\/p>\n<h2>El engorroso mundo del COM cl\u00e1sico<\/h2>\n<p>Cuando quer\u00edas usar un objeto COM, el compilador de C# se enfrentaba a un proceso complejo. Curiosamente, en su d\u00eda, Borland ten\u00eda esto bastante mejor resuelto, aunque tambi\u00e9n fallaba m\u00e1s. Cada objeto COM ven\u00eda con un fichero IDL (Interface Definition Language) que describ\u00eda qu\u00e9 hac\u00eda, c\u00f3mo cargarlo y c\u00f3mo traducir las llamadas desde tu c\u00f3digo al c\u00f3digo nativo del objeto, que generalmente estaba en C++.<\/p>\n<p>El compilador procesaba este fichero IDL y generaba una serie de clases \u00abenvolventes\u00bb para facilitar el manejo de la interfaz. Sin embargo, mucho trabajo segu\u00eda siendo manual. Ten\u00edas que llamar a <code>IUnknown<\/code>, gestionar punteros y liberar memoria expl\u00edcitamente. 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\u00f3n a medio hacer.<\/p>\n<p>Una de las funcionalidades interesantes era la integraci\u00f3n de men\u00fas. Si tu aplicaci\u00f3n Win32 o MFC ten\u00eda un men\u00fa \u00abArchivo\u00bb, el men\u00fa \u00abArchivo\u00bb de un componente Office, como Word, pod\u00eda fusionarse con el tuyo, mostrando tus opciones y las de Office. Un detalle curioso que demuestra el nivel de integraci\u00f3n que se buscaba.<\/p>\n<h2>C# llega al rescate (parcialmente)<\/h2>\n<p>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 <code>COMVisible<\/code>, y autom\u00e1ticamente est\u00e1 disponible para ser usada por otras aplicaciones. De C# a C# la integraci\u00f3n es transparente y casi instant\u00e1nea. Al a\u00f1adir la referencia a tu proyecto, el sistema de reflexi\u00f3n te permite ver y usar todas las clases y m\u00e9todos p\u00fablicos sin esfuerzo.<\/p>\n<p>El lenguaje se encarga de toda la fontaner\u00eda por debajo, gestionando los <code>IUnknown<\/code> y las referencias por ti. Esto es una capa de abstracci\u00f3n potent\u00edsima 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\u00eda, claro, porque en la pr\u00e1ctica siempre surgen problemas.<\/p>\n<h2>El problema persistente con C++ nativo<\/h2>\n<p>Pero, \u00bfqu\u00e9 pasaba si quer\u00edas acceder a ese objeto COM hecho en C# desde C++ nativo? Volv\u00edamos al punto de partida. Hab\u00eda que generar un fichero (en este caso, WinMD) que, a trav\u00e9s de una herramienta como MIDL.exe, creaba las clases de envoltorio para C++. Y aqu\u00ed empezaban los dolores de cabeza.<\/p>\n<p>MIDL.exe estaba lleno de bugs. A veces, si usabas un objeto en C# que la herramienta no conoc\u00eda, generaba mal las clases. El c\u00f3digo compilaba, el IntelliSense no daba pistas, pero en tiempo de ejecuci\u00f3n, al llamar a esa parte mal definida, el programa reventaba. Era algo muy parecido a los cl\u00e1sicos \u00abRuntime Error\u00bb de Visual Basic. Si adem\u00e1s quer\u00edas usarlo desde Pascal, un COBOL moderno o JavaScript, el proceso era el mismo: crear envoltorios y cruzar los dedos.<\/p>\n<h2>WinRT: \u00bfLa soluci\u00f3n definitiva?<\/h2>\n<p>Aqu\u00ed es donde entra en juego WinRT. Es el siguiente paso evolutivo, una interfaz COM gestionada a trav\u00e9s de ficheros WinMD que define lo que se conoce como una ABI (Application Binary Interface) est\u00e1tica y bien definida. Esto es fundamental en tecnolog\u00edas como .NET Core. El <code>IUnknown<\/code> sigue existiendo, pero el sistema es mucho m\u00e1s moderno.<\/p>\n<p>Para C++, WinRT se presenta como un conjunto de plantillas en ficheros de cabecera, lo que significa que no hay sobrecarga de c\u00f3digo. Microsoft promete que es s\u00faper r\u00e1pido, que la adaptaci\u00f3n es autom\u00e1tica y que la liberaci\u00f3n de memoria tambi\u00e9n es autom\u00e1tica. Se acabaron los punteros manuales. Es, en esencia, la siguiente generaci\u00f3n de COM, dise\u00f1ada para ser s\u00faper f\u00e1cil de usar.<\/p>\n<h2>Un par\u00e9ntesis t\u00e9cnico: El &#8216;Name Mangling&#8217;<\/h2>\n<p>Para entender por qu\u00e9 una ABI est\u00e1tica es tan importante, hay que hablar del <em>name mangling<\/em> en C++. C++ no es un lenguaje de objetos en su ejecuci\u00f3n final; simula la orientaci\u00f3n a objetos pasando un puntero oculto (<code>this<\/code>) a las funciones. Si tienes un m\u00e9todo <code>HazPityCoreDeVoyne<\/code> en la clase A y otro con el mismo nombre en la clase B, \u00bfc\u00f3mo sabe el compilador a cu\u00e1l llamar?<\/p>\n<p>Lo que hace es cambiar los nombres internamente a algo como <code>HazPityCoreDeVoyneClaseA<\/code> y <code>HazPityCoreDeVoyneClaseB<\/code>. Este proceso, el <em>name mangling<\/em>, var\u00eda con cada compilador e incluso con cada versi\u00f3n. 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.<\/p>\n<h2>El escepticismo de siempre: El historial de Microsoft<\/h2>\n<p>La idea de WinRT es absolutamente genial. El problema, para m\u00ed, es que me da mucho repel\u00fas. 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\u00e9s UWP&#8230; y ahora WinRT. Todas las anteriores llegaron llenas de bugs y problemas.<\/p>\n<p>Microsoft es famosa por tener ideas maravillosas y luego tardar a\u00f1os en pulir la implementaci\u00f3n. Justo cuando algo se vuelve estable, deciden cambiarlo. Prometieron una API est\u00e1tica con .NET Core y creo que ya van por la tercera versi\u00f3n de esa promesa \u00abpara siempre\u00bb. Conoci\u00e9ndolos, aunque digan que van a mejorar WinUI y WinRT, me temo que ser\u00e1 m\u00e1s de lo mismo.<\/p>\n<h2>Conclusi\u00f3n: Una idea brillante, una implementaci\u00f3n incierta<\/h2>\n<p>WinRT est\u00e1 dise\u00f1ado 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\u00f3n muy r\u00e1pida que corre por encima y termina haciendo llamadas a Win32.<\/p>\n<p>La idea es chula, pero la pr\u00e1ctica ya la veremos. O mejor dicho, ya se ver\u00e1, porque yo personalmente no creo que lo use. Por lo menos, ahora ya s\u00e9 qu\u00e9 es y c\u00f3mo funciona. Ya veremos si esta vez Microsoft consigue una implementaci\u00f3n robusta desde el principio.<\/p>\n<p>Y con esto cerramos el cap\u00edtulo de WinRT. En el pr\u00f3ximo audio hablaremos sobre WinUI, pero eso ser\u00e1 otra historia. \u00a1No olvid\u00e9is sospechosos, habitualizaros! Adi\u00f3s.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Analizamos la evoluci\u00f3n desde los objetos COM y sus ficheros IDL hasta WinRT, pasando por las simplificaciones de C# y los desaf\u00edos de la interoperabilidad en C++.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[58,57,53,59,52],"class_list":["post-169","post","type-post","status-publish","format-standard","hentry","category-podcastexto","tag-c-2","tag-c","tag-com","tag-interoperabilidad","tag-winrt"],"_links":{"self":[{"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/posts\/169","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/rfog.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=169"}],"version-history":[{"count":1,"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/posts\/169\/revisions"}],"predecessor-version":[{"id":179,"href":"https:\/\/rfog.es\/index.php?rest_route=\/wp\/v2\/posts\/169\/revisions\/179"}],"wp:attachment":[{"href":"https:\/\/rfog.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=169"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rfog.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=169"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rfog.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=169"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}