Aplicaciones de Windows
Collapse the table of content
Expand the table of content

Tutorial: Crear en C++ un componente básico de Windows en tiempo de ejecución y llamarlo desde JavaScript o C#

 

Publicado: abril de 2016

Este tutorial muestra cómo crear un componente básico DLL de Windows en tiempo de ejecución que se pueda llamar desde JavaScript, C# o Visual Basic. Antes de iniciar este tutorial, asegúrate de familiarizarte con conceptos tales como la interfaz binaria abstracta (ABI), las clases ref y Extensiones de componentes de Visual C++ que facilitan el trabajo con las clases ref. Para obtener más información, consulte Crear componentes de Windows en tiempo de ejecución en C++ y Referencia del lenguaje Visual C++ (C++-CX).

En este ejemplo, se crea en primer lugar el proyecto de componente, pero se podría crear el proyecto de JavaScript primero. El orden no importa.

Ten en cuenta que la clase principal del componente contiene ejemplos de definiciones de propiedades y métodos, así como una declaración de evento. Estos se proporcionan solo para mostrar cómo se hizo. No son necesarios y, en este ejemplo, vamos a reemplazar todo el código generado con nuestro propio código.

Para crear el proyecto de componente de C++

  1. En la barra de menús de Visual Studio, elija Archivo, Nuevo, Proyecto.

  2. En el cuadro de diálogo Nuevo proyecto, en el panel de la izquierda, expande Visual C++ y selecciona el nodo correspondiente a aplicaciones de la Tienda Windows.

  3. En el panel central, selecciona Componente de Windows en tiempo de ejecución y, a continuación, asigna al proyecto el nombre WinRT_CPP.

  4. Elija el botón Aceptar.

Para agregar una clase activable al componente

  1. Una clase activable es aquella que el código de cliente puede crear utilizando una expresión new (New en Visual Basic o ref new en C++). En el componente, se declara como public ref class sealed. De hecho, los archivos Class1.h y .cpp ya tienen una clase ref. Puede cambiar el nombre, pero en este ejemplo usaremos el nombre predeterminado: Class1. Puede definir clases ref adicionales o clases regulares en el componente si es necesario. Para obtener más información sobre las clases ref, consulta Sistema de tipos (C++/CX).

Para agregar las directivas #include necesarias

  • Agrega estas directivas #include a Class1.h:

    collection.h es el archivo de encabezado para las clases concretas de C++ como Platform::Collections::Vector (Clase) y Platform::Collections::Map (Clase), que implementan las interfaces independientes del lenguaje definidas por Windows en tiempo de ejecución. Los encabezados amp se utilizan para ejecutar cálculos en la GPU. No tienen un equivalente en Windows en tiempo de ejecución, lo cual no es un problema dado su carácter privado. Normalmente, por motivos de rendimiento se debe utilizar código C++ conforme a las normas ISO y bibliotecas estándar internamente dentro del componente; únicamente es necesario expresar la interfaz de Windows en tiempo de ejecución mediante tipos de Windows en tiempo de ejecución.

Para agregar un delegado en el ámbito de espacio de nombres

  1. Un delegado es una construcción que define los parámetros y el tipo de valor devuelto para los métodos. Un evento es una instancia de un tipo determinado de delegado, y cualquier método de controlador de eventos que se suscriba al evento debe tener la signatura especificada en el delegado. El código siguiente define un tipo de delegado que toma un valor int y devuelve void. A continuación, el código declara un event público de este tipo; esto permite al código de cliente proporcionar métodos que se invocan cuando se desencadena el evento.

    Agrega la siguiente declaración de delegado en el ámbito de espacio de nombres en Class1.h, justo antes de la declaración de Class1.

    System_CAPS_tipSugerencia

    Si el código no se alinea correctamente al pegarlo en Visual Studio, simplemente presiona Ctrl+K+D para corregir la sangría de todo el archivo.

