Acerca de...
El equipo
Encuestas
WinTablets

Encuesta

Si las WINTABLETs no pudiesen ejecutar aplicaciones de escritorio, ¿las seguirías usando?

Cargando ... Cargando ...

últimas entradas importantes

Categorías

Archivos

14
Sep 2014
DesarrolloInteroprfogdev

Mezclar código nativo y manejado en aplicaciones de la Tienda de Windows y Windows Phone

¿Cómo puedo añadir una DLL nativa a mi código en Windows Phone o Windows 8? ¿Tengo que hacer algo especial para que funcione? ¿Me va a ayudar C++/CX? ¿Qué pasa si no funciona, incluso con aquellas instaladas desde NuGet?

A todas esas preguntas, y a alguna más, os voy a responder en esta entrada. Vamos allá.

De todos modos, si has venido aquí para responder a la duda de la excepción de tipo System.TypeLoadException o System.TypeInitializationException durante la ejecución de un componente instalado a través de NuGet, ve al final de la entrada.

Ya lo he comentado en otros sitios, en .NET todas las clases son objetos COM. COM es la evolución de una tecnología que nació en las primeras versiones de Windows para el intercambio de datos.

Primero se llamó DDE, luego se transformó en OLE, siguió subiendo de versión a OLE2, OCX, COM, COM+, DCOM…

En su momento la idea era competir con una cosa llamada CORBA que fue un intento de estandarizar el modelo de componentes. La idea de CORBA (y de todas sus variantes, incluidas las de Microsoft) es tener un conjunto de componentes autónomos que sean capaces de ofrecer de forma estándar sus servicios y que sea el propio componente el que ofrezca la forma sobre cómo acceder a ellos.

Básicamente, por lo menos en la implementación de Microsoft, lo que ocurren es que cuando quieres usar un componente instalado en el sistema, te vas al catálogo de componentes, eliges el que quieras, y comienzas una batería de preguntas, de forma que, al final, obtienes su interfaz pública con todos sus métodos y cómo se llaman.

A partir de ahí ya puedes usarlo en tu código. No voy a entrar en detallas sobre cómo se hace eso. Es complicado, abstruso, retorcido y necesita de ciertas herramientas especiales que se deben ejecutar en tu programa para que todo eso sea funcional. Además, a fecha de hoy está obsoleto.

(En el ínterin, y a título personal, diré que todo eso es un galimatías bastante infumable cuyo único propósito era el de posibilitar la comunicación remota entre diferentes arquitecturas de procesadores y de sistemas operativos. Creo que nadie llegó a usarlo nunca del todo. En su momento, la parte más útil de todo esto era embeber Word o Excel dentro de tu aplicación.)

Todo aquello ha ido evolucionando, y lo que en principio necesitaba a un programador especialista en todo aquello, a fecha de hoy es enormemente sencillo, sobre todo en el mundo .NET y en las aplicaciones de la tienda de Windows y Windows Phone.

De hecho, como ya he comentado, cualquier clase de .NET es un objeto COM listo para ser utilizado de cualquier modo. Si quieres usarlo desde otra clase .NET, simplemente lo llamas, lo instancias o haces lo que quieras con él.

Por ejemplo, la forma que tiene Visual Studio de mostrarnos el IntelliSense es utilizar la potencia COM de cada clase .NET para desplegar todos sus métodos, objetos y demás mediante reflexión, que es la técnica actual para obtener de forma dinámica qué métodos y qué clases hay dentro de un ensamblado .NET (ya sea una DLL o un EXE). Y no es complicado de hacer. Aquí tenéis la referencia sobre el tema.

Por lo tanto, cuando uno añade una DLL .NET a un proyecto existente, tan sólo hay que añadir la referencia de la misma al proyecto de Visual Studio en el que se quiera usar. La magia del IDE y del compilador hacen el resto, que es registrar el fichero durante la carga de la aplicación para que nosotros sólo tengamos que usarla.

¿Pero qué pasa con una DLL nativa? En principio no puedes usarla de forma nativa. Es decir, no puedes dejarla caer en la sección de referencias de tu proyecto, armar un envoltorio mediante Interop a través de una clase .NET y usarla. No en las aplicaciones de la tienda de Windows y de Windows Phone.

[Nota: al menos yo creo que no, pero no estoy totalmente seguro de ello ya que no he probado a hacerlo.]

Bien, ¿entonces cómo?

A través de C++/CX. ¿Qué es C++/CX? Nada más y nada menos que el C++ clásico (y no tan clásico ya que Microsoft está soportando C++11 casi en su totalidad) pero con un sugar syntax para la parte COM que debe ser compatible con .NET.

Es algo similar al C++/CLI con la diferencia de que el primero genera código nativo y el segundo código MSIL que luego debe ser compilado por la máquina virtual .NET en tiempo de ejecución.

