Maggio 2018

Volume 33 Numero 5

Il presente articolo è stato tradotto automaticamente.

Piattaforma UWP - Chiusura dei gap tra la piattaforma UWP e Win32

Dal Andrew Whitechapel

Uno dei temi importanti per l'aggiornamento più recente di Windows è stata per chiudere il gap tra la piattaforma UWP (Universal Windows) e Win32 app per i modelli tradizionali. Come parte di questo lavoro richiesto, Microsoft ha introdotto i miglioramenti delle principali tre:

  • Istanze multiple
  • App UWP console
  • Accesso più ampio del file system

Le funzionalità sono in gran parte indipendente ma correlata. Vale a dire, è possibile creare un'app multi-istanza che è un'applicazione a finestre regolare o un'app console e può o non può essere più ampia del file system accedere. Allo stesso modo, è possibile creare un'app console non, multi-istanza regolari che dispone dell'ampia del file system accesso. Una restrizione è che un'applicazione console deve essere configurata per supportare istanze multiple.

Istanze multiple

In Win32, Linux e altri ambienti di modello di app, istanze multiple, il valore predefinito sono sempre stato. In UWP, contrasto forte, il valore predefinito è sempre stato istanze singolo, e, in realtà, istanze multiple non era supportata affatto fino ad ora.

Senza istanze multiple, alcune App hanno fatto ricorso a un'architettura multi-windowing invece che in genere comporta un impegno notevole e i risultati delle complessità e fragilità a livello di. È necessario investire un notevole sforzo nella gestione di windows, invece di occuparsi dei requisiti di dominio. Processo singolo multi-windowing risente anche da problemi di affidabilità: Se si blocca la singola istanza, arrestate tutte le relative finestre; Ciò non accade per multi-creazione di istanze, in cui ogni istanza viene eseguito come processo separato.

Nel modello a istanza singola, l'utente può attivare un'app in diversi modi: tramite una scelta riquadro nell'avvio; tramite un URL o protocollo l'attivazione; facendo doppio clic su un file con un'estensione registrata per l'app; E così via. L'app viene avviata la prima attivazione (di qualsiasi tipo). Successivamente, è sufficiente chiamano tutte le attivazioni successive nell'istanza in esecuzione l'app, l'applicazione può gestire l'override del metodo OnActivated.

La nuova funzionalità di istanze multiple permette alle App UWP a funzionare come applicazioni Win32: Se un'istanza di un'app è in esecuzione e viene ricevuta una richiesta di attivazione successivi, la piattaforma non chiama per attivare l'istanza esistente. Al contrario, creerà una nuova istanza in un processo separato.

Poiché questa funzionalità è dovuta in larga misura a parità di Win32, inizialmente è supportato solo sul Desktop e IoT. Sono stati introdotti due livelli di supporto per istanze multiple:

  • App UWP multi-istanza: Questo vale per il caso più semplice, in cui l'app desidera solo poter dichiarare che deve essere creata un'istanza multipla.
  • Reindirizzamento di multi-istanza App della piattaforma UWP: Questo è il caso complesso, in cui l'app desidera inoltre multi-istanza, ma deve anche disporre di una parola per esattamente come viene attivata ogni istanza.

Per entrambi i casi, viene fornito un modello di progetto di Visual Studio, come illustrato figura 1.

Nuovi modelli di progetto per le app Multi-istanza
Figura 1 nuovi modelli di progetto per le app Multi-istanza

Nel caso semplice, il modello di progetto genera codice che è quasi identico al codice del modello applicazione vuota. L'unica differenza è in uso dell'attributo SupportsMultipleInstances nel manifesto dell'applicazione. Esistono due dichiarazioni aggiuntive: Il primo è spazi dei nomi XML desktop4 e iot2 nella parte superiore del manifesto:

xmlns:desktop4="https://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="https://schemas.microsoft.com/appx/manifest/iot/windows10/2"
  IgnorableNamespaces="uap mp desktop4 iot2">

Il secondo aggiunge l'attributo nell'elemento < applicazione >:

<Application
  Id="App8" Executable="$targetnametoken$.exe" EntryPoint="App8.App"
  desktop4:SupportsMultipleInstances="true"
  iot2:SupportsMultipleInstances="true">

Se si sta aggiornando il codice app esistente invece di generare una nuova app, puoi semplicemente aggiungere manualmente queste voci al manifesto. Dopo aver eseguito questo, è possibile compilare l'app e avviare più istanze. Con questo manifesto voce, ogni volta che viene attivato l'app, ovvero se da una scelta del riquadro o qualsiasi altro attivazione contratto supportato dall'applicazione, ad esempio associazione di file o protocollo di avvio, ovvero ogni attivazione comporterà un'istanza separata. È semplicissimo.

Reindirizzamento di multi-istanza

Per la maggior parte delle App, è necessario eseguire altre operazioni è aggiungere la voce del manifesto, ma per un'app che richiede un miglior controllo sui relativi attivazioni di istanza, è possibile utilizzare il secondo modello. Questo consente di aggiungere le voci di manifesto stesso esatto e aggiunge anche un file aggiuntivo (Program.cs per le app c#) o effettuata per C++ che contiene una funzione Main standard, come illustrato nella figura 2. Utilizza una nuova classe AppInstance introdotta in questa versione.

Figura 2 Standard Main (funzione) per il reindirizzamento di multi-istanza

static void Main(string[] args)
{
  IActivatedEventArgs activatedArgs = AppInstance.GetActivatedEventArgs();
  if (AppInstance.RecommendedInstance != null)
  {
    AppInstance.RecommendedInstance.RedirectActivationTo();
  }
  else
  {
    uint number = CryptographicBuffer.GenerateRandomNumber();
    string key = (number % 2 == 0) ? "even" : "odd";
    var instance = AppInstance.FindOrRegisterInstanceForKey(key);
    if (instance.IsCurrentInstance)
    {
      global::Windows.UI.Xaml.Application.Start((p) => new App());
    }
    else
    {
      instance.RedirectActivationTo();
    }
  }
}

La prima cosa che svolge la funzione è acquisire argomenti di attivazione di questa istanza. L'app useranno probabilmente le informazioni contenute in questi argomenti come parte della logica di reindirizzamento.

In alcuni scenari, la piattaforma potrebbe indicare un'istanza consigliata. In tal caso, è possibile reindirizzare l'attivazione a quell'istanza invece se si desidera, tramite il metodo AppInstance.RedirectActivationTo. In altre parole, l'app è possibile scegliere di consentire questa richiesta di attivazione essere reindirizzati a un'istanza esistente. Se reindirizza, quindi l'istanza di destinazione viene attivata e viene richiamato il metodo OnActivated, e la nuova istanza viene terminata.

Se la piattaforma non indica un'istanza preferita, si proseguo e creare una chiave. Nell'esempio di codice costituisce una chiave da un numero casuale, ma che normalmente sarebbero sostituire questo codice e creare una chiave in base alla logica definita dall'app. In genere ciò potrebbe essere basata sugli argomenti di attivazione recuperati in precedenza. Ad esempio, se gli argomenti di attivazione sono di tipo FileActivatedEventArgs, l'app può usare il nome file specificato come parte della chiave. Dopo che è stato composto la chiave, passarlo al metodo FindOrRegisterInstanceForKey, che restituisce un oggetto dell'istanza dell'applicazione che rappresenta un'istanza di questa app. Per determinare quale istanza da restituire, il metodo eseguite due operazioni:

  • Cerca un'istanza esistente di app che questa chiave è già registrato.
  • Se nessuna istanza esistente è già registrato questa chiave, registra l'istanza corrente con questa chiave.

Se è stato registrato correttamente questa istanza, è possibile ora proseguiamo ed eseguire l'inizializzazione di app normale. Per un'app XAML, in tal caso la chiamata Application.Start con una nuova istanza della classe App. Se un'altra istanza è già registrato questa chiave, è ora possibile reindirizzare invece questa attivazione a tale istanza e consentire a questa istanza terminare. Ad esempio, si consideri un'applicazione che modifica i file. Se l'utente ha Foo.doc aperta per le modifiche nell'app e quindi tenta nuovamente ad aprire Foo.doc, è possibile scegliere l'app reindirizzare l'attivazione di secondo per l'istanza che dispone già di Foo.doc open, ovvero e impedire all'utente di aprire il file stesso in più istanze. La logica per decidere se inviare o meno reindirizzare e l'istanza da selezionare come destinazione del reindirizzamento, è completamente definita dall'app.