Para agregar los miembros públicos

  1. La clase expone tres métodos públicos y un evento público. El primer método es sincrónico porque siempre se ejecuta muy rápidamente. Dado que los otros dos métodos pueden tardar algún tiempo, son asincrónicos para que no bloqueen el subproceso de la interfaz de usuario. Estos métodos devuelven IAsyncOperationWithProgress e IAsyncActionWithProgress. El primero define un método async que devuelve un resultado, y el segundo define un método async que devuelve void. Estas interfaces también permiten al código de cliente recibir las notificaciones sobre el progreso de la operación.

Para agregar los miembros privados

  1. La clase contiene tres miembros privados: dos métodos auxiliares para los cálculos numéricos y un objeto CoreDispatcher que se utiliza para calcular las referencias a las invocaciones de eventos desde los subprocesos de trabajo al subproceso de la interfaz de usuario.

Para agregar el encabezado y las directivas de espacio de nombres

  1. En Class1.cpp, agrega estas directivas #include:

  2. A continuación, agrega estas instrucciones using para extraer los espacios de nombres necesarios:

Para agregar la implementación para ComputeResult

  1. En Class1.cpp, agrega la implementación de método siguiente. Este método se ejecuta sincrónicamente en el subproceso de llamada, pero es muy rápido porque utiliza C++ AMP para paralelizar el cálculo en la GPU. Para obtener más información, consulta Información general sobre C++ AMP. Los resultados se anexan a un tipo concreto Platform::Collections::Vector<T que se convierte implícitamente en una interfaz Windows::Foundation::Collections::IVector<T> cuando se devuelve.

Para agregar la implementación para GetPrimesOrdered y el método auxiliar

  1. En Class1.cpp, agrega las implementaciones para GetPrimesOrdered y el método auxiliar is_prime.GetPrimesOrdered usa Clase concurrent_vector y un bucle parallel_for (Función) para repartir el trabajo y utilizar los máximos recursos del equipo en el que se ejecuta el programa para generar los resultados. Una vez calculados, almacenados y ordenados, los resultados se agregan a un objeto Platform::Collections::Vector<T y se devuelven en la interfaz Windows::Foundation::Collections::IVector<T> al código de cliente.

    Observe el código del indicador de progreso, que permite al cliente enlazar una barra de progreso u otro tipo de interfaz de usuario para mostrar al usuario cuánto tiempo queda para finalizar la operación. La notificación sobre el progreso tiene un costo. Debe desencadenarse un evento en el lado del componente y controlarse en el subproceso de la interfaz de usuario, y el valor de progreso se debe almacenar en cada iteración. Una manera de minimizar el costo consiste en limitar la frecuencia con la que se desencadena un evento de progreso. Si el costo sigue siendo prohibitivo, o si no puede hacer un cálculo aproximado de la duración de la operación, considere la posibilidad de utilizar un anillo de progreso, que muestra que una operación está en curso pero no muestra el tiempo restante hasta la finalización.

Para agregar la implementación para GetPrimesUnordered

  1. El último paso para crear el componente de C++ consiste en agregar la implementación para el método GetPrimesUnordered en Class1.cpp. Este método devuelve cada resultado a medida que lo encuentra, sin esperar a que se encuentren todos los resultados. Cada resultado se devuelve en el controlador de eventos y se muestra en la interfaz de usuario en tiempo real. Una vez más, observe que se utiliza un indicador de progreso. Este método también utiliza el método auxiliar is_prime.

  2. Presiona Ctrl+Mayús+B para compilar el componente.

Para crear un proyecto de JavaScript

  1. System_CAPS_noteNota

    Si solo desea crear un cliente de C#, puede omitir esta sección.

    En el Explorador de soluciones, abra el menú contextual del nodo Solución y elija Agregar, Nuevo proyecto.

  2. Expanda JavaScript (puede estar anidado en Otros lenguajes) y elija Aplicación vacía.

  3. Elige el botón Aceptar para aceptar el nombre predeterminado: App1.

  4. Abra el menú contextual del nodo del proyecto App1 y elija Establecer como proyecto de inicio.

  5. Agregue una referencia de proyecto a WinRT_CPP:

    1. Abra el menú contextual del nodo Referencias y elija Agregar referencia.

    2. En el panel izquierdo del cuadro de diálogo Administrador de referencias, selecciona Solución y, después, Proyectos.

    3. En el panel central, seleccione WinRT_CPP y elija el botón Aceptar.

