Compartir a través de


Generación de eventos en componentes de Windows Runtime

Nota:

Para obtener más información sobre cómo generar eventos en un componente de Windows Runtime de C++/WinRT , consulta Crear eventos en C++/WinRT.

Si el componente de Windows Runtime genera un evento de un tipo de delegado definido por el usuario en un subproceso en segundo plano (subproceso de trabajo) y quieres que JavaScript pueda recibir el evento, puedes implementarlo o generarlo de cualquiera de estas maneras.

  • (Opción 1) Genere el evento a través de Windows.UI.Core.CoreDispatcher para serializar el evento en el contexto del subproceso de JavaScript. Aunque normalmente esta es la mejor opción, en algunos escenarios es posible que no proporcione el rendimiento más rápido.
  • (Opción 2) Usa el objeto> Windows.Foundation.EventHandler<(pero pierde la información del tipo de evento). Si la opción 1 no es factible o si su rendimiento no es adecuado, se trata de una buena segunda opción siempre que la pérdida de información de tipo sea aceptable. Si vas a crear un componente de Windows Runtime de C#, el tipo de objeto> Windows.Foundation.EventHandler<no está disponible; en su lugar, ese tipo se proyecta en System.EventHandler, por lo que debes usarlo en su lugar.
  • (Opción 3) Cree su propio proxy y código auxiliar para el componente. Esta opción es la más difícil de implementar, pero conserva la información de tipos y podría proporcionar un mejor rendimiento en comparación con la opción 1 en escenarios exigentes.

Si simplemente genera un evento en un subproceso en segundo plano sin usar una de estas opciones, un cliente de JavaScript no recibirá el evento.

Fondo

Todos los componentes y aplicaciones de Windows Runtime son objetos COM fundamentalmente, independientemente del lenguaje que use para crearlos. En la API de Windows, la mayoría de los componentes son objetos COM ágiles que pueden comunicarse igualmente bien con objetos en el subproceso en segundo plano y en el subproceso de interfaz de usuario. Si un objeto COM no se puede hacer ágil, requiere objetos auxiliares conocidos como servidores proxy y códigos auxiliares para comunicarse con otros objetos COM a través del límite del subproceso de interfaz de usuario. (En términos COM, esto se conoce como comunicación entre los apartamentos de subproceso).

La mayoría de los objetos de la API de Windows son ágiles o tienen servidores proxy y códigos auxiliares integrados. Sin embargo, los servidores proxy y códigos auxiliares no se pueden crear para tipos genéricos como Windows.Foundation.TypedEventHandler<TSender, TResult> porque no son tipos completos hasta que se proporciona el argumento type. Solo es con los clientes de JavaScript que la falta de proxies o códigos auxiliares se convierte en un problema, pero si desea que el componente se pueda usar desde JavaScript, así como desde C++ o un lenguaje .NET, debe usar una de las tres opciones siguientes.

(Opción 1) Generar el evento a través de CoreDispatcher

Puede enviar eventos de cualquier tipo de delegado definido por el usuario mediante Windows.UI.Core.CoreDispatcher y JavaScript podrá recibirlos. Si no está seguro de qué opción usar, pruebe primero esta. Si la latencia entre la activación de eventos y el control de eventos se convierte en un problema, pruebe una de las otras opciones.

En el ejemplo siguiente se muestra cómo usar CoreDispatcher para generar un evento fuertemente tipado. Observe que el argumento type es Toast, no Object.

public event EventHandler<Toast> ToastCompletedEvent;
private void OnToastCompleted(Toast args)
{
    var completedEvent = ToastCompletedEvent;
    if (completedEvent != null)
    {
        completedEvent(this, args);
    }
}

public void MakeToastWithDispatcher(string message)
{
    Toast toast = new Toast(message);
    // Assume you have a CoreDispatcher at class scope.
    // Initialize it here, then use it from the background thread.
    var window = Windows.UI.Core.CoreWindow.GetForCurrentThread();
    m_dispatcher = window.Dispatcher;

    Task.Run( () =>
    {
        if (ToastCompletedEvent != null)
        {
            m_dispatcher.RunAsync(CoreDispatcherPriority.Normal,
            new DispatchedHandler(() =>
            {
                this.OnToastCompleted(toast);
            })); // end m_dispatcher.RunAsync
         }
     }); // end Task.Run
}