Si sabes C++, la parte CX la aprendes en una tarde, menos si ya sabías C++/CLI. Básicamente todas las clases CX compatibles con .NET han de ser sealed y del tipo ref class. No hay punteros sino “tejaícos” (el circunflejo), que devuelve una referencia en lugar de un puntero, la parte pública de la misma debe usar y devolver tipos válidos de la tienda de Windows y poco más. De hecho en la parte privada de la clase puedes usar cualquier cosa nativa siempre que esté dentro de las API Win32 autorizadas, que son casi todas las importantes.

Tenemos, pues, que envolver nuestra DLL en otra escrita en C++/CX y llamar a los métodos de esta última, que a su vez usarán los de la nativa.

O si estamos construyendo un componente para la tienda que necesite de código nativo, simplemente declaramos una interfaz pública compatible y usamos el API de Win32 sin más dentro de los métodos, teniendo cuidado de convertir los tipos entre los nativos y los de la tienda cuando haya que devolverlos.

Básicamente es lo que hace el propio interfaz .NET de las aplicaciones de la tienda de Windows cuando se programa en C# ya que las tripas están escritas en C++/CX.

Un ejemplo práctico. Vamos a obtener el nombre que le hemos dado a nuestro Windows Phone cuando lo enchufamos al ordenador, servicio que no está disponible en las API Modern UI de Windows Phone. Para ello vamos a seguir la vía didáctica y no la que deberíamos seguir si estuviéramos haciendo esto, que es primero investigar dónde está el método nativo que obtiene dicho valor y si esa llamada al API de Win32 es válida o no para una aplicación de la tienda.

Por lo tanto el primer paso es añadir un proyecto del tipo “Windows Runtime Component” desde la rama de C++ de nuestro gestor de proyectos, que nos va a crear un esqueleto de proyecto en C++/CX con dos ficheros, pch.cpp y pch.h. Hay más ficheros, pero estos son los únicos que nos interesan.

Imagen del portapapeles 6

Esos dos ficheros dan soporte a lo que se llama cabeceras precompiladas, que es una técnica o patrón o como queráis llamarlo que acelera de forma muy singular el proceso de compilación del código escrito en C++, pero no vamos a entrar en más detalles sobre ello que tener que añadir los siguientes ficheros a pch.h, dejando el correspondiente cpp sin tocar:

Imagen del portapapeles 5

Una vez hecho esto, renombramos la pareja de ficheros Class1.cpp y Class1.h por NetHelper.cpp y NetHelper.h, aunque podríamos dejar sin tocar los nombres. No obstante, es una buena práctica poner los nombres correctos.

Podríamos compilar ahora el proyecto y obtendríamos un componente nativo que se puede usar en Windows Phone, con una clase pública llamada Class1 dentro del espacio de nombres NetHelper, pero vamos a añadir ya nuestro código.

Sustituimos el contenido de NetHelper.h por el siguiente:

Imagen del portapapeles 4

SI os fijáis, tenemos aquí todos los elementos de un componente C++/CX. Clase sellada de tipo  ref, que tiene una propiedad estática que devuelve una referencia a una cadena de Platform, que es el espacio de nombres base de las aplicaciones de la tienda escritas en C++/CX. El código interior a la propiedad es la forma que tenemos en el lenguaje de definir una propiedad.

Y finalmente, la implementación, que va en NetHelper.cpp:

Imagen del portapapeles 3

Aquí podemos observar a C++/CX en todo su esplendor. El método PhoneName::get() que implementa el getter de la propiedad es un envoltorio que recibe parámetros de la tienda de Windows (en este caso ninguno) y que devuelve un parámetro del mismo tipo. El cuerpo del método, salvo la última línea, que convierte una cadena de C en un string adecuado, es código no C++, sino C, que es la forma de hablar con Win32.

(Nota: el código del ejemplo está sacado de aquí. Lo que yo he hecho ha sido explicar con más detalle el citado artículo de CodeProject).

Si construimos el proyecto, y compila, hemos obtenido una DLL que puede ser usada en un proyecto de Windows Phone como si estuviera escrito en C#.

No hay nada en contra de repetir lo mismo para la tienda de Windows 8, incluso bajo una aplicación universal. Tan solo hay que elegir el tipo de proyecto adecuado, en este caso bajo la rama de Windows Store dentro de C++.

El último paso para utilizar NetHelper en otra aplicación, es añadir la referencia al mismo en dicha aplicación, lo que se hace con el botón derecho sobre la carpeta “Referencias” en el Explorador de Soluciones, añadiendo la DLL a mano o a través de las disponibles en la ventana del “Manejador de Referencias”. Quizás haya que recompilar la solución para que nuestro proyecto esté disponible.