Para agregar el código HTML que invoca los controladores de eventos de JavaScript

  1. Pega este código HTML en el nodo <body> de la página default.html:

Para agregar estilos

  1. En default.css, quita el estilo body y agrega estos estilos:

    
    #LogButtonDiv { border: orange solid 1px; -ms-grid-row: 1; /* default is 1 */ -ms-grid-column: 1; /* default is 1 */ } #LogResultDiv { background: black; border: red solid 1px; -ms-grid-row: 1; -ms-grid-column: 2; } #UnorderedPrimeButtonDiv, #OrderedPrimeButtonDiv { border: orange solid 1px; -ms-grid-row: 2; -ms-grid-column:1; } #UnorderedPrimeProgress, #OrderedPrimeProgress { border: red solid 1px; -ms-grid-column-span: 2; height: 40px; } #UnorderedPrimeResult, #OrderedPrimeResult { border: red solid 1px; font-size:smaller; -ms-grid-row: 2; -ms-grid-column: 3; -ms-overflow-style:scrollbar; }
    
    

Para agregar controladores de eventos de JavaScript que llaman a la DLL del componente

  1. Agrega las siguientes funciones al final del archivo default.js: Se llama a estas funciones cuando se eligen los botones de la página principal. Observe cómo JavaScript genera clases de C++ y después llama a sus métodos y usa los valores devueltos para rellenar las etiquetas HTML.

  2. Presione F5 para ejecutar la aplicación.

Resulta igual de sencillo llamar a la DLL del componente de Windows en tiempo de ejecución de C++ desde un cliente de C# que hacerlo desde un cliente de JavaScript. Los pasos siguientes muestran cómo crear un cliente de C# que es aproximadamente equivalente al cliente de JavaScript de la sección anterior.

Para crear un proyecto de C#

  1. En el Explorador de soluciones, abra el menú contextual del nodo Solución y, a continuación, elija Agregar, Nuevo proyecto.

  2. Expande Visual C# (puede estar anidado en Otros lenguajes), selecciona Tienda Windows en el panel izquierdo y, a continuación, Aplicación vacía en el panel central.

  3. Asigne a esta aplicación el nombre CS_Client y elija el botón Aceptar.

  4. Abra el menú contextual del nodo del proyecto CS_Client y elija Establecer como proyecto de inicio.

  5. Agregue una referencia de proyecto a WinRT_CPP:

    1. Abra el menú contextual del nodo Referencias y elija Agregar referencia.

    2. En el panel izquierdo del cuadro de diálogo Administrador de referencias, selecciona Solución y, después, Proyectos.

    3. En el panel central, seleccione WinRT_CPP y elija el botón Aceptar.

Para agregar el código XAML que define la interfaz de usuario

  1. Agrega el control ScrollViewer siguiente y su contenido a la cuadrícula en mainpage.xaml:

    <ScrollViewer> <StackPanel Width="1400"> <Button x:Name="Button1" Width="340" Height="50"  Margin="0,20,20,20" Content="Synchronous Logarithm Calculation" FontSize="16" Click="Button1_Click_1"/> <TextBlock x:Name="Result1" Height="100" FontSize="14"></TextBlock> <Button x:Name="PrimesOrderedButton" Content="Prime Numbers Ordered" FontSize="16" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesOrderedButton_Click_1"></Button> <ProgressBar x:Name="PrimesOrderedProgress" IsIndeterminate="false" Height="40"></ProgressBar> <TextBlock x:Name="PrimesOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock> <Button x:Name="PrimesUnOrderedButton" Width="340" Height="50" Margin="0,20,20,20" Click="PrimesUnOrderedButton_Click_1" Content="Prime Numbers Unordered" FontSize="16"></Button> <ProgressBar x:Name="PrimesUnOrderedProgress" IsIndeterminate="false" Height="40" ></ProgressBar> <TextBlock x:Name="PrimesUnOrderedResult" MinHeight="100" FontSize="10" TextWrapping="Wrap"></TextBlock> <Button x:Name="Clear_Button" Content="Clear" HorizontalAlignment="Left" Margin="0,20,20,20" VerticalAlignment="Top" Width="341" Click="Clear_Button_Click" FontSize="16"/> </StackPanel> </ScrollViewer>
    