Per le app XAML, il metodo Main viene normalmente generato automaticamente e nascosti da parte dello sviluppatore. Questo comportamento viene eliminato nel modello "multi-istanza con il reindirizzamento". Se si sta aggiornando un'app esistente, è possibile eliminare il principale predefinito aggiungendo DISABLE_XAML_GENERATED_MAIN all'elenco dei simboli di compilazione condizionale nelle proprietà di compilazione per l'app. In alcuni tipi di app, ad esempio, un'app C++ DirectX, ovvero la funzione principale non sia nascosto. A parte ciò, uso dell'app un DirectX delle nuove API segue gli stessi modelli come illustrato nell'esempio XAML.

Si noti che un'app può utilizzare solo i metodi GetActivatedEventArgs e RedirectActivationTo durante Main; Se queste vengono definite in qualsiasi altro punto, non riuscirà. Infatti, se si desidera partecipare nel reindirizzamento di attivazione, è necessario eseguire questa operazione estremamente anticipata in tutta la durata del processo di app e certamente prima di qualsiasi windows vengono creati.

D'altro canto, è possibile utilizzare i metodi rimanenti dell'istanza dell'applicazione e le proprietà in qualsiasi momento. In particolare, è possibile utilizzare FindOrRegisterInstanceForKey per aggiornare la chiave per l'istanza corrente, quando necessario. Ad esempio, se la chiave è stata basata su un nome di file e il file è stato chiuso in un secondo momento, aggiornare la registrazione alla chiave in quel momento. È inoltre possibile utilizzare il metodo di annullamento della registrazione per annullare la registrazione completamente se per qualche motivo che non si desidera più questa istanza specifica per prendere parte il reindirizzamento di attivazione. Inoltre, in qualsiasi momento, è possibile utilizzare il metodo AppInstance.GetInstances per ottenere un elenco di tutte le istanze registrate della tua app, incluse le relative chiavi, in modo che è possibile ragionare sul relativo stato.

Considerazioni aggiuntive

Istanze multiple sono una funzionalità avanzata di principale e la versione iniziale riguarda solo gli scenari principali. In particolare, il supporto è incluso per istanze multiple un'app in primo piano, le applicazioni console e la maggior parte delle attività in background out-of-process inclusi i servizi di app. Tuttavia, è presente alcun supporto in questa versione per le attività ApplicationTrigger o tutte le attività in background in-Process.

Durante lo sviluppo, Microsoft ha dedicato tempo considerevole test un'ampia gamma di App Store esistenti per vedere come si eseguono quando multi-istanza. Da questo oggetto, Microsoft appreso che le app rientrano in tre ampie categorie:

  • App che non hanno alcun motivo per essere creata un'istanza multipla. Queste App appena non optare per la funzionalità.
  • App che desidera essere creata un'istanza multipla e continuerà a funzionare correttamente senza alcuna modifica al codice. Queste App possono semplicemente acconsentire esplicitamente a istanze multiple e chiamarlo eseguita.
  • App che desidera essere multi-istanza, ma devono essere usate per consentire le differenze nel modello di esecuzione.

Il problema con le app della terza categoria comune è che stanno usando alcune risorse centrali, forse una cache o un database o un altro file e quando a istanza singola è stato in modo sicuro supponendo che l'app disponga di accesso esclusivo per questa risorsa. Quando si sceglie di partecipare a istanze multiple, potrebbero essere presenti più istanze durante il tentativo di accedere alla risorsa. In questo scenario, l'app deve essere utilizzato per sincronizzare l'accesso, il blocco letture e scritture e così via, in altre parole, tutti la sincronizzazione consueta emette tale tradizionali Win32 App devono tenere in considerazione.

Ad esempio ovvio, prendere in considerazione l'utilizzo dell'archiviazione locale dell'app. Questo è un esempio di una risorsa in cui l'accesso è vincolato in un pacchetto, non a intervalli di processo, e, naturalmente tutte le istanze di un'app condividono lo stesso pacchetto. Anche se ogni istanza dell'app è in esecuzione come processo separato, tutti usino la stessa risorsa di archiviazione locale e le impostazioni, come rappresentato dalle API di ApplicationData.Current. Se si sta eseguendo operazioni di accesso ai dati nel servizio di archiviazione locale, è necessario considerare come evitare conflitti. Un'opzione consiste nell'utilizzare i file di istanza univoco, in cui le operazioni dell'istanza non sono in conflitto con qualsiasi altro. In alternativa, se si desidera utilizzare un file comune tra più istanze, è necessario bloccare e sbloccare l'accesso al file in modo appropriato. È possibile utilizzare meccanismi standard, ad esempio un Mutex denominato per questo oggetto.

Console di App UWP

Un altro spazio evidente nel landscape UWP è la possibilità di creare un'applicazione console headless. In Win32 e altri ambienti, è possibile creare uno strumento da riga di comando che utilizza la finestra della console per l'input e output. In tal caso, è stato aggiunto il supporto anche. Anche in questo caso è un nuovo modello di progetto di Visual Studio e come con le app multi-istanza, verrà generato voci aggiuntive del manifesto. Questa funzionalità è limitata ai Desktop e IoT, ovvero non minimi poiché solo tali SKU dispongono effettivamente di finestre della console ora. Gli stessi spazi dei nomi XML vengono dichiarati. Elemento < Application > include attributi SupportsMultipleInstances sia sottosistema, con un sottosistema "console". Applicazioni console devono essere creata un'istanza di multi-si tratta del modello previsto per le app lo spostamento da applicazioni di console Win32 tradizionale. Inoltre, l'applicazione include un AppExecutionAlias, e ciò ha anche il nuovo attributo di sottosistema, come illustrato nel figura 3.

Figura 3 ulteriori voci di manifesto per un'applicazione Console

<Application Id="App"
  Executable="$targetnametoken$.exe"
  EntryPoint="App9.App"
  desktop4:Subsystem="console"
  desktop4:SupportsMultipleInstances="true"
  iot2:Subsystem="console"
  iot2:SupportsMultipleInstances="true">
...
  <Extensions>
    <uap5:Extension
      Category="windows.appExecutionAlias"
      Executable="App9.exe"
      EntryPoint="App9.App">
      <uap5:AppExecutionAlias
         desktop4:Subsystem="console" 
        iot2:Subsystem="console">
        <uap5:ExecutionAlias Alias="App9.exe"/>
      </uap5:AppExecutionAlias>
    </uap5:Extension>
  </Extensions>
</Application>

È possibile modificare il valore dell'Alias per un nome appropriato per l'app. Nuovamente, a istanze multiple, la generazione del codice include un file Program.cs o effettuata. Il codice generato viene fornito un esempio del modo in cui è possibile implementare la funzione principale necessaria, come illustrato nell'esempio di C++ figura 4. È possibile sostituire tutto il codice in main con il proprio codice personalizzato.

Figura 4 modello generato codice per una funzione Main App Console

int __cdecl main()
{
  // You can get parsed command-line arguments from the CRT globals.
  wprintf(L"Parsed command-line arguments:\n");
  for (int i = 0; i < __argc; i++)
  {
    wprintf(L"__argv[%d] = %S\n", i, __argv[i]);
  }
  wprintf(L"Press Enter to continue:");
  getchar();
}

Dopo aver compilato e distribuito l'app, sarà possibile eseguirla da un prompt dei comandi normale, finestra di PowerShell o Windows-R, come illustrato figura 5. Si noti che poiché l'app Usa la finestra della console, sono non previsti creare altre finestre, e in effetti, ciò non è supportato. L'app può ora utilizzare tutte le APIs System.Console, oltre a numerose API Win32 tradizionale che è stato aggiunto all'elenco approvato specificamente per supportare le applicazioni console.

L'esecuzione di una Console di App UWP dalla riga di comando
Figura 5, l'esecuzione di una Console di App UWP dalla riga di comando

Con questa funzionalità, è infine possibile compilare App console della riga di comando che possono sfruttare i vantaggi della piattaforma UWP, tra cui creazione dei pacchetti APPX, archiviare pubblicazione, gli aggiornamenti facile e così via.

Accesso più ampio del File System

Fino ad ora, un'app UWP è stata in grado di accedere a determinate cartelle specifiche, ad esempio la libreria di immagini e il catalogo musicale e quindi solo se l'applicazione dichiara queste informazioni come funzionalità nel proprio manifesto. Tuttavia, l'app è stato possibile ottenere l'accesso a qualsiasi altro file system per la generazione di una finestra di dialogo FilePicker e chiedere conferma all'utente di scegliere una posizione, che concede le autorizzazioni di app.

A questo punto, la terza funzionalità principale aggiunta per la parità di Win32 aumenta il livello di accesso del file system per App UWP. Tale operazione viene eseguita in due modi includendo:

  • Accedere in modo implicito alla directory di lavoro corrente.
  • Accesso ampie del file system gestita da una capacità limitata.

Qualsiasi app UWP (un'applicazione a finestre regolare o un'applicazione console) che dichiara un AppExecutionAlias ora viene concesso accesso implicito al file e cartelle nella directory di lavoro corrente e verso il basso, qualora venga attivata da una riga di comando. Directory di lavoro corrente è da qualsiasi posizione del file system l'utente sceglie di eseguire il AppExecutionAlias. In questo stato opinabile per molto tempo, come il modello UWP è sempre stato prestare particolare attenzione sulla concessione dell'accesso del file system per App. In generale, si è deciso che l'utente sceglie di eseguire l'app da una specifica posizione è equivalente all'utente di scegliere un percorso in una finestra di dialogo FilePicker, in termini di concessione di autorizzazioni.

È importante notare che l'app abbia esattamente le stesse autorizzazioni di file dell'utente che sta eseguendo l'app, pertanto possono comunque essere presenti file o cartelle non può accedere all'app, perché l'utente non sono accessibili, ovvero. Ad esempio, se l'utente non è possibile visualizzare un file nascosto quando si esegue un comando dir, l'app anche non è in grado di visualizzare il file nascosto.

Per sfruttare i vantaggi di questa funzionalità, è possibile progettare la sostituzione OnActivated cercare CommandLineActivatedEventArgs. La traccia includerà CurrentDirectoryPath, che in questo caso sarà il percorso del file system da cui l'utente ha eseguito l'AppExecutionAlias. Figura 6 illustra un esempio; a questo punto, l'app estrae la directory corrente e lo passa a MainPage.

Figura 6 si esegue l'override OnActivated per l'attivazione della riga di comando

protected override void OnActivated(IActivatedEventArgs args)
{
  switch (args.Kind)
  {
    case ActivationKind.CommandLineLaunch:
      CommandLineActivatedEventArgs cmdLineArgs =
         args as CommandLineActivatedEventArgs;
      CommandLineActivationOperation operation = cmdLineArgs.Operation;
      string activationPath = operation.CurrentDirectoryPath;
      Frame rootFrame = Window.Current.Content as Frame;
      if (rootFrame == null)
      {
        rootFrame = new Frame();
        Window.Current.Content = rootFrame;
      }
      rootFrame.Navigate(typeof(MainPage), activationPath);
      Window.Current.Activate();
      break;
  }
}

È quindi possibile codificare la sostituzione di MainPage OnNavigatedTo per recuperare il percorso da NavigationEventArgs in ingresso, come illustrato nella figura 7. In questo esempio, l'app è l'inizializzazione di un StorageFolder da questo percorso e quindi la creazione di un controllo TreeView per i file e cartelle da qui verso il basso.

Figura 7 compilazione di un albero del File System da Directory di lavoro corrente

protected async override void OnNavigatedTo(NavigationEventArgs e)
{
  string activationPath = e.Parameter as string;
  argumentsText.Text = activationPath;
  fileTreeView.RootNodes.Clear();
  try
  {
    StorageFolder folder =
       await StorageFolder.GetFolderFromPathAsync(activationPath);
    if (folder != null)
    {
      TreeViewNode rootNode = new TreeViewNode() { Content = folder.Name };
      IReadOnlyList<StorageFolder> folders = await folder.GetFoldersAsync();
      GetDirectories(folders, rootNode);
      fileTreeView.RootNodes.Add(rootNode);
    }
  }
  catch (Exception ex)
  {
    Debug.WriteLine(ex.Message);
  }
}

Nuova funzionalità

Il secondo modo in cui viene fornito l'accesso più esteso del file system è tramite una nuova funzionalità limitate. Per utilizzare questo, è necessario dichiarare lo spazio dei nomi XML restrictedcapabilities nella parte superiore del manifesto dell'app e includono broadFileSystemAccess nell'elenco < funzionalità >:

xmlns:rescap="https://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
  IgnorableNamespaces="uap mp uap5 rescap">
...
  <Capabilities>
    <rescap:Capability Name="broadFileSystemAccess" />
  </Capabilities>

Se si dichiara alcuna funzionalità limitate, ciò Attiva controlli aggiuntivi in fase di che invio del pacchetto nell'archivio per la pubblicazione. Se l'app viene concessa questa funzionalità, avrà lo stesso accesso al file system come l'utente che esegue l'app. Non solo dalla directory di lavoro corrente ma everywhere che l'utente disponga dell'accesso. Se si dispone di questa funzionalità non è necessario un AppExecutionAlias. Poiché si tratta di una funzione molto potente, Microsoft concederà la funzionalità solo se lo sviluppatore dell'app fornisce ragioni importanti per la richiesta, una descrizione del modo in cui verrà utilizzato e una spiegazione del modo in cui questo vantaggio per l'utente.

Se si dichiara la funzionalità broadFileSystemAccess, non è necessario dichiarare qualsiasi funzionalità con ambito più ristretto del file system (documenti, immagini o video); in effetti, un'app non deve dichiarare broadFileSystemAccess sia una delle altre tre funzionalità del file system.

Anche dopo che l'app è stata concessa la funzionalità, è inoltre disponibile un controllo di runtime, perché ciò costituisce un problema di privacy per l'utente. Come altri problemi di privacy, l'app verrà attivata una richiesta di consenso dell'utente al primo utilizzo. Se l'utente sceglie di negare l'autorizzazione, l'app deve essere resiliente a questo. L'utente può inoltre modificare dovesse cambiare idea in qualsiasi momento, accedendo alla pagina pertinente File system sotto l'elenco di Privacy nelle impostazioni, come illustrato figura 8.

Nuova pagina di sistema di File nelle impostazioni
Figura 8 nuova pagina File System nelle impostazioni

Si noti che per poter sfruttare l'accesso alla directory di lavoro corrente sia le autorizzazioni broadFileSystemAccess, il codice deve usare le API di Windows. Storage WinRT per la gestione dei file.

Conclusioni

Una delle strategie a lungo termine con la piattaforma UWP consiste nel chiudere gli spazi vuoti con tecnologie meno recenti di app, Win32 in particolare, in modo che la piattaforma UWP è un'opzione valida per più tipi di app nel corso del tempo. Con l'introduzione del supporto per istanze multiple true, le app UWP console e un accesso più ampio del file system, tre ulteriori passaggi di grandi dimensioni sono stati eseguiti sul proprio questo processo. Codice di esempio è disponibile all'indirizzo bit.ly/2GtzM3T, e sono disponibili i modelli di progetto di Visual Studio al bit.ly/2HApmii e bit.ly/2FEIAXu.


Andrew Whitechapelè program manager della divisione di Microsoft Windows, responsabile app attivazione del flusso di lavoro per la piattaforma Windows universale.

Grazie ai seguenti esperti per la revisione dell'articolo: Jason Holmes, Tim Kurtzman, Anis Mohammed Khaja Mohideen


Viene illustrato in questo articolo nel forum di MSDN Magazine