Imagen del portapapeles 2

Finalmente, el uso de todo esto es idéntico al de cualquier otra clase en C#. La única diferencia es interna, o más bien que el código que se va a ejecutar ha sido creado por nosotros en lugar de por Microsoft, porque es así como funciona por dentro la plataforma de las aplicaciones para las tiendas y cómo se llama a código nativo desde los envoltorios escritos en C# que nos ofrecen los SDK de Windows Phone y de Windows.

Imagen del portapapeles

Fijaos que hasta ahora no hemos hablado ni de COM, ni de objetos activables, ni nada que se le parezca. Dad gracias de que sea así, porque la otra opción… Digamos que si esta os parece complicada, no os digo la de usar el compilador de MIDL, crear el fichero de exportación WINMD, realizar el registro de los objetos declarados de forma manual y toda la parafernalia del COM.

Ahora es cuando viene el tío de la rebaja. Si seguís todos los pasos descritos aquí, lo más seguro es que no podáis usar el código de la última captura. Si el IDE y el compilador os encuentra la referencia (que podría no hacerlo incluso después de reconstruir la solución completa), es muy posible que a la hora de ejecutar ese código obtengáis una retahíla de excepciones encadenadas, empezando por una de tipo

 

A first chance exception of type ‘System.TypeLoadException’ occurred in NetHelper.dll

Additional information: Requested Windows Runtime type ‘ClrCompression.ZLibInterop’ is not registered.

 

Seguida por otra de

 

A first chance exception of type ‘System.TypeInitializationException’ occurred in NetHelper.dll

Additional information: The type initializer for ‘System.IO.Compression.Interop’ threw an exception.

 

Y alguna que otra más. Estamos ante un bug del compilador de C# que vamos a explicar cómo sortear en una segunda entrada.

Por RFOG | 12 Comentarios | Enlaza esta entrada

12 Comentarios

arcali
Enviado el 14/09/2014 a las 13:41 | Permalink

Ante todo, he de dar las gracias a RFOG por su articulo. Se nota que está trabajado y que seguro que es interesantísimo, no lo dudo, y una persona que desinteresadamente escribe un articulo así para los demás, se merece un muchas gracias.
Yo creía que al menos, aunque ni de cerca experimentado, era un aficionado más bien avanzado en temas de informática. Bien es cierto que desde q1ue me empezó a interesar esto he manejado el entorno mac y en el móvil android.
Pero después de leer el articulo detenidamente y casi dos veces 8por aquello de intentar entender al menos algo), me siento totalmente frustrado. Me acabo de dar cuenta de que no tengo ni puta idea de informática, ya que no he entendido ni una frase completa.
Decidme una cosa, ¿soy realmente un principiante absoluto en informática, o es este un articulo muy técnico, para gente profesional de la informática?
Supongo que tiene que haber artículos para todos los niveles, pero, y no tiene ningún fin de critica, ¿mi frustración es justificada no?.
Sea lo que sea, gracias RFOG por tú completo articulo y por tu interés en enseñar. Espero que continuando leyendo esta pagina me empiece a enterar algo de la informática, que me apasiona. :-?
Un saludo a todos.

    Enviado el 14/09/2014 a las 13:50 | Permalink

    No te preocupes, acá somos como los cines, ponemos pelis para todas las edades. Los artículos de Rafa son para adultos, sin problemas del corazón.

    RFOG
    Enviado el 14/09/2014 a las 15:05 | Permalink

    Lo cierto es que es una entrada hardcore añadida a que versa sobre desarrollo.

    Pero sí, es de desarrollo, y muy específica. Si no eres desarrollador de Windows 8 o de Windows Phone 8.x, te va a sonar a chino, y aun siéndolo, a veces también. Pero como dice el refrán, nobleza obliga.

    Mi trabajo actual es la creación y mantenimiento de una de las aplicaciones más complejas que hay a fecha de hoy en la tienda de Windows Phone. Quizás no haya dos o tres equivalentes, entre las que podemos citar a Skype (que pese a ser de Microsoft no implementa al completo lo que la mía), y otras que permitan chat y llamadas por teléfono por VOIP a clientes propios y a terceros (fijos y móviles alrededor del mundo, con un coste más o menos fijo).

    Esta entrada originalmente no estaba planteada así, sino que iba a ser la solución a los últimos párrafos, pero como me pasa muy a menudo, mi faceta didáctica se impuso a la de simplemente publicar la solución al problema. Comentar que la gente de Microsoft España, los desarrolladores que nos dan soporte a los externos, no sabían ni por dónde meterle mano a mi problema… que como casi siempre, terminé solucionando por mi mismo con apenas ayuda. Sobre este problema no hay nada publicado en ningún lado, y por supuesto me pidieron que publicara algo al respecto. Aquí, aunque no descarto que la segunda parte de esta entrada vaya también en la MSDN en español, como ya hay otros textos míos allí.

    Y me das una idea para publicar un artículo sobre la historia de la informática de los años noventa que ya, si esta te parece hardcore… :evil:

      RFOG
      Enviado el 14/09/2014 a las 15:07 | Permalink

      Bueno, en resumen, que no pasa nada si no te enteras de nada y no eres programador de Windows Phone.

      Enviado el 14/09/2014 a las 21:18 | Permalink

      UppTalk funciona de fábula. Al menos en Android. En Windows Phone la he probado menos.

      No seas modesto.

      Hoy mismo he tenido una llamada de 40 minutos por UppTalk (de UppTalk a Upptalk) sin un solo corte.

      arcali
      Enviado el 15/09/2014 a las 10:07 | Permalink

      Menos mal. Estaba asustándome de mi bajísimo nivel, bueno no es que tenga mucho, pero es que me recordaba a cuando empezaba eso de la informática más popular , tendría yo unos 30 años o así, y me parecía que estaba leyendo en chino. Recuerdo que pensé: “yo nunca leeré sobre esto, es imposible entender ese lenguaje de chinos” .
      Y mira después empecé a cogerle el gusto y ahora me paso todo mi tiempo libre leyendo al respecto.
      Lo próximo será entender algo de códigos de programación y de la misma.
      Enhorabuena por tu articulo.
      Un saludo para ti. :wink:

        Quique
        Enviado el 15/09/2014 a las 19:38 | Permalink

        Bienvenido al club de los que no entendemos nada de programación.

        Las computadoras son las herramientas más flexibles que existen. Asi que uno puede ser un experto en una cosa e inútil en otras.
        Por ejemplo, yo me considero un usuario experto de Word, PowerPoint, Excel y OneNote. Probablemente sepa más de estas cosas que RFGO, pero no tengo idea de programación.

        Un diseñador gráfico probablemente sepa poco y nada de planificación, pero mucho de Photoshop. Y viceversa.

        Un ejemplo interesante es el de Excel. Probablemente no exista ningún ser humano en la tierra que lo domine totalmente. Es tan amplio que se puede ser experto en todo lo que tiene que ver con contabilidad en Excel y ser un inepto en todo lo que tiene que ver con estadísticas, y viceversa.

        Así es la industria de la informática. Es imposible que un ser humano lo abarque todo. Y eso no implica que uno no sepa nada de computación.