(Opción 2) Usar el objeto> EventHandler<, pero perder información de tipo

Nota:

Si vas a crear un componente de Windows Runtime de C#, el tipo de objeto> Windows.Foundation.EventHandler<no está disponible; en su lugar, ese tipo se proyecta en System.EventHandler, por lo que debes usarlo en su lugar.

Otra manera de enviar un evento desde un subproceso en segundo plano es usar el objeto> Windows.Foundation.EventHandler<como el tipo del evento. Windows proporciona esta creación de instancias concreta del tipo genérico y proporciona un proxy y código auxiliar para él. El inconveniente es que se pierde la información de tipo de los argumentos de evento y el remitente. Los clientes de C++ y .NET deben saber a través de la documentación a qué tipo se va a devolver cuando se recibe el evento. Los clientes de JavaScript no necesitan la información de tipo original. Encuentran las propiedades arg, en función de sus nombres en los metadatos.

En este ejemplo se muestra cómo usar el objeto> Windows.Foundation.EventHandler<en C#:

public sealed Class1
{
// Declare the event
public event EventHandler<Object> ToastCompletedEvent;

    // Raise the event
    public async void MakeToast(string message)
    {
        Toast toast = new Toast(message);
        // Fire the event from a background thread to allow this thread to continue
        Task.Run(() =>
        {
            if (ToastCompletedEvent != null)
            {
                OnToastCompleted(toast);
            }
        });
    }

    private void OnToastCompleted(Toast args)
    {
        var completedEvent = ToastCompletedEvent;
        if (completedEvent != null)
        {
            completedEvent(this, args);
        }
    }
}

Este evento se consume en el lado de JavaScript de la siguiente manera:

toastCompletedEventHandler: function (event) {
   var toastType = event.toast.toastType;
   document.getElementById("toasterOutput").innerHTML = "<p>Made " + toastType + " toast</p>";
}

(Opción 3) Creación de su propio proxy y código auxiliar

Para obtener posibles mejoras de rendimiento en los tipos de eventos definidos por el usuario que tienen información de tipos totalmente conservados, debe crear sus propios objetos proxy y código auxiliar e insertarlos en el paquete de la aplicación. Normalmente, tiene que usar esta opción solo en situaciones poco frecuentes en las que ninguna de las otras dos opciones es adecuada. Además, no hay ninguna garantía de que esta opción proporcione un mejor rendimiento que las otras dos opciones. El rendimiento real depende de muchos factores. Use el generador de perfiles de Visual Studio u otras herramientas de generación de perfiles para medir el rendimiento real de la aplicación y determinar si el evento es de hecho un cuello de botella.

El resto de este artículo muestra cómo usar C# para crear un componente básico de Windows Runtime y, a continuación, usar C++ para crear un archivo DLL para el proxy y el código auxiliar que permitirá que JavaScript consuma un evento Windows.Foundation.TypedEventHandler<TSender, TResult> generado por el componente en una operación asincrónica. (También puede usar C++ o Visual Basic para crear el componente. Los pasos relacionados con la creación de servidores proxy y códigos auxiliares son los mismos). Este tutorial se basa en crear un ejemplo de componente en proceso de Windows Runtime (C++/CX) y ayuda a explicar sus propósitos.

Este tutorial tiene estas partes.

  • Aquí crearás dos clases básicas de Windows Runtime. Una clase expone un evento de tipo Windows.Foundation.TypedEventHandler<TSender, TResult> y la otra clase es el tipo que se devuelve a JavaScript como argumento para TValue. Estas clases no se pueden comunicar con JavaScript hasta que complete los pasos posteriores.
  • Esta aplicación activa el objeto de clase principal, llama a un método y controla un evento generado por el componente de Windows Runtime.
  • Estas son necesarias para las herramientas que generan las clases proxy y stub.
  • A continuación, use el archivo IDL para generar el código fuente de C para el proxy y el código auxiliar.
  • Registre los objetos proxy-stub para que el entorno de ejecución COM pueda encontrarlos y haga referencia al archivo DLL proxy-stub en el proyecto de aplicación.

Para crear el componente de Windows Runtime

En Visual Studio, en la barra de menús, elija Archivo > nuevo proyecto. En el cuadro de diálogo Nuevo proyecto, expanda Windows universal de JavaScript > y, a continuación, seleccione Aplicación en blanco. Asigne al proyecto el nombre ToasterApplication y elija el botón Aceptar .

