Recepción de contenido en la aplicación: integración de Windows Share

La hoja de recursos compartidos de Windows permite recibir contenido (compartido desde otras aplicaciones) a través de la aplicación. En esta guía se explica cómo registrar la aplicación como destino de recurso compartido y controlar el contenido compartido entre aplicaciones empaquetadas (MSIX), Web Apps progresivas (PWA) y aplicaciones Win32 sin empaquetar.

En este artículo

Section Lo que encontrará
Antes de declarar las funcionalidades Declarar solo los tipos de archivo y los formatos que controla la aplicación
Implementar el destino para compartir para aplicaciones empaquetadas (UWP y aplicaciones de escritorio empaquetadas) Control de activación y declaración de manifiesto para UWP y aplicaciones de escritorio empaquetadas
Implementación del destino de recurso compartido para PWA share_target manifiesto y manejo de POST
Recibir elementos compartidos en una aplicación Win32 sin empaquetar Conceder identidad al paquete y registrar como destino para compartir
procedimientos recomendados Recomendaciones para flujos de recepción confiables
Progreso de recepción del informe Informes de estado de recursos compartidos grandes o de larga duración
Solución de problemas Correcciones para problemas comunes de destino de recurso compartido

Antes de declarar las funcionalidades

La mayoría de los errores de integración del destino para compartir provienen de declarar más de lo que su aplicación puede gestionar realmente. Si la aplicación declara <uap:SupportsAnyFileType />, aparecerá en la hoja para compartir para todos los tipos de archivo, incluidos archivos que no puede procesar (por ejemplo, un editor de fotos que aparece cuando un usuario comparte una hoja de cálculo).

Declare siempre solo los tipos de archivo y los formatos de datos específicos que puede controlar la aplicación. Por ejemplo:

<!-- ✓ Correct: declare only what you support -->
<uap:SupportedFileTypes>
  <uap:FileType>.jpg</uap:FileType>
  <uap:FileType>.png</uap:FileType>
</uap:SupportedFileTypes>

<!-- ✗ Incorrect: declares everything -->
<!-- <uap:SupportsAnyFileType /> -->

Reserve <uap:SupportsAnyFileType /> solo para mover archivos de uso general (almacenamiento en la nube, aplicaciones de transferencia de archivos). Consulta Referencia de DataFormat y FileType para obtener declaraciones por categoría de aplicación.

Implementar el destino para compartir para aplicaciones empaquetadas (UWP y aplicaciones de escritorio empaquetadas)

Esta sección se aplica a las aplicaciones para UWP y a las aplicaciones de escritorio empaquetadas (WinUI 3, WPF, WinForms). Ambos se envían como paquetes MSIX con identidad de paquete, por lo que declaran el destino de recurso compartido de la misma manera y solo difieren en cómo controlan la activación (se muestra en el paso 2).

1. Declarar en el manifiesto

Edita tu package.appxmanifest para registrarlo como destino para compartir. Declare solo los tipos de archivo y los formatos de datos que controla la aplicación:

<Extensions>
  <uap:Extension Category="windows.shareTarget">
    <uap:ShareTarget>
      <uap:SupportedFileTypes>
        <uap:FileType>.jpg</uap:FileType>
        <uap:FileType>.jpeg</uap:FileType>
        <uap:FileType>.png</uap:FileType>
        <uap:FileType>.gif</uap:FileType>
        <uap:FileType>.bmp</uap:FileType>
      </uap:SupportedFileTypes>
      <uap:DataFormat>Bitmap</uap:DataFormat>
    </uap:ShareTarget>
  </uap:Extension>
</Extensions>

2. Administrar la activación de Compartir

Cuando tu aplicación se active como destino para compartir, controla el evento OnShareTargetActivated:

Note

OnShareTargetActivated es la anulación de la activación para aplicaciones UWP (Windows.UI.Xaml.Application). Las aplicaciones de escritorio empaquetadas (WinUI 3, WPF, WinForms) reciben la activación para compartir a través de AppInstance.GetActivatedEventArgs y comprueban si hay ExtendedActivationKind.ShareTarget. Consulta Obtener información de activación para aplicaciones empaquetadas.

protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
    ShareOperation shareOperation = args.ShareOperation;
    shareOperation.ReportStarted();

    try
    {
        if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
        {
            IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
            
            // Validate: check count, types, and sizes
            if (items.Count == 0)
            {
                shareOperation.ReportError("No items received.");
                return;
            }

            var file = (IStorageFile)items[0];
            
            // Process the file
            await ProcessImageAsync(file);
        }
        
        shareOperation.ReportCompleted();
    }
    catch (Exception ex)
    {
        shareOperation.ReportError($"Error: {ex.Message}");
    }
}

private async Task ProcessImageAsync(IStorageFile file)
{
    // Your processing logic here
}

Para las aplicaciones de escritorio empaquetadas (WinUI 3, WPF, WinForms) creadas con SDK de Aplicaciones para Windows, no existe ninguna sobrescritura de OnShareTargetActivated. En su lugar, inspeccione la activación en su método Main y compruebe si hay ExtendedActivationKind.ShareTarget:

using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.DataTransfer;

[STAThread]
static void Main(string[] args)
{
    AppActivationArguments activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
    if (activatedArgs.Kind == ExtendedActivationKind.ShareTarget)
    {
        HandleShareAsync(activatedArgs.Data as ShareTargetActivatedEventArgs);
    }
    else
    {
        // Normal launch path
    }
}

static async void HandleShareAsync(ShareTargetActivatedEventArgs args)
{
    ShareOperation shareOperation = args.ShareOperation;
    shareOperation.ReportStarted();

    if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
    {
        IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
        // Process the shared items.
    }

    shareOperation.ReportCompleted();
}

3. Elegir los formatos de datos que se van a declarar

Use esta referencia para decidir qué declarar:

Format Cuándo se deben usar Aplicaciones de ejemplo
StorageItems La aplicación recibe archivos Editores de fotos, lectores de documentos
Bitmap La aplicación recibe imágenes Visores de imágenes, aplicaciones de diseño
Text La aplicación recibe texto sin formato Aplicaciones de notas, editores de texto
Html La aplicación recibe contenido de texto enriquecido Clientes de correo electrónico, editores enriquecidos
Uri / WebLink La aplicación controla los vínculos Exploradores, administradores de vínculos
Rtf La aplicación recibe texto con formato procesadores Word

Para obtener más información, consulte Referencia de DataFormat y FileType.

Implementación del destino de recursos compartidos para Web Apps progresivas (PWA)

Las PWA en Windows se registran como destino para compartir a través del manifiesto de la aplicación web. Agregue una share_target entrada:

{
  "name": "My PWA",
  "short_name": "MyPWA",
  "share_target": {
    "action": "/share",
    "method": "POST",
    "enctype": "multipart/form-data",
    "params": {
      "title": "title",
      "text": "text",
      "url": "url",
      "files": [
        {
          "name": "media",
          "accept": ["image/*", "video/*"]
        }
      ]
    }
  }
}

En la ruta /share, gestione la solicitud POST:

app.post('/share', async (req, res) => {
  const { title, text, url, files } = req.body;

  // Validate and process
  if (files && files.length > 0) {
    const file = files[0];
    // Process the file
    console.log('Received file:', file.originalname);
  }

  if (text) {
    console.log('Received text:', text);
  }

  res.redirect('/');
});

Declare solo los tipos de archivo que puede controlar su PWA. Por ejemplo, no declares * como un tipo de aceptación a menos que la aplicación controle realmente todos los archivos.

Recibir elementos compartidos en una aplicación Win32 sin empaquetar

Para registrarse como destino de recurso compartido, la aplicación necesita la identidad del paquete. Si la aplicación Win32 está desempaquetada, concédale la identidad del paquete de una de estas dos maneras:

  • Volver a empaquetar con MSIX (preferido): use la plantilla de Windows Application Packaging Project en Visual Studio para una instalación limpia y confiable. Consulte Configuración de la aplicación de escritorio para el empaquetado MSIX.
  • Paquete con ubicación externa (paquete disperso): agregue un paquete MSIX vacío que contenga la identidad, el registro de destino del recurso compartido y los recursos visuales, mientras que el instalador existente sigue administrando los archivos binarios de la aplicación. Use esto solo cuando tenga un instalador que no pueda convertir a MSIX.

El resto de esta sección explica el enfoque de la ubicación externa paso a paso.

1. Redactar el manifiesto del paquete

Cree un AppxManifest.xml que establezca <uap10:AllowExternalContent>, declare la identidad y las capacidades, y registre el destino para compartir. Mantenga Publisher, PackageName y ApplicationId sincronizados con su .exe.manifest y certificado de firma.

<Identity Name="PhotoStoreDemo" ProcessorArchitecture="neutral" Publisher="CN=YourPubNameHere" Version="1.0.0.0" />
<Properties>
  <uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Dependencies>
  <TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Capabilities>
  <rescap:Capability Name="runFullTrust" />
  <rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
<Applications>
  <Application Id="PhotoStoreDemo" Executable="PhotoStoreDemo.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
    <Extensions>
      <uap:Extension Category="windows.shareTarget">
        <uap:ShareTarget Description="Send to PhotoStoreDemo">
          <uap:SupportedFileTypes>
            <uap:FileType>.jpg</uap:FileType>
            <uap:FileType>.png</uap:FileType>
          </uap:SupportedFileTypes>
          <uap:DataFormat>StorageItems</uap:DataFormat>
          <uap:DataFormat>Bitmap</uap:DataFormat>
        </uap:ShareTarget>
      </uap:Extension>
    </Extensions>
  </Application>
</Applications>

Agregue un manifiesto de aplicación (YourApp.exe.manifest) que vincule el ejecutable a la identidad del paquete:

<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="PhotoStoreDemo.app" />
  <msix xmlns="urn:schemas-microsoft-com:msix.v1"
        publisher="CN=YourPubNameHere"
        packageName="PhotoStoreDemo"
        applicationId="PhotoStoreDemo" />
</assembly>

2. Crear y firmar el paquete

Use MakeAppx.exe con el modificador /nv para crear un paquete que contenga solo el manifiesto y luego fírmelo con un certificado de confianza mediante SignTool.exe:

MakeAppx.exe pack /d <folder with AppxManifest.xml> /p <output>\mypackage.msix /nv
SignTool.exe sign /fd SHA256 /a /f <path to cert> /p <cert key> <path to package>

Instale el certificado de firma en una ubicación de confianza en la máquina.

3. Registrar el paquete en la primera ejecución

En la primera ejecución, registre el paquete de ubicación externa para que la aplicación se reinicie con la identidad. Proporcione rutas de acceso absolutas a la ubicación externa y a la firma .msix.

[STAThread]
public static void Main(string[] cmdArgs)
{
    if (!ExecutionMode.IsRunningWithIdentity())
    {
        string externalLocation = Environment.CurrentDirectory;
        string externalPkgPath = externalLocation + @"\PhotoStoreDemo.package.msix";

        if (registerPackageWithExternalLocation(externalLocation, externalPkgPath))
        {
            // Registration succeeded - restart so the app runs with identity.
            // Join the arguments into a single string; cmdArgs.ToString() would
            // return the array type name ("System.String[]"), not the arguments.
            string forwardedArgs = cmdArgs is null ? string.Empty : string.Join(" ", cmdArgs);
            Process.Start(Application.ResourceAssembly.Location, arguments: forwardedArgs);
        }
        else
        {
            // Registration failed - run without identity.
            new SingleInstanceManager().Run(cmdArgs);
        }
    }
}

4. Gestionar la activación del uso compartido

Después de que la aplicación se reinicie con identidad, procese ExtendedActivationKind.ShareTarget como se muestra en Controlar la activación de Compartir.

Para obtener ejemplos completos, consulte el ejemplo PhotoStoreDemo (empaquetado con ubicación externa) y el ejemplo de destino de recurso compartido de WinUI.

Para compartir escritorio del lado del origen, use IDataTransferManagerInterop como se describe en Compartir contenido desde su aplicación.

procedimientos recomendados

Usa esta lista de comprobación al crear flujos de recepción.

Recommended Evite ¿Por qué es importante?
Declarar solo extensiones de archivo específicas y formatos de datos Declarar <uap:SupportsAnyFileType /> para aplicaciones que no mueven archivos Evita que aparezcan destinos irrelevantes en la hoja de recursos compartidos
Validar el formato, el recuento, el tipo de archivo y el tamaño de archivo antes de procesar Suponiendo que los datos entrantes siempre coinciden con las expectativas Evita errores en tiempo de ejecución y experiencias de recursos compartidos rotos
Declarar Uri para controladores de vínculos y Bitmap + StorageItems controladores de imágenes Declaraciones parciales para cargas útiles compartidas comunes Garantiza que tu app aparezca para el contenido con el que realmente es compatible.
Usa ReportStarted, ReportDataRetrieved y ReportCompleted en flujos de recepción de larga duración Realizar operaciones de recepción prolongadas sin notificar el progreso Mantiene la operación de uso compartido confiable y proporciona el estado correcto del sistema

Para cargas de gran tamaño o un procesamiento más prolongado, notifica el estado desde el destino de recursos compartidos:

protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
  ShareOperation shareOperation = args.ShareOperation;
  shareOperation.ReportStarted();

  try
  {
    // Acquire the data your app needs.
    var items = await shareOperation.Data.GetStorageItemsAsync();
    shareOperation.ReportDataRetrieved();

    // Process data.
    await ProcessAsync(items);

    shareOperation.ReportCompleted();
  }
  catch (Exception ex)
  {
    shareOperation.ReportError($"Share failed: {ex.Message}");
  }
}

Use ReportCompleted(QuickLink) cuando desee devolver un QuickLink para recursos compartidos futuros.

Troubleshooting

Mi aplicación no aparece en la hoja Compartir:

  • Compruebe que las declaraciones de manifiesto coinciden con el contenido que se comparte (compruebe los tipos de archivo y los formatos de datos).
  • En el caso de las aplicaciones empaquetadas, asegúrese de que ejecuta la aplicación con la identidad del paquete.
  • Compruebe la referencia de DataFormat y FileType para la categoría de la aplicación.

Mi aplicación aparece para contenido que no puede gestionar:

  • Reduzca sus listas SupportedFileTypes y DataFormat solo a lo que admita.

La hoja para compartir se cierra con un error:

  • Asegúrese de llamar a ReportStarted() antes de cualquier operación asíncrona y a ReportCompleted() al terminar.
  • Controle las excepciones y llame a ReportError() con un mensaje descriptivo.

No recibo el archivo que espero:

  • Compruebe que el formato de archivo coincide con un declarado FileType o DataFormat.
  • Agregue lógica de validación en el controlador de activación para inspeccionar lo que realmente llega.