Enviado el 14/09/2014 a las 13:59 | Permalink

Como siempre otra excelente entrega de Rafa. Cuando veo en las cosas que está metido hace parecer las mías cosas de principiante.

arcali
Enviado el 14/09/2014 a las 14:06 | Permalink

Ya imagino que muchos habrán entendido, incluso que es interesantísimo, y lógicamente no me quejo. Todo saber, no ocupa lugar, y ciertamente, el que quiera ir a una película de acción, que no se queje de que haya películas de arte y ensayo en los cines. Y yo no me quejo, solo que me he quedado asustado de no haber entendido ni “papa”.
Pienso leer el articulo unas cuantas veces, para intentar empezar a enterarme algo más profundamente de este tema.
Soy un recién nacido en esto de las informática.¡ Qué bien, al menos me he quitado cincuenta y tantos años de encima en algo! :wink:
Un saludo.

    Enviado el 14/09/2014 a las 14:10 | Permalink

    Es que cuando las cosas van a las profundidades del Código es cuando de verdad se es un informático. Los demás somos tan solo aficionados. 8) 8)

ender2004 flozanoc
Enviado el 14/09/2014 a las 16:22 | Permalink

Simplemente “Sublime”, y me ha dado idea para un problema que tuve en mi primera aplicación y creo que así podre solucionar, aunque esperare a leer la segunda entrega.
Gracias Rafa

Martín Romania
Enviado el 17/09/2014 a las 23:13 | Permalink

Buenísimo artículo,
En cuanto a lo de entenderlo…. no te preocupes. Yo llevo una pila de años programando, no al nivel de RFOG, y no te creas que lo acabo de entender. Me lo voy a poner como tarea a ver si soy capaz de reproducirlo el fin de semana
un saludo y muy buen artículo

Deja un comentario  

Tu email nunca se publica o se comparte. Los campos obligatorios están marcados con *

*
*
:wink: :-| :-x :twisted: :) 8-O :( :roll: :-P :oops: :-o :mrgreen: :lol: :idea: :-D :evil: :cry: 8) :arrow: :-? :?: :!:
Puedes usar las siguientes etiquetas y atributos HTML:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

contacto@wintablet.info tema WinTablet.info por Ángel García (Hal9000)