Agregue un componente de Windows Runtime de C# a la solución: en Explorador de soluciones, abra el menú contextual de la solución y, a continuación, elija Agregar > nuevo proyecto. Expanda Microsoft Store de Visual C# > y, a continuación, seleccione Componente de Windows Runtime. Asigne al proyecto el nombre ToasterComponent y elija el botón Aceptar . ToasterComponent será el espacio de nombres raíz de los componentes que creará en pasos posteriores.

En Explorador de soluciones, abra el menú contextual de la solución y elija Propiedades. En el cuadro de diálogo Páginas de propiedades , seleccione Propiedades de configuración en el panel izquierdo y, a continuación, en la parte superior del cuadro de diálogo, establezca Configuración en Depurar y Plataforma en x86, x64 o ARM. Elija el botón Aceptar .

Importante Plataforma = Cualquier CPU no funcionará porque no es válido para el archivo DLL win32 de código nativo que agregará a la solución más adelante.

En Explorador de soluciones, cambie el nombre de class1.cs a ToasterComponent.cs para que coincida con el nombre del proyecto. Visual Studio cambia automáticamente el nombre de la clase del archivo para que coincida con el nuevo nombre de archivo.

En el archivo .cs, agregue una directiva using para el espacio de nombres Windows.Foundation para poner TypedEventHandler en el ámbito.

Cuando se requieren proxies y códigos auxiliares, el componente debe usar interfaces para exponer sus miembros públicos. En ToasterComponent.cs, defina una interfaz para la tostadora y otra para la notificación del sistema que genera el tostador.

Nota En C# puede omitir este paso. En su lugar, cree primero una clase y, a continuación, abra su menú contextual y elija Refactorizar > interfaz de extracción. En el código generado, proporcione manualmente la accesibilidad pública de las interfaces.

	public interface IToaster
        {
            void MakeToast(String message);
            event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;

        }
        public interface IToast
        {
            String ToastType { get; }
        }

La interfaz IToast tiene una cadena que se puede recuperar para describir el tipo de notificación del sistema. La interfaz IToaster tiene un método para realizar notificaciones del sistema y un evento para indicar que se realiza la notificación del sistema. Dado que este evento devuelve la parte concreta (es decir, tipo) de la notificación del sistema, se conoce como un evento con tipo.

A continuación, necesitamos clases que implementen estas interfaces y sean públicas y selladas para que sean accesibles desde la aplicación de JavaScript que programará más adelante.

	public sealed class Toast : IToast
        {
            private string _toastType;

            public string ToastType
            {
                get
                {
                    return _toastType;
                }
            }
            internal Toast(String toastType)
            {
                _toastType = toastType;
            }

        }
        public sealed class Toaster : IToaster
        {
            public event TypedEventHandler<Toaster, Toast> ToastCompletedEvent;

            private void OnToastCompleted(Toast args)
            {
                var completedEvent = ToastCompletedEvent;
                if (completedEvent != null)
                {
                    completedEvent(this, args);
                }
            }

            public void MakeToast(string message)
            {
                Toast toast = new Toast(message);
                // Fire the event from a thread-pool thread to enable this thread to continue
                Windows.System.Threading.ThreadPool.RunAsync(
                (IAsyncAction action) =>
                {
                    if (ToastCompletedEvent != null)
                    {
                        OnToastCompleted(toast);
                    }
                });
           }
        }

En el código anterior, creamos la notificación del sistema y, a continuación, activamos un elemento de trabajo del grupo de subprocesos para activar la notificación. Aunque el IDE podría sugerir que aplique la palabra clave await a la llamada asincrónica, no es necesario en este caso porque el método no realiza ningún trabajo que dependa de los resultados de la operación.

Nota La llamada asincrónica en el código anterior usa ThreadPool.RunAsync únicamente para demostrar una manera sencilla de desencadenar el evento en un subproceso en segundo plano. Podría escribir este método en particular como se muestra en el ejemplo siguiente y funcionaría bien porque el programador de tareas de .NET serializa automáticamente las llamadas asincrónicas o await al subproceso de la interfaz de usuario.  

	public async void MakeToast(string message)
    {
        Toast toast = new Toast(message)
        await Task.Delay(new Random().Next(1000));
        OnToastCompleted(toast);
    }

Si compila el proyecto ahora, debe compilarse limpiamente.

Para programar la aplicación JavaScript

Ahora podemos agregar un botón a la aplicación de JavaScript para que use la clase que acabamos de definir para realizar notificaciones del sistema. Antes de hacerlo, debemos agregar una referencia al proyecto ToasterComponent que acabamos de crear. En Explorador de soluciones, abra el menú contextual del proyecto ToasterApplication, elija Agregar referencias y, a continuación, elija el botón Agregar nueva referencia>. En el cuadro de diálogo Agregar referencia, en el panel izquierdo de La solución, seleccione el proyecto de componente y, después, en el panel central, seleccione ToasterComponent. Elija el botón Aceptar .

En Explorador de soluciones, abra el menú contextual del proyecto ToasterApplication y, a continuación, elija Establecer como proyecto de inicio.

Al final del archivo default.js, agregue un espacio de nombres para contener las funciones para llamar al componente y volver a llamarlo. El espacio de nombres tendrá dos funciones, una para realizar notificaciones del sistema y otra para controlar el evento de notificaciones del sistema. La implementación de makeToast crea un objeto Toaster, registra el controlador de eventos y realiza la notificación del sistema. Hasta ahora, el controlador de eventos no hace mucho, como se muestra aquí:

	WinJS.Namespace.define("ToasterApplication"), {
       makeToast: function () {

          var toaster = new ToasterComponent.Toaster();
          //toaster.addEventListener("ontoastcompletedevent", ToasterApplication.toastCompletedEventHandler);
          toaster.ontoastcompletedevent = ToasterApplication.toastCompletedEventHandler;
          toaster.makeToast("Peanut Butter");
       },

       toastCompletedEventHandler: function(event) {
           // The sender of the event (the delegate's first type parameter)
           // is mapped to event.target. The second argument of the delegate
           // is contained in event, which means in this case event is a
           // Toast class, with a toastType string.
           var toastType = event.toastType;

           document.getElementById('toastOutput').innerHTML = "<p>Made " + toastType + " toast</p>";
        },
    });

La función makeToast debe enlazarse a un botón. Actualice default.html para incluir un botón y algún espacio para generar el resultado de realizar la notificación del sistema:

    <body>
        <h1>Click the button to make toast</h1>
        <button onclick="ToasterApplication.makeToast()">Make Toast!</button>
        <div id="toasterOutput">
            <p>No Toast Yet...</p>
        </div>
    </body>

Si no usamos typedEventHandler, ahora podríamos ejecutar la aplicación en el equipo local y hacer clic en el botón para realizar la notificación del sistema. Pero en nuestra aplicación no sucede nada. Para averiguar por qué, vamos a depurar el código administrado que desencadena ToastCompletedEvent. Detenga el proyecto y, a continuación, en la barra de menús, elija Depurar > propiedades de la aplicación de tostadora. Cambie el tipo del depurador a Solo administrado. De nuevo en la barra de menús, elija Depurar > excepciones y, a continuación, seleccione Excepciones de Common Language Runtime.

Ahora ejecute la aplicación y haga clic en el botón make-toast. El depurador detecta una excepción de conversión no válida. Aunque no es obvio de su mensaje, esta excepción se está produciendo porque faltan servidores proxy para esa interfaz.

que falta el proxy

El primer paso para crear un proxy y código auxiliar para un componente es agregar un identificador único o GUID a las interfaces. Sin embargo, el formato GUID que se va a usar difiere en función de si está codificando en C#, Visual Basic u otro lenguaje .NET o en C++.

Para generar GUID para las interfaces del componente (C# y otros lenguajes .NET)

En la barra de menús, elija Herramientas > Crear GUID. En el cuadro de diálogo, seleccione 5. [Guid("xxxxxxxx-xxxx... xxxx")]. Elija el botón Nuevo GUID y, a continuación, elija el botón Copiar.

herramienta de generador guid

Vuelva a la definición de la interfaz y pegue el nuevo GUID justo antes de la interfaz IToaster, como se muestra en el ejemplo siguiente. (No use el GUID en el ejemplo. Cada interfaz única debe tener su propio GUID).

[Guid("FC198F74-A808-4E2A-9255-264746965B9F")]
        public interface IToaster...

Agregue una directiva using para el espacio de nombres System.Runtime.InteropServices.

Repita estos pasos para la interfaz IToast.

Para generar GUID para las interfaces del componente (C++)

En la barra de menús, elija Herramientas > Crear GUID. En el cuadro de diálogo, seleccione 3. GUID de estructura estática const = {...}. Elija el botón Nuevo GUID y, a continuación, elija el botón Copiar.

Pegue el GUID justo antes de la definición de la interfaz IToaster. Después de pegar, el GUID debe ser similar al ejemplo siguiente. (No use el GUID en el ejemplo. Cada interfaz única debe tener su propio GUID).

// {F8D30778-9EAF-409C-BCCD-C8B24442B09B}
    static const GUID <<name>> = { 0xf8d30778, 0x9eaf, 0x409c, { 0xbc, 0xcd, 0xc8, 0xb2, 0x44, 0x42, 0xb0, 0x9b } };

Agregue una directiva using para Windows.Foundation.Metadata para incluir GuidAttribute en el ámbito.

Ahora, convierta manualmente el GUID const en guidAttribute para que tenga el formato como se muestra en el ejemplo siguiente. Observe que las llaves se reemplazan por corchetes y paréntesis, y se quita el punto y coma final.

// {E976784C-AADE-4EA4-A4C0-B0C2FD1307C3}
    [GuidAttribute(0xe976784c, 0xaade, 0x4ea4, 0xa4, 0xc0, 0xb0, 0xc2, 0xfd, 0x13, 0x7, 0xc3)]
    public interface IToaster
    {...

Repita estos pasos para la interfaz IToast.

Ahora que las interfaces tienen identificadores únicos, podemos crear un archivo IDL mediante la alimentación del archivo .winmd en la herramienta de línea de comandos winmdidl y, a continuación, generar el código fuente de C para el proxy y el código auxiliar mediante la alimentación de ese archivo IDL en la herramienta de línea de comandos MIDL. Visual Studio lo hace por nosotros si creamos eventos posteriores a la compilación, como se muestra en los pasos siguientes.

Para generar el código fuente del proxy y del código auxiliar

Para agregar un evento posterior a la compilación personalizado, en Explorador de soluciones, abra el menú contextual del proyecto ToasterComponent y, a continuación, elija Propiedades. En el panel izquierdo de las páginas de propiedades, seleccione Eventos de compilación y, a continuación, elija el botón Editar posterior a la compilación. Agregue los siguientes comandos a la línea de comandos posterior a la compilación. (Primero se debe llamar al archivo por lotes para establecer las variables de entorno para buscar la herramienta winmdidl).

call "$(DevEnvDir)..\..\vc\vcvarsall.bat" $(PlatformName)
winmdidl /outdir:output "$(TargetPath)"
midl /metadata_dir "%WindowsSdkDir%References\CommonConfiguration\Neutral" /iid "$(ProjectDir)$(TargetName)_i.c" /env win32 /h "$(ProjectDir)$(TargetName).h" /winmd "Output\$(TargetName).winmd" /W1 /char signed /nologo /winrt /dlldata "$(ProjectDir)dlldata.c" /proxy "$(ProjectDir)$(TargetName)_p.c" "Output\$(TargetName).idl"

Importante Para una configuración de proyecto arm o x64, cambie el parámetro MIDL /env a x64 o arm32.

Para asegurarse de que el archivo IDL se vuelve a generar cada vez que se cambia el archivo .winmd, cambie Ejecutar el evento posterior a la compilación a Cuando la compilación actualice la salida del proyecto. La página de propiedades Eventos de compilación debe ser similar a la siguiente: eventos de compilación

Recompile la solución para generar y compilar el IDL.

Puede comprobar que MIDL compiló correctamente la solución buscando ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c y dlldata.c en el directorio del proyecto ToasterComponent.

Para compilar el proxy y el código auxiliar en un archivo DLL

Ahora que tiene los archivos necesarios, puede compilarlos para generar un archivo DLL, que es un archivo C++. Para que esto sea lo más fácil posible, agregue un nuevo proyecto para admitir la creación de servidores proxy. Abra el menú contextual de la solución ToasterApplication y elija Agregar > nuevo proyecto. En el panel izquierdo del cuadro de diálogo Nuevo proyecto, expanda Windows > universal de Visual C++ > y, después, en el panel central, seleccione DLL (aplicaciones para UWP). (Tenga en cuenta que no es un proyecto componente de Windows Runtime de C++). Asigne al proyecto el nombre Proxies y, a continuación, elija el botón Aceptar . Estos archivos se actualizarán mediante los eventos posteriores a la compilación cuando cambie algo en la clase de C#.

De forma predeterminada, el proyecto Proxies genera archivos .h de encabezado y archivos .cpp de C++. Dado que el archivo DLL se compila a partir de los archivos producidos a partir de MIDL, los archivos .h y .cpp no son necesarios. En Explorador de soluciones, abra el menú contextual para ellos, elija Quitar y confirme la eliminación.

Ahora que el proyecto está vacío, puede agregar los archivos generados por MIDL. Abra el menú contextual del proyecto Proxies y, a continuación, elija Agregar > elemento existente. En el cuadro de diálogo, vaya al directorio del proyecto ToasterComponent y seleccione estos archivos: ToasterComponent.h, ToasterComponent_i.c, ToasterComponent_p.c y archivos dlldata.c. Elija el botón Agregar.

En el proyecto Proxies, cree un archivo .def para definir las exportaciones dll descritas en dlldata.c. Abra el menú contextual del proyecto y elija Agregar > nuevo elemento. En el panel izquierdo del cuadro de diálogo, seleccione Código y, después, en el panel central, seleccione Archivo de definición de módulo. Asigne al archivo el nombre proxies.def y elija el botón Agregar . Abra este archivo .def y modifíquelo para incluir las EXPORTACIONES definidas en dlldata.c:

EXPORTS
    DllCanUnloadNow         PRIVATE
    DllGetClassObject       PRIVATE

Si compila el proyecto ahora, se producirá un error. Para compilar correctamente este proyecto, debe cambiar cómo se compila y vincula el proyecto. En Explorador de soluciones, abra el menú contextual del proyecto Proxies y, a continuación, elija Propiedades. Cambie las páginas de propiedades de la siguiente manera.

En el panel izquierdo, seleccione Preprocesador de C/C++ > y, después, en el panel derecho, seleccione Definiciones de preprocesador, elija el botón de flecha abajo y, a continuación, seleccione Editar. Agregue estas definiciones en el cuadro:

WIN32;_WINDOWS

En Encabezados precompilados de C/C++>, cambie Encabezado precompilado a No usar encabezados precompilados y, a continuación, elija el botón Aplicar.

En Enlazador > General, cambie Omitir la biblioteca de importación a y, a continuación, elija el botón Aplicar .

En Entrada del enlazador>, seleccione Dependencias adicionales, elija el botón de flecha abajo y, a continuación, seleccione Editar. Agregue este texto en el cuadro:

rpcrt4.lib;runtimeobject.lib

No pegue estas bibliotecas directamente en la fila de lista. Use el cuadro Editar para asegurarse de que MSBuild en Visual Studio mantendrá las dependencias adicionales correctas.

Cuando haya realizado estos cambios, elija el botón Aceptar en el cuadro de diálogo Páginas de propiedades .

A continuación, tome una dependencia en el proyecto ToasterComponent. Esto garantiza que la notificación del sistema se compilará antes de que se compile el proyecto de proxy. Esto es necesario porque el proyecto toaster es responsable de generar los archivos para compilar el proxy.

Abra el menú contextual del proyecto Proxies y, a continuación, elija Dependencias del proyecto. Active las casillas para indicar que el proyecto Proxies depende del proyecto ToasterComponent para asegurarse de que Visual Studio los compila en el orden correcto.

Para comprobar que la solución se compila correctamente, elija Compilar > recompilar solución en la barra de menús de Visual Studio.

Para registrar el proxy y el código auxiliar

En el proyecto ToasterApplication, abra el menú contextual de package.appxmanifest y, a continuación, elija Abrir con. En el cuadro de diálogo Abrir con, seleccione Editor de texto XML y, a continuación, elija el botón Aceptar . Vamos a pegar algunos XML que proporciona un registro de extensión windows.activeableClass.proxyStub y que se basan en los GUID del proxy. Para buscar los GUID que se van a usar en el archivo .appxmanifest, abra ToasterComponent_i.c. Busque entradas similares a las del ejemplo siguiente. Observe también las definiciones de IToast, IToaster y una tercera interfaz: un controlador de eventos con tipo que tiene dos parámetros: toaster y toast. Esto coincide con el evento definido en la clase Toaster. Observe que los GUID de IToast e IToaster coinciden con los GUID definidos en las interfaces del archivo C#. Dado que la interfaz del controlador de eventos con tipo se genera automáticamente, el GUID de esta interfaz también se genera automáticamente.

MIDL_DEFINE_GUID(IID, IID___FITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast,0x1ecafeff,0x1ee1,0x504a,0x9a,0xf5,0xa6,0x8c,0x6f,0xb2,0xb4,0x7d);

MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToast,0xF8D30778,0x9EAF,0x409C,0xBC,0xCD,0xC8,0xB2,0x44,0x42,0xB0,0x9B);

MIDL_DEFINE_GUID(IID, IID___x_ToasterComponent_CIToaster,0xE976784C,0xAADE,0x4EA4,0xA4,0xC0,0xB0,0xC2,0xFD,0x13,0x07,0xC3);

Ahora copiamos los GUID, péguelos en package.appxmanifest en un nodo que agregamos y asignamos el nombre Extensiones y, a continuación, se vuelven a formatear. La entrada del manifiesto es similar al ejemplo siguiente, pero de nuevo, recuerde usar sus propios GUID. Observe que el GUID de ClassId del XML es el mismo que ITypedEventHandler2. Esto se debe a que ese GUID es el primero que aparece en ToasterComponent_i.c. Los GUID aquí no distinguen mayúsculas de minúsculas. En lugar de volver a formatear manualmente los GUID para IToast e IToaster, puede volver a las definiciones de interfaz y obtener el valor GuidAttribute, que tiene el formato correcto. En C++, hay un GUID con formato correcto en el comentario. En cualquier caso, debe volver a formatear manualmente el GUID que se usa para classId y el controlador de eventos.

	  <Extensions> <!--Use your own GUIDs!!!-->
        <Extension Category="windows.activatableClass.proxyStub">
          <ProxyStub ClassId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d">
            <Path>Proxies.dll</Path>
            <Interface Name="IToast" InterfaceId="F8D30778-9EAF-409C-BCCD-C8B24442B09B"/>
            <Interface Name="IToaster"  InterfaceId="E976784C-AADE-4EA4-A4C0-B0C2FD1307C3"/>  
            <Interface Name="ITypedEventHandler_2_ToasterComponent__CToaster_ToasterComponent__CToast" InterfaceId="1ecafeff-1ee1-504a-9af5-a68c6fb2b47d"/>
          </ProxyStub>      
        </Extension>
      </Extensions>

Pegue el nodo XML Extensiones como elemento secundario directo del nodo Paquete y un par de, por ejemplo, el nodo Recursos.

Antes de continuar, es importante asegurarse de que:

  • ProxyStub ClassId se establece en el primer GUID del archivo ToasterComponent_i.c. Use el primer GUID definido en este archivo para classId. (Esto puede ser el mismo que el GUID para ITypedEventHandler2).
  • La ruta de acceso es la ruta de acceso relativa del paquete del binario proxy. (En este tutorial, proxies.dll está en la misma carpeta que ToasterApplication.winmd).
  • Los GUID tienen el formato correcto. (Esto es fácil de equivocarse).
  • Los identificadores de interfaz del manifiesto coinciden con los IID en el archivo ToasterComponent_i.c.
  • Los nombres de interfaz son únicos en el manifiesto. Dado que el sistema no usa estos valores, puede elegir los valores. Se recomienda elegir nombres de interfaz que coincidan claramente con las interfaces que haya definido. En el caso de las interfaces generadas, los nombres deben indicar las interfaces generadas. Puede usar el archivo ToasterComponent_i.c para ayudarle a generar nombres de interfaz.

Si intenta ejecutar la solución ahora, obtendrá un error que proxies.dll no forma parte de la carga. Abra el menú contextual de la carpeta Referencias en el proyecto ToasterApplication y, a continuación, elija Agregar referencia. Active la casilla situada junto al proyecto Proxies. Además, asegúrese de que la casilla situada junto a ToasterComponent también está seleccionada. Elija el botón Aceptar .

El proyecto ahora debería compilarse. Ejecute el proyecto y compruebe que puede realizar la notificación del sistema.