Ricevere contenuti nell'app - integrare Condivisione di Windows

Il foglio di condivisione Windows consente di ricevere contenuti (condivisi da altre app) tramite l'app. Questa guida illustra come registrare l'app come destinazione di condivisione e gestire il contenuto condiviso tra app in pacchetto (MSIX), progressive App Web (PWA) e app Win32 senza pacchetti.

In questo articolo

Sezione Cosa troverai
Prima di dichiarare le funzionalità Dichiara solo i tipi e i formati di file che la tua app gestisce
Implementa la destinazione Condividi per le app pacchettizzate (UWP e desktop pacchettizzate) Dichiarazione del manifest e gestione dell'attivazione per UWP e app desktop in pacchetto
Implementa il target di condivisione per le PWA share_target gestione di manifest e POST
Ricevere condivisioni in un'app Win32 senza pacchetti Concedere l'identità del pacchetto e registrarlo come destinazione di condivisione
Procedure consigliate Raccomandazioni per flussi di ricezione affidabili
Stato di ricezione del report Report sullo stato per condivisioni di grandi dimensioni o di lunga durata
Risoluzione dei problemi Correzioni per problemi comuni di Share Target

Prima di dichiarare le funzionalità

La maggior parte dei bug di integrazione di share-target deriva dalla dichiarazione di più di quanto l'app possa effettivamente gestire. Se l'app dichiara <uap:SupportsAnyFileType />, verrà visualizzata nel foglio di condivisione per ogni tipo di file, inclusi i file che non è in grado di elaborare (ad esempio, un editor di foto visualizzato quando un utente condivide un foglio di calcolo).

Dichiara sempre solo i tipi di file e i formati di dati specifici che l'app può gestire. Ad esempio:

<!-- ✓ 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 /> -->

Riservare <uap:SupportsAnyFileType /> esclusivamente alle applicazioni per lo spostamento di file di uso generico (archiviazione nel cloud, app per il trasferimento di file). Vedi Informazioni di riferimento su DataFormat e FileType per le dichiarazioni per categoria di app.

Implementare la destinazione di condivisione per le app pacchettizzate (UWP e app desktop pacchettizzate)

Questa sezione si applica alle app UWP e alle app desktop in pacchetto (WinUI 3, macchine virtuali Windows, WinForms). Entrambi i pacchetti MSIX vengono forniti con l'identità del pacchetto, quindi dichiarano la destinazione di condivisione allo stesso modo e differiscono solo in che modo gestiscono l'attivazione (illustrato nel passaggio 2).

1. Dichiarare nel manifesto

Modificare il package.appxmanifest per registrarlo come destinazione di condivisione. Dichiara solo i tipi di file e i formati di dati gestiti dall'app:

<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. Gestire l'attivazione della condivisione

Quando l'app viene attivata come destinazione di condivisione, gestire l'evento OnShareTargetActivated :

Annotazioni

OnShareTargetActivated è l'override di attivazione per le app UWP (Windows.UI.Xaml.Application). Le app desktop pacchettizzate (WinUI 3, macchine virtuali Windows, WinForms) supportano l'attivazione della condivisione tramite AppInstance.GetActivatedEventArgs e verificano la presenza di ExtendedActivationKind.ShareTarget. Vedi Ottenere informazioni sull'attivazione per le app in pacchetto.

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
}

Per le app desktop pacchettizzate (WinUI 3, macchine virtuali Windows, WinForms) create con SDK per app di Windows, non esiste alcun override OnShareTargetActivated. Invece, controlla l'attivazione nel metodo Main e verifica la presenza di 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. Scegliere i formati di dati da dichiarare

Usare questo riferimento per decidere cosa dichiarare:

Formato Quando utilizzare App di esempio
StorageItems L'app riceve i file Editor di foto, lettori di documenti
Bitmap L'app riceve immagini Visualizzatori di immagini, app di progettazione
Text L'app riceve testo normale App per prendere appunti, editor di testo
Html L'app riceve contenuto RTF Client di posta elettronica, editor avanzati
Uri / WebLink L'app gestisce i collegamenti Browser, gestioni collegamenti
Rtf L'app riceve testo formattato processori Word

Per altri dettagli, vedere Informazioni di riferimento su DataFormat & FileType.

Implementare la destinazione di condivisione per le App Web progressive (PWA)

Le PWA su Windows si registrano come destinazione di condivisione tramite il manifesto dell'app web. Aggiungere una share_target voce:

{
  "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/*"]
        }
      ]
    }
  }
}

Nel tuo /share route, gestisci la richiesta 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('/');
});

Dichiara solo i tipi di file che il pwa può gestire. Ad esempio, non dichiarare * come tipo di accettazione, a meno che l'app non gestisca effettivamente tutti i file.

Ricevere condivisioni in un'app Win32 senza pacchetti

Per registrarsi come destinazione di condivisione, l'app necessita dell'identità del pacchetto. Se la tua app Win32 è senza pacchetto, assegnale un'identità di pacchetto in uno dei due modi seguenti:

  • Ripacchetto con MSIX (preferito): usare il modello Project di creazione di pacchetti di applicazioni Windows in Visual Studio per un'installazione pulita e attendibile. Vedere Configurare l'applicazione desktop per la creazione di pacchetti MSIX.
  • Pacchetto con posizione esterna (pacchetto sparse): aggiungi un pacchetto MSIX vuoto che include l'identità, la registrazione come destinazione di condivisione e le risorse visive, mentre il programma di installazione esistente continua a gestire i file binari dell'app. Usa questo solo se hai un installer che non puoi convertire in MSIX.

La parte restante di questa sezione illustra l'approccio alla posizione esterna.

1. Creare il manifesto del pacchetto

Crea un oggetto AppxManifest.xml che imposta <uap10:AllowExternalContent>, dichiara identità e capacità e registra la destinazione di condivisione. Mantieni Publisher, PackageName e ApplicationId sincronizzati con il tuo .exe.manifest e il certificato di 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>

Aggiungere un manifesto dell'applicazione (YourApp.exe.manifest) che collega l'eseguibile all'identità del pacchetto:

<?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. Creare e firmare il pacchetto

Usare MakeAppx.exe con l'opzione /nv per compilare un pacchetto contenente solo il manifesto, quindi firmarlo con un certificato attendibile usando 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>

Installare il certificato di firma in una posizione attendibile sul computer.

3. Registrare il pacchetto alla prima esecuzione

Al primo avvio, registrare il pacchetto external-location in modo che l'app venga riavviata con l'identità. Specificare percorsi assoluti per la posizione esterna e l'oggetto firmato .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. Gestire l'attivazione della condivisione

Dopo il riavvio dell'app con identità, gestire ExtendedActivationKind.ShareTarget come illustrato in Gestire l'attivazione della condivisione.

Per esempi completi, vedi l'esempio PhotoStoreDemo (in pacchetto con posizione esterna) e l'esempio di destinazione di condivisione WinUI.

Per la condivisione desktop sul lato sorgente, usare IDataTransferManagerInterop come descritto in Condividere contenuto dall'app.

Procedure consigliate

Usare questo elenco di controllo durante la compilazione dei flussi di ricezione.

Raccomandato Evitare Perché è importante
Dichiarare solo estensioni di file e formati di dati specifici Dichiarazione di <uap:SupportsAnyFileType /> per le app che non spostano file Impedisce la visualizzazione di destinazioni irrilevanti nel foglio di condivisione
Convalidare il formato, il numero, il tipo di file e le dimensioni del file prima dell'elaborazione Supponendo che i dati in ingresso corrispondano sempre alle aspettative Impedisce gli errori di runtime e le esperienze di condivisione interrotte
Dichiarare Uri per i gestori di collegamento e Bitmap + StorageItems per i gestori di immagini Dichiarazioni parziali per payload di condivisione comuni Assicura che l'app venga visualizzata per il contenuto che supporta effettivamente
Usare ReportStarted, ReportDataRetrievede ReportCompleted nei flussi di ricezione a esecuzione prolungata Esecuzione di attività di ricezione di lunga durata senza segnalazione dell'avanzamento Mantiene affidabile l'operazione di condivisione e fornisce lo stato corretto del sistema

Per payload di grandi dimensioni o per elaborazioni più lunghe, segnala lo stato dalla destinazione di condivisione:

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}");
  }
}

Usa ReportCompleted(QuickLink) quando vuoi restituire un QuickLink per condivisioni future.

Risoluzione dei problemi

L'app non viene visualizzata nel foglio di condivisione:

  • Verificare che le dichiarazioni del manifesto corrispondano al contenuto condiviso (controllare i tipi di file e i formati di dati).
  • Per le app in pacchetto, assicurarsi di eseguire l'app con l'identità del pacchetto.
  • Consulta il riferimento DataFormat & FileType per la categoria della tua app.

La mia app compare per contenuti che non può gestire:

  • Restringete gli elenchi SupportedFileTypes e DataFormat solo a ciò che supportate.

Il pannello di condivisione si chiude con un errore:

  • Assicurarsi di chiamare ReportStarted() prima di qualsiasi lavoro asincrono e ReportCompleted() al termine.
  • Gestire le eccezioni e chiamare ReportError() con un messaggio descrittivo.

Non ricevo il file previsto:

  • Verificare che il formato di file corrisponda a un oggetto dichiarato FileType o DataFormat.
  • Aggiungi la logica di convalida nel gestore dell'attivazione per verificare che cosa sta effettivamente arrivando.