Para agregar controladores de eventos para los botones

  1. En el Explorador de soluciones, abra mainpage.xaml.cs. (El archivo puede estar anidado en mainpage.xaml). Agregue una directiva using para System.Text y, a continuación, agregue el controlador de eventos para el cálculo del logaritmo en la clase MainPage justo después de OnNavigateTo.

  2. Agregue el controlador de eventos para el resultado ordenado:

  3. Agregue el controlador de eventos para el resultado sin ordenar y para el botón que borra los resultados, lo que le permitirá volver a ejecutar el código.

Seleccione el proyecto de C# o el proyecto de JavaScript como proyecto de inicio; para ello, abra el menú contextual del nodo del proyecto en el Explorador de soluciones y elija Establecer como proyecto de inicio. Presiona F5 para ejecutarlo con depuración o Ctrl+F5 para ejecutarlo sin depuración.

En el Examinador de objetos, puede inspeccionar todos los tipos de Windows en tiempo de ejecución definidos en los archivos .winmd. Esto incluye los tipos en el espacio de nombres Platform y en el espacio de nombres predeterminado. Sin embargo, debido a que los tipos del espacio de nombres Platform::Collections están definidos en el archivo de encabezado collections.h, no en un archivo winmd, no aparecen en el Examinador de objetos.

Para inspeccionar el componente

  1. En la barra de menús, elija Ver, Otras ventanas, Examinador de objetos.

  2. En el panel izquierdo del Examinador de objetos, expande el nodo WinRT_CPP para mostrar los tipos y métodos definidos en el componente.

Para mejorar la experiencia al usar la depuración, descarga los símbolos de depuración de los servidores de símbolos públicos de Microsoft:

  1. En la barra de menús, elija Herramientas, Opciones.

  2. En el cuadro de diálogo Opciones, expande el nodo Depuración y selecciona Símbolos.

  3. Seleccione Servidores de símbolos de Microsoft y, a continuación, elija el botón Aceptar.

Es posible que la primera vez se tarde algo de tiempo en descargar los símbolos. Para acelerar el rendimiento la próxima vez que presiones F5, especifica un directorio local donde almacenar los símbolos en memoria caché.

Al depurar una solución de JavaScript que tenga un objeto DLL de componente, puede establecer el depurador para habilitar el recorrido paso a paso a través del script o el recorrido paso a paso a través del código nativo del componente, pero no ambos al mismo tiempo. Para cambiar el valor, abra el menú contextual del nodo del proyecto de JavaScript en el Explorador de soluciones y elija Propiedades, Depuración, Tipo de depurador.

Asegúrese de seleccionar las capacidades adecuadas en el diseñador de paquetes. Por ejemplo, si estás intentando tener acceso mediante programación a los archivos de la carpeta Imágenes, asegúrate de activar la casilla Biblioteca de imágenes en el panel Capacidades del diseñador de paquetes.

Si el código de JavaScript no reconoce los métodos o propiedades públicos del componente, asegúrate de que en JavaScript se esté usando el uso combinado de mayúsculas y minúsculas tipo Camel. Por ejemplo, en JavaScript debe hacerse referencia al método ComputeResult de C++ como computeResult.

Si quita de una solución un proyecto de componente de Windows en tiempo de ejecución de C++, también debe quitar manualmente la referencia al proyecto desde el proyecto de JavaScript. De lo contrario, se impiden las operaciones de depuración o compilación subsiguientes. Si es necesario, puedes agregar una referencia de ensamblado al archivo DLL.

Mostrar:
© 2017 Microsoft