Compartir a través de


Implementación de un proveedor de fuentes en una aplicación de Windows de C#

Nota:

Parte de la información hace referencia al producto de versión preliminar, el cual puede sufrir importantes modificaciones antes de que se publique la versión comercial. Microsoft no proporciona ninguna garantía, expresa o implícita, con respecto a la información proporcionada aquí.

Este artículo le guía a través de la creación de un proveedor de fuentes simple que registra un URI de contenido de fuente e implementa la interfaz IFeedProvider. El Panel de widgets invoca los métodos de esta interfaz para solicitar parámetros de cadena de consulta personalizados, normalmente para admitir escenarios de autenticación. Los proveedores de fuentes pueden admitir una sola fuente o varias fuentes.

Para implementar un proveedor de fuentes con C++/WinRT, consulte Implementación de un proveedor de fuentes en una aplicación win32 (C++/WinRT).

Requisitos previos

  • El dispositivo debe tener habilitado el modo de desarrollador. Para obtener más información, vea Habilitar el dispositivo para el desarrollo.
  • Visual Studio 2022 o posterior con la carga de trabajo Desarrollo de la Plataforma universal de Windows.

Creación de una aplicación de consola de C#

En Visual Studio, cree un nuevo proyecto. En el cuadro de diálogo Crear un nuevo proyecto, establezca el filtro de lenguaje en "C#" y el filtro de plataforma en Windows y, a continuación, seleccione la plantilla de proyecto Aplicación de consola. Asigne al nuevo proyecto el nombre "ExampleFeedProvider". Para este tutorial, asegúrese de que la opción Colocar la solución y el proyecto en el mismo directorio esté desactivada. Cuando se le solicite, establezca la versión de .NET de destino en 6.0.

Cuando se cargue el proyecto, en el Explorador de soluciones, haga clic con el botón derecho en el nombre del proyecto y seleccione Propiedades. En la página General, desplácese hacia abajo hasta Sistema operativo de destino y seleccione "Windows". En Versión del sistema operativo de destino, seleccione la versión 10.022631.2787 o posterior.

Tenga en cuenta que en este tutorial se usa una aplicación de consola que muestra la ventana de consola cuando se activa la fuente para habilitar la depuración sencilla. Cuando esté listo para publicar la aplicación del proveedor de fuentes, puede convertir la aplicación de consola en una aplicación de Windows siguiendo los pasos descritos en Conversión de la aplicación de consola en una aplicación de Windows.

Adición de referencias al paquete Nuget SDK de Aplicaciones para Windows

En este ejemplo se usa el paquete NuGet SDK de Aplicaciones para Windows estable más reciente. En Explorador de soluciones, haga clic con el botón derecho en Dependencias y seleccione Administrar paquetes NuGet.... En el administrador de paquetes NuGet, seleccione la pestaña Examinar y busque "Microsoft.WindowsAppSDK". Seleccione la versión estable más reciente en la lista desplegable Versión y, a continuación, haga clic en Instalar.

Adición de una clase FeedProvider para controlar las operaciones de fuente

En Visual Studio, haga clic con el botón derecho en el proyecto ExampleFeedProvider en Explorador de soluciones y seleccione Agregar->clase. En el cuadro de diálogo Agregar clase, asigne a la clase el nombre "FeedProvider" y, después, haga clic en Agregar. En el archivo WidgetProvider.cs generado, actualice la definición de clase para indicar que implementa la interfaz IFeedProvider.

Cree un CLSID que se usará para identificar el proveedor de fuentes para la activación COM. Para generar un GUID en Visual Studio, vaya a Herramientas->Crear GUID. Guarde este GUID en un archivo de texto que se usará más adelante al empaquetar la aplicación del proveedor de fuentes. Reemplace el GUID en las anotaciones de la clase FeedProvider que se muestra en el ejemplo siguiente.

// FeedProvider.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
...
[ComVisible(true)]
[ComDefaultInterface(typeof(IFeedProvider))]
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
public sealed class FeedProvider : IFeedProvider

Implementación de los métodos IFeedProvider

En las secciones siguientes, implementaremos los métodos de la interfaz IFeedProvider.

Nota:

Solo se garantiza que los objetos pasados a los métodos de devolución de llamada de la interfaz IFeedProvider sean válidos dentro de la devolución de llamada. No debe almacenar referencias a estos objetos porque su comportamiento fuera del contexto de la devolución de llamada no está definido.

OnFeedProviderEnabled

El método OnFeedProviderEnabled se invoca cuando el host del panel de widgets crea una fuente asociada al proveedor. En la implementación de este método, genere una cadena de consulta con los parámetros que se pasarán a la dirección URL que proporciona el contenido de la fuente, incluidos los tokens de autenticación necesarios. Cree una instancia de CustomQueryParametersUpdateOptions, pasando FeedProviderDefinitionId desde los argumentos del evento que identifica la fuente que se ha habilitado y la cadena de consulta. Obtenga el FeedManager predeterminado y llame a SetCustomQueryParameters para registrar los parámetros de cadena de consulta con el Panel de widgets.

// FeedProvider.cs

public void OnFeedProviderEnabled(FeedProviderEnabledArgs args)
{
    Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was enabled.");
    var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1&param2");
    FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}

OnFeedProviderDisabled

Se llama a OnFeedProviderDisabled cuando se ha deshabilitado el panel de widgets cuando se han deshabilitado todas las fuentes de este proveedor. No es necesario que los proveedores de fuentes realicen ninguna acción en respuesta a esta llamada de método. La invocación del método se puede usar con fines de telemetría o para actualizar los parámetros de cadena de consulta o revocar tokens de autenticación, si es necesario. Si la aplicación solo admite un único proveedor de fuentes o si todos los proveedores de fuentes admitidos por la aplicación se han deshabilitado, la aplicación puede salir en respuesta a esta devolución de llamada.

// FeedProvider.cs
public void OnFeedProviderDisabled(FeedProviderDisabledArgs args)
{
    Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was disabled.");
}

OnFeedEnabled, OnFeedDisabled

OnFeedEnabled y OnFeedDisabled se invocan mediante el Panel de widgets cuando una fuente está habilitada o deshabilitada. No es necesario que los proveedores de fuentes realicen ninguna acción en respuesta a estas llamadas de método. La invocación del método se puede usar con fines de telemetría o para actualizar los parámetros de cadena de consulta o revocar tokens de autenticación, si es necesario.

// FeedProvider.cs
public void OnFeedEnabled(FeedEnabledArgs args)
{
    Console.WriteLine($"{args.FeedDefinitionId} feed was enabled.");
}

// FeedProvider.cs
public void OnFeedDisabled(FeedDisabledArgs args)
{
    Console.WriteLine($"{args.FeedDefinitionId} feed was disabled.");
}

OnCustomQueryParametersRequested

OnCustomQueryParametersRequested se genera cuando el Panel de widgets determina que es necesario actualizar los parámetros de consulta personalizados asociados al proveedor de fuentes. Por ejemplo, este método se puede generar si se produce un error en la operación para capturar contenido de fuente del servicio web remoto. La propiedad FeedProviderDefinitionId de CustomQueryParametersRequestedArgs que se pasa a este método especifica la fuente para la que se solicitan parámetros de cadena de consulta. El proveedor debe volver a generar la cadena de consulta y volver a pasarla al Panel de widgets llamando a SetCustomQueryParameters.

// FeedProvider.cs

public void OnCustomQueryParametersRequested(CustomQueryParametersRequestedArgs args)
{
    Console.WriteLine($"CustomQueryParamaters were requested for {args.FeedProviderDefinitionId}.");
    var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1&param2");
    FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}

Implementación de un generador de clases que creará una instancia de FeedProvider a petición

Para que el host de la fuente se comunique con nuestro proveedor de fuentes, debemos llamar a CoRegisterClassObject. Esta función requiere que creemos una implementación de IClassFactory que creará un objeto de clase para nuestra clase FeedProvider. Implementaremos nuestro generador de clases en una clase auxiliar independiente.

En Visual Studio, haga clic con el botón derecho en el proyecto ExampleFeedProvider en Explorador de soluciones y seleccione Agregar->clase. En el cuadro de diálogo Agregar clase, asigne a la clase el nombre "FactoryHelper" y, después, haga clic en Agregar.

Reemplace todo el contenido del archivo FactoryHelper.cs por el siguiente código. Este código define la interfaz IClassFactory e implementa dos métodos: CreateInstance y LockServer. Este código es el típico reemplazable para implementar un generador de clases y no es específico de la funcionalidad de un proveedor de fuentes, excepto que indicamos que el objeto de clase que se está creando implementa la interfaz IFeedProvider.

// FactoryHelper.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
using System.Runtime.InteropServices;
using WinRT;

namespace ExampleFeedProvider
{
    namespace Com
    {
        static class Guids
        {
            public const string IClassFactory = "00000001-0000-0000-C000-000000000046";
            public const string IUnknown = "00000000-0000-0000-C000-000000000046";
        }

        [ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(Guids.IClassFactory)]
        internal interface IClassFactory
        {
            [PreserveSig]
            int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
            [PreserveSig]
            int LockServer(bool fLock);
        }

        static class ClassObject
        {
            public static void Register(Guid clsid, object pUnk, out uint cookie)
            {
                [DllImport("ole32.dll")]
                static extern int CoRegisterClassObject(
                    [MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
                    [MarshalAs(UnmanagedType.IUnknown)] object pUnk,
                    uint dwClsContext,
                    uint flags,
                    out uint lpdwRegister);

                int result = CoRegisterClassObject(clsid, pUnk, 0x4, 0x1, out cookie);
                if (result != 0)
                {
                    Marshal.ThrowExceptionForHR(result);
                }
            }

            public static int Revoke(uint cookie)
            {
                [DllImport("ole32.dll")]
                static extern int CoRevokeClassObject(uint dwRegister);

                return CoRevokeClassObject(cookie);
            }
        }
    }

    internal class FeedProviderFactory<T> : Com.IClassFactory
            where T : IFeedProvider, new()
    {
        public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
        {
            ppvObject = IntPtr.Zero;

            if (pUnkOuter != IntPtr.Zero)
            {
                Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
            }

            if (riid == typeof(T).GUID || riid == Guid.Parse(Com.Guids.IUnknown))
            {
                // Create the instance of the .NET object
                ppvObject = MarshalInspectable<IFeedProvider>.FromManaged(new T());
            }
            else
            {
                // The object that ppvObject points to does not support the
                // interface identified by riid.
                Marshal.ThrowExceptionForHR(E_NOINTERFACE);
            }

            return 0;
        }

        int Com.IClassFactory.LockServer(bool fLock)
        {
            return 0;
        }

        private const int CLASS_E_NOAGGREGATION = -2147221232;
        private const int E_NOINTERFACE = -2147467262;
    }
}

Registro del objeto de clase de proveedor de fuentes con OLE

En el archivo Program.cs de nuestro ejecutable, llamaremos a CoRegisterClassObject para registrar nuestro proveedor de fuentes con OLE, de forma que el Panel de widgets pueda interactuar con él. Reemplace el contenido de Program.cs por el código siguiente. Esto usa la interfaz FeedProviderFactory que definimos en un paso anterior para registrar la clase auxiliar FeedProvider. Para fines de depuración, en este ejemplo se llama a GetEnabledFeedProviders en la instancia predeterminada FeedManager para obtener una lista de objetos FeedProviderInfo que representan los proveedores de fuentes habilitados. Recorre en bucle los proveedores de fuentes habilitados mediante la propiedad EnabledFeedDefinitionIds para enumerar todos los identificadores de fuente habilitados.

// Program.cs

using Microsoft.Windows.Widgets.Feeds.Providers;
using Microsoft.Windows.Widgets.Providers;
using System; 
using System.Runtime.InteropServices;

namespace ExampleFeedProvider
{

    public static class Program
    {
        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [MTAThread]
        static void Main(string[] args)
        {
            Console.WriteLine("FeedProvider Starting...");
            if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
            {
                WinRT.ComWrappersSupport.InitializeComWrappers();

                uint registrationHandle;
                var factory = new FeedProviderFactory<FeedProvider>();
                Com.ClassObject.Register(typeof(FeedProvider).GUID, factory, out registrationHandle);

                Console.WriteLine("Feed Provider registered.");

                var existingFeedProviders = FeedManager.GetDefault().GetEnabledFeedProviders();
                if (existingFeedProviders != null)
                {
                    Console.WriteLine($"There are {existingFeedProviders.Length} FeedProviders currently outstanding:");
                    foreach (var feedProvider in existingFeedProviders)
                    {
                        Console.WriteLine($"  ProviderId: {feedProvider.FeedProviderDefinitionId}, DefinitionIds: ");
                        var m = WidgetManager.GetDefault().GetWidgetIds();
                        if (feedProvider.EnabledFeedDefinitionIds != null)
                        {
                            foreach (var enabledFeedId in feedProvider.EnabledFeedDefinitionIds)
                            {
                                Console.WriteLine($" {enabledFeedId} ");
                            }
                        }
                    }
                }
                if (GetConsoleWindow() != IntPtr.Zero)
                {
                    Console.WriteLine("Press ENTER to exit.");
                    Console.ReadLine();
                }
                else
                {
                    while (true)
                    {
                        // You should fire an event when all the outstanding
                        // FeedProviders have been disabled and exit the app.
                    }
                }
            }
            else
            {
                Console.WriteLine("Not being launched to service Feed Provider... exiting.");
            }
        }
    }
}

Tenga en cuenta que este ejemplo de código importa la función GetConsoleWindow para determinar si la aplicación se ejecuta como una aplicación de consola, el comportamiento predeterminado de este tutorial. Si la función devuelve un puntero válido, se escribe información de depuración en la consola. De lo contrario, la aplicación se ejecuta como una aplicación de Windows. En ese caso, esperamos al evento que establecimos en el método OnFeedProviderDisabled cuando la lista de proveedores de fuentes habilitados esté vacía y salimos de la aplicación. Para obtener información sobre cómo convertir la aplicación de consola de ejemplo en una aplicación de Windows, consulte Conversión de la aplicación de consola en una aplicación de Windows.

Empaquetar la aplicación del proveedor de fuentes

En la versión actual, solo las aplicaciones empaquetadas se pueden registrar como proveedores de fuentes. Los pasos siguientes le llevarán a través del proceso de empaquetado de la aplicación y la actualización del manifiesto de aplicación para registrar la aplicación con el sistema operativo como proveedor de fuentes.

Creación de un proyecto de empaquetado MSIX

En Explorador de soluciones, haga clic con el botón derecho en la solución y seleccione Agregar->Nuevo proyecto.... En el cuadro de diálogo Agregar un nuevo proyecto, seleccione la plantilla "Proyecto de paquete de aplicación de Windows" y haga clic en Siguiente. Establezca el nombre del proyecto en "ExampleFeedProviderPackage" y haga clic en Crear. Cuando se le solicite, establezca el destino en la versión 22621 o posterior y haga clic en Aceptar. A continuación, haga clic con el botón derecho en el proyecto ExampleFeedProviderPackage y seleccione Agregar->Referencia de proyecto. Seleccione el proyecto ExampleFeedProvider y haga clic en Aceptar.

Adición de la referencia del paquete SDK de Aplicaciones para Windows al proyecto de empaquetado

Debe agregar una referencia al paquete Nuget SDK de Aplicaciones para Windows al proyecto de empaquetado MSIX. En Explorador de soluciones, haga doble clic en el proyecto ExampleFeedProviderPackage para abrir el archivo ExampleFeedProviderPackage.wapproj. Agregue el siguiente XML dentro del elemento Proyecto.

<!--ExampleWidgetProviderPackage.wapproj-->
<ItemGroup>
    <PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
        <IncludeAssets>build</IncludeAssets>
    </PackageReference>  
</ItemGroup>

Nota

Asegúrese de que la versión especificada en el elemento PackageReference coincide con la versión estable más reciente a la que se hizo referencia en el paso anterior.

Si la versión correcta del SDK de Aplicaciones para Windows ya está instalada en el equipo y no desea agrupar el entorno de ejecución del SDK en el paquete, puede especificar la dependencia del paquete en el archivo Package.appxmanifest para el proyecto ExampleFeedProviderPackage.

<!--Package.appxmanifest-->
...
<Dependencies>
...
    <PackageDependency Name="Microsoft.WindowsAppRuntime.1.5.233430000-experimental1" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...

Actualización del manifiesto del paquete

En el Explorador de soluciones, haga clic con el botón derecho en el archivo Package.appxmanifest y seleccione Ver código para abrir el archivo xml del manifiesto. A continuación, debe agregar algunas declaraciones de espacio de nombres para las extensiones de paquete de la aplicación que usaremos. Agregue las siguientes definiciones de espacio de nombres al elemento de nivel superior Package.

<!-- Package.appmanifest -->
<Package
  ...
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"

Dentro del elemento Application, cree un nuevo elemento vacío denominado Extensions. Asegúrese de que aparece después de la etiqueta de cierre de uap:VisualElements.

<!-- Package.appxmanifest -->
<Application>
...
    <Extensions>

    </Extensions>
</Application>

La primera extensión que necesitamos agregar es ComServer. Registra el punto de entrada del ejecutable en el sistema operativo. Esta extensión es el equivalente en aplicaciones empaquetadas a registrar un servidor COM estableciendo una clave del Registro, y no es específica de los proveedores de widgets. Agregue el siguiente elemento com:Extension como elemento secundario del elemento Extensions. Cambie el GUID en el atributo Id del elemento com:Class por el GUID que generó en un paso anterior al definir la clase FeedProvider.

<!-- Package.appxmanifest -->
<Extensions>
    <com:Extension Category="windows.comServer">
        <com:ComServer>
            <com:ExeServer Executable="ExampleFeedProvider\ExampleFeedProvider.exe" Arguments="-RegisterProcessAsComServer" DisplayName="C# Feed Provider App">
                <com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="FeedProvider" />
            </com:ExeServer>
        </com:ComServer>
    </com:Extension>
</Extensions>


A continuación, agregue la extensión que registra la aplicación como proveedor de fuentes. Pegue el elemento uap3:Extension en el siguiente fragmento de código, como elemento secundario del elemento Extensions. Asegúrese de reemplazar el atributo ClassId del elemento COM por el GUID que usó en los pasos anteriores.

<!-- Package.appxmanifest -->
<Extensions>
    ...
    <uap3:Extension Category="windows.appExtension">
        <uap3:AppExtension Name="com.microsoft.windows.widgets.feeds" DisplayName="ContosoFeed" Id="com.examplewidgets.examplefeed" PublicFolder="Public">
            <uap3:Properties>
                <FeedProvider Icon="ms-appx:Assets\StoreLogo.png" Description="FeedDescription">
                    <Activation>
                        <!-- Apps exports COM interface which implements IFeedProvider -->
                        <CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
                    </Activation>
                    <Definitions>
                        <Definition Id="Contoso_Feed"
                            DisplayName="Contoso_Feed Feed"
                            Description="Feed representing Contoso"
                            ContentUri="https://www.contoso.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                        <Definition Id="Fabrikam_Feed"
                            DisplayName="Fabrikam Feed"
                            Description="Feed representing Example"
                            ContentUri="https://www.fabrikam.com/"
                            Icon="ms-appx:Images\StoreLogo.png">
                        </Definition>
                    </Definitions>
                </FeedProvider>
            </uap3:Properties>
        </uap3:AppExtension>
    </uap3:Extension>
</Extensions>

Para obtener descripciones detalladas e información de formato para todos estos elementos, vea Formato XML del manifiesto de paquete del proveedor de fuentes.

Probar un proveedor de fuentes

Asegúrese de que ha seleccionado la arquitectura que coincide con la máquina de desarrollo en la lista desplegable Plataformas de soluciones, por ejemplo, "x64". En el Explorador de soluciones, haga clic con el botón secundario en la solución y seleccione Generar solución. Una vez hecho esto, haga clic con el botón derecho en ExampleWidgetProviderPackage y seleccione Implementar. La aplicación de consola debe iniciarse en la implementación y verá que las fuentes se habilitan en la salida de la consola. Abra el Panel de widgets y debería ver las nuevas fuentes en las pestañas de la parte superior de la sección de fuentes.

Depurar un proveedor de fuentes

Después de anclar las fuentes, la plataforma de widgets iniciará la aplicación del proveedor de fuentes para recibir y enviar información pertinente sobre la fuente. Para depurar la fuente en ejecución, puede asociar un depurador a la aplicación del proveedor de fuentes en ejecución o configurar Visual Studio para que inicie automáticamente la depuración del proceso del proveedor de fuentes una vez iniciado.

Para asocia un elemento al proceso en ejecución:

  1. En Visual Studio, haga clic en Depurar->Asociar al proceso.
  2. Filtre los procesos y busque la aplicación del proveedor de fuentes deseada.
  3. Asocie el depurador.

Para asociar automáticamente el depurador al proceso cuando se inicia por primera vez:

  1. En Visual Studio, haga clic en Depurar -> Otros destinos de depuración -> Depurar paquete de aplicación instalado.
  2. Filtre los paquetes y busque el paquete de proveedor de fuentes deseado.
  3. Selecciónelo y active la casilla que indica No iniciar, pero depurar mi código cuando se inicie.
  4. Haga clic en Adjuntar.

Conversión de la aplicación de consola en una aplicación de Windows

Para convertir la aplicación de consola creada en este tutorial en una aplicación de Windows, haga clic con el botón derecho en el proyecto ExampleFeedProvider en el Explorador de soluciones y seleccione Propiedades. En Aplicación->General, cambie el Tipo de salida de "Aplicación de consola" a "Aplicación de Windows".

Captura de pantalla que muestra las propiedades del proyecto del proveedor de fuentes de C# con el tipo de salida establecido en Aplicación de Windows

Publicación de la aplicación del proveedor de fuentes

Después de haber desarrollado y probado el proveedor de fuentes, puede publicar la aplicación en Microsoft Store para que los usuarios instalen las fuentes en sus dispositivos. Para obtener instrucciones paso a paso para publicar una aplicación, consulta Publicación de la aplicación en Microsoft Store.

La colección feeds Store

Una vez publicada la aplicación en Microsoft Store, puedes solicitar que la aplicación se incluya en la colección de la Tienda feeds que ayuda a los usuarios a detectar aplicaciones que cuentan con fuentes de Windows. Para enviar la solicitud, consulta Enviar tu feed/Board para agregar la colección de la Tienda.