Novità di C++/WinRT

Man mano che vengono rilasciate versioni di C++/WinRT successive, questo argomento descrive le novità e le modifiche.

Riepilogo dei miglioramenti o delle aggiunte recenti al mese di marzo 2020

Tempi di compilazione ridotti del 23%

I team di C++/WinRT e del compilatore C++ hanno collaborato per ridurre il più possibile i tempi di compilazione. I dati di analisi del compilatore sono stati esaminati attentamente per comprendere come ristrutturare gli elementi interni di C++/WinRT, in modo da consentire al compilatore C++ di eliminare il sovraccarico in fase di compilazione, e come migliorare il compilatore C++ stesso per gestire la libreria C++/WinRT. C++/WinRT è stato ottimizzato per il compilatore e quest'ultimo è stato ottimizzato per C++/WinRT.

Prendiamo ad esempio lo scenario del caso peggiore in cui viene creata un'intestazione precompilata (PCH) che contiene ogni singola intestazione dello spazio dei nomi della proiezione C++/WinRT.

Versione Dimensione PCH (byte) Ore
C++/WinRT di luglio, con Visual C++ 16.3 3.004.104.632 31
C++/WinRT versione 2.0.200316.3, con Visual C++ 16.5 2.393.515.336 24

Abbiamo ottenuto una riduzione della dimensione del 20% e una riduzione del tempo di compilazione del 23%.

Supporto di MSBuild migliorato

Abbiamo dedicato molto impegno a migliorare il supporto di MSBuild per una vasta gamma di scenari diversi.

Memorizzazione nella cache di factory ancora più veloce

Abbiamo migliorato l'inlining della cache di factory per ottenere percorsi critici inline più efficienti, consentendo così un'esecuzione più veloce.

Questo miglioramento non influisce sulla dimensione del codice, come descritto di seguito in Generazione del codice con gestione delle eccezioni ottimizzata, se l'applicazione usa la gestione delle eccezioni C++ in modo intensivo. Puoi quindi compattare il codice binario usando l'opzione /d2FH4, che è attiva per impostazione predefinita nei nuovi progetti creati con Visual Studio 2019, versione 16.3 e successive.

Conversione boxing più efficiente

Quando viene usato in un'applicazione XAML, winrt::box_value è ora più efficiente (vedi Boxing e unboxing). Anche per le applicazioni che eseguono molte conversioni boxing potrai notare una riduzione della dimensione del codice.

Supporto per l'implementazione di interfacce COM che implementano IInspectable

Se devi implementare un'interfaccia COM (non Windows Runtime) che sta semplicemente implementando IInspectable, puoi ora eseguire questa operazione con C++/WinRT. Vedi Interfacce COM che implementano IInspectable.

Miglioramenti del blocco dei moduli

Il controllo del blocco dei moduli consente ora sia scenari di hosting personalizzati sia l'eliminazione del blocco a livello di modulo. Vedi la richiesta pull sui miglioramenti del blocco dei moduli.

Supporto per le informazioni sugli errori di runtime non Windows

Alcune API (anche di Windows Runtime) segnalano errori senza usare API di origine degli errori di Windows Runtime. In casi come questi, C++/WinRT ora ricorre all'uso delle informazioni sugli errori COM. Vedi Supporto di C++/WinRT per informazioni sugli errori non WinRT.

Abilitazione del supporto per i moduli C++

Il supporto per i moduli C++ è di nuovo disponibile, ma solo in via sperimentale. La funzionalità non è ancora completa nel compilatore C++.

Ripresa più efficiente delle coroutine

Le coroutine C++/WinRT funzionano già bene, ma siamo costantemente alla ricerca di soluzioni per migliorarle. Vedi la richiesta pull su come migliorare la scalabilità della ripresa delle coroutine.

Nuovi helper asincroni when_all e when_any

La funzione helper when_all crea un oggetto IAsyncAction, che viene completato al termine di tutti gli elementi awaitable forniti. La funzione helper when_any crea un oggetto IAsyncAction, che viene completato al termine di uno degli elementi awaitable forniti.

Vedi le richieste pull su come aggiungere un helper asincrono when_any e un helper asincrono when_all.

Altre ottimizzazioni e aggiunte

Abbiamo introdotto anche numerose correzioni di bug e ottimizzazioni e aggiunte secondarie, inclusi vari miglioramenti per semplificare il debug e ottimizzare gli elementi interni e le implementazioni predefinite. Segui questo collegamento per un elenco completo: https://github.com/microsoft/xlang/pulls?q=is%3Apr+is%3Aclosed.

Funzionalità nuove e aggiornate di C++/WinRT 2.0

Per altre informazioni sull'estensione di Visual Studio C++/WinRT (VSIX), sul pacchetto NuGet Microsoft.Windows.CppWinRT e sullo strumento cppwinrt.exe, incluse le istruzioni su come installarli, vedi Supporto di Visual Studio per C++/WinRT, XAML, l'estensione VSIX e il pacchetto NuGet.

Modifiche all'estensione di Visual Studio C++/WinRT (VSIX) per la versione 2.0

  • Il visualizzatore di debug supporta ora Visual Studio 2019, oltre a continuare a supportare Visual Studio 2017.
  • Sono state apportate numerose correzioni di bug.

Modifiche al pacchetto NuGet Microsoft.Windows.CppWinRT per la versione 2.0

  • Nel pacchetto NuGet Microsoft.Windows.CppWinRT è ora incluso lo strumento cppwinrt.exe che genera su richiesta intestazioni di proiezione della piattaforma per ogni progetto. Pertanto, lo strumento cppwinrt.exe non dipende più da Windows SDK, anche se viene ancora distribuito con l'SDK per motivi di compatibilità.
  • cppwinrt.exe genera ora le intestazioni di proiezione in ogni cartella intermedia specifica della configurazione o della piattaforma ($IntDir) per consentire la generazione di build parallele.
  • Il supporto per la compilazione in C++/WinRT (props/targets) è ora interamente documentato, offrendo così la possibilità di personalizzare i file di progetto in modo manuale. Vedi il file readme del pacchetto NuGet Microsoft.Windows.CppWinRT.
  • Sono state apportate numerose correzioni di bug.

Modifiche a C++/WinRT per la versione 2.0

Open source

Lo strumento cppwinrt.exe prende un file di metadati di Windows Runtime (.winmd) e genera una libreria C++ standard che proietta le API descritte nei metadati. Puoi così utilizzare tali API dal codice C++/WinRT.

Questo strumento è ora un progetto completamente open source, disponibile su GitHub. Visita Microsoft/cppwinrt.

Librerie xlang

Una libreria di sole intestazioni completamente portabile (per l'analisi del formato di metadati ECMA-335 usato da Windows Runtime) costituirà la base di tutti gli strumenti di Windows Runtimes e xlang in futuro. In particolare, abbiamo anche riscritto completamente lo strumento cppwinrt.exe usando le librerie xlang. Ciò consentirà di eseguire query sui metadati più accurate, risolvendo alcuni annosi problemi relativi alla proiezione del linguaggio C++/WinRT.

Minori dipendenze

Grazie al lettore di metadati xlang, lo strumento cppwinrt.exe ha meno dipendenze. È quindi molto più flessibile, oltre a essere utilizzabile in diversi scenari, soprattutto in ambienti di compilazione vincolati. In particolare, non dipende più da RoMetadata.dll.   Ecco le dipendenze per cppwinrt.exe 2.0.  

  • ADVAPI32.dll
  • KERNEL32.dll
  • SHLWAPI.dll
  • XmlLite.dll

Tutte queste DLL sono disponibili non solo in Windows 10, ma anche in Windows 7 e Windows Vista. Se lo vuoi, il server di compilazione precedente che esegue Windows 7 può ora eseguire cppwinrt.exe per generare intestazioni C++ per il progetto. Con un po' di lavoro, se ti interessa puoi anche eseguire C++/WinRT in Windows 7.

Confronta l'elenco sopra riportato con queste dipendenze di cppwinrt.exe 1.0.

  • ADVAPI32.dll
  • SHELL32.dll
  • api-ms-win-core-file-l1-1-0.dll
  • XmlLite.dll
  • api-ms-win-core-libraryloader-l1-2-0.dll
  • api-ms-win-core-processenvironment-l1-1-0.dll
  • RoMetadata.dll
  • SHLWAPI.dll
  • KERNEL32.dll
  • api-ms-win-core-rtlsupport-l1-1-0.dll
  • api-ms-win-core-heap-l1-1-0.dll
  • api-ms-win-core-timezone-l1-1-0.dll
  • api-ms-win-core-console-l1-1-0.dll
  • api-ms-win-core-localization-l1-2-0.dll
  • OLEAUT32.dll
  • api-ms-win-core-winrt-error-l1-1-0.dll
  • api-ms-win-core-winrt-error-l1-1-1.dll
  • api-ms-win-core-winrt-l1-1-0.dll
  • api-ms-win-core-winrt-string-l1-1-0.dll
  • api-ms-win-core-synch-l1-1-0.dll
  • api-ms-win-core-threadpool-l1-2-0.dll
  • api-ms-win-core-com-l1-1-0.dll
  • api-ms-win-core-com-l1-1-1.dll
  • api-ms-win-core-synch-l1-2-0.dll

Attributo noexcept di Windows Runtime

Windows Runtime ha un nuovo attributo [noexcept] che puoi aggiungere ai metodi e alle proprietà in MIDL 3.0. La presenza dell'attributo indica agli strumenti di supporto che l'implementazione non genera un'eccezione (né restituisce un errore HRESULT). Ciò consente proiezioni del linguaggio per ottimizzare la generazione di codice, evitando così il sovraccarico per la gestione delle eccezioni necessario per supportare eventuali errori delle chiamate all'interfaccia binaria dell'applicazione (ABI).

C++/WinRT sfrutta questo vantaggio generando implementazioni noexcept C++ di codice per l'utilizzo e la creazione di dati. Se hai metodi o proprietà di API che non generano errori e la dimensione del codice è per te motivo di preoccupazione, puoi prendere in considerazione questo attributo.

Generazione del codice ottimizzata

C++/WinRT genera ora (dietro le quinte) codice sorgente C++ ancora più efficiente, consentendo così al compilatore C++ di generare codice binario il più compatto ed efficiente possibile. Molti dei miglioramenti sono stati pensati per ridurre il costo legato alla gestione delle eccezioni, evitando inutili informazioni di correzione. Nei file binari che usano grandi quantità di codice C++/WinRT si noterà una riduzione delle dimensioni del codice di circa il 4%. Il codice risulta anche più efficiente (e viene eseguito più rapidamente) grazie al numero minore di istruzioni.

Questi miglioramenti si basano su una nuova funzionalità di interoperabilità disponibile per gli sviluppatori. Tutti i tipi C++/WinRT che sono proprietari di risorse includono ora un costruttore per acquisire direttamente la proprietà, evitando l'approccio precedente in due fasi.

ABI::Windows::Foundation::IStringable* raw = ...

IStringable projected(raw, take_ownership_from_abi);

printf("%ls\n", projected.ToString().c_str());

Generazione del codice con gestione delle eccezioni ottimizzata

Questa modifica si integra con il lavoro svolto dal team Microsoft dedicato all'ottimizzazione del codice C++ per ridurre il costo legato alla gestione delle eccezioni. Se nel codice usi una notevole quantità di interfacce binarie di applicazione (ABI), ad esempio COM, puoi osservare che una grande quantità di codice segue questo modello.

int32_t Function() noexcept
{
    try
    {
        // code here constitutes unique value.
    }
    catch (...)
    {
        // code here is always duplicated.
    }
}

Lo stesso C++/WinRT genera questo modello per ogni API implementata. Con migliaia di funzioni API, qualsiasi ottimizzazione può avere un peso rilevante. In passato, l'ottimizzatore non rilevava che i blocchi catch sono tutti identici e quindi duplicava una grande quantità di codice attorno a ogni interfaccia ABI, contribuendo così alla convinzione che l'uso di eccezioni nel codice di sistema ha l'effetto di generare file binari di grandi dimensioni. A partire da Visual Studio 2019, tuttavia, il compilatore C++ comprime tutti i funclet catch e archivia solo quelli univoci. Questo comportamento consente di ottenere un'ulteriore riduzione complessiva del 18% nella dimensione del codice per i file binari che si basano in maniera significativa su questo modello. Non solo il codice di gestione delle eccezioni è ora più efficiente rispetto all'uso di codici restituiti, ma anche il rischio di ottenere file binari più grandi è ormai un ricordo del passato.

Miglioramenti incrementali delle build

Lo strumento cppwinrt.exe confronta ora l'output di un file di codice sorgente o di intestazione generato con il contenuto dei file presenti sul disco e scrive il file solo se è stato effettivamente modificato. Ciò consente di risparmiare molto tempo nelle operazioni di I/O su disco e assicura che i file non vengano considerati "dirty" dal compilatore C++. In questo modo, la ricompilazione viene evitata, o almeno ridotta, in molti casi.

Generazione completa delle interfacce generiche

Grazie al lettore di metadati xlang, C++/WinRT genera ora dai metadati tutte le interfacce con parametri o generiche. Le interfacce come Windows::Foundation::Collections::IVector<T> vengono ora generate dai metadati anziché essere scritte manualmente in winrt/base.h. Di conseguenza, la dimensione di winrt/base.h viene dimezzata e le ottimizzazioni vengono generate direttamente nel codice (un'operazione piuttosto difficile con l'approccio manuale).

Importante

Le interfacce come quelle riportate nell'esempio vengono ora inserite nelle rispettive intestazioni di spazio dei nomi, anziché in winrt/base.h. Pertanto, per usare l'interfaccia, dovrai includere l'intestazione di spazio dei nomi appropriata, se non lo hai già fatto.

Ottimizzazioni dei componenti

Questo aggiornamento introduce il supporto per diverse ottimizzazioni aggiuntive per C++/WinRT che richiedono il consenso esplicito, illustrate nelle sezioni seguenti. Poiché queste ottimizzazioni costituiscono modifiche importanti, per il cui supporto possono essere necessarie alcune piccole modifiche, dovrai attivarle in modo esplicito. In Visual Studio imposta la proprietà del progetto Proprietà comuni>C++/WinRT>Ottimizzato su . Questa operazione ha come risultato l'aggiunta di <CppWinRTOptimized>true</CppWinRTOptimized> al file del progetto e ha lo stesso effetto dell'impostazione dell'opzione -opt[imize] quando viene richiamato cppwinrt.exe dalla riga di comando.

Nei nuovi progetti (creati a partire da un modello di progetto), -opt viene usato per impostazione predefinita.

Costruzione uniforme e accesso diretto all'implementazione

Queste due ottimizzazioni consentono a un componente di accedere direttamente ai rispettivi tipi di implementazione, anche quando usa solo tipi proiettati. Non devi usare make, make_self o get_self se vuoi semplicemente usare la superficie di API pubblica. Le chiamate verranno compilate fino alle chiamate dirette nell'implementazione e anche queste potrebbero essere interamente impostate come inline.

Per altre informazioni ed esempi di codice, vedi Acconsentire esplicitamente alla costruzione uniforme e all'accesso diretto all'implementazione.

Factory con cancellazione di tipi

Questa ottimizzazione consente di evitare le dipendenze #include in module.g.cpp in modo che non sia necessario ripetere la compilazione ogni volta che viene modificata una singola classe di implementazione. Questo ha come risultato un miglioramento delle prestazioni di compilazione.

module.g.cpp più intelligente ed efficiente per progetti di grandi dimensioni con più librerie

Il file module.g.cpp contiene ora anche due helper componibili aggiuntivi, denominati winrt_can_unload_now e winrt_get_activation_factory. Questi helper sono stati ideati per progetti di grandi dimensioni, in cui una DLL è composta da un certo numero di librerie, ciascuna con specifiche classi di runtime. In una situazione di questo tipo, è necessario riunire manualmente le funzioni DllGetActivationFactory e DllCanUnloadNow della DLL. Questi helper semplificano notevolmente questa operazione, evitando errori di origine non corretta. Il flag cppwinrt.exe dello strumento -lib può essere usato anche per assegnare a ogni singola libreria uno specifico preambolo (anziché winrt_xxx) in modo che le funzioni di ogni libreria vengano denominate singolarmente e quindi combinate in modo non ambiguo.

Supporto per coroutine

Il supporto per coroutine è incluso automaticamente. In precedenza, il supporto si trovava in più posizioni, e questo era considerato come troppo limitante. Di conseguenza, temporaneamente per la versione 2.0, era richiesto un file di intestazione winrt/coroutine.h che ora non è più necessario. Poiché le interfacce asincrone di Windows Runtime vengono generate in modo automatico, anziché essere scritte manualmente, si trovano ora winrt/Windows.Foundation.h. Ciò significa che gli helper di coroutine come resume_foreground, oltre a essere più gestibili e supportabili, non devono più essere aggiunti alla fine di una specifica intestazione di spazio dei nomi. Possono invece includere più naturalmente le rispettive dipendenze. In questo modo, resume_foreground può supportare il ripristino non solo in base a un determinato oggetto Windows::UI::Core::CoreDispatcher, ma anche in base a un determinato oggetto Windows::System::DispatcherQueue. In precedenza, uno solo dei due poteva essere supportato, poiché la definizione poteva risiedere in un solo spazio dei nomi.

Ecco un esempio del supporto per DispatcherQueue.

...
#include <winrt/Windows.System.h>
using namespace Windows::System;
...
fire_and_forget Async(DispatcherQueueController controller)
{
    bool queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(queued);

    // This is just to simulate queue failure...
    co_await controller.ShutdownQueueAsync();

    queued = co_await resume_foreground(controller.DispatcherQueue());
    assert(!queued);
}

Gli helper di coroutine sono stati ora aggiornati con [[nodiscard]], migliorandone la facilità d'uso. Se dimentichi (o non ti rendi conto) di dover applicare co_await sugli helper per consentirne il funzionamento, grazie a [[nodiscard]] viene ora generato un avviso del compilatore per segnalare tale errore.

Diagnosi facilitata delle allocazioni stack dirette

Poiché i nomi delle classi di implementazione e proiettate coincidono (per impostazione predefinita) e si differenziano solo per lo spazio dei nomi, è possibile confonderle e creare accidentalmente un'implementazione dello stack, invece di usare la famiglia di helper make. La diagnosi di casi come questo può non essere facile, poiché l'oggetto potrebbe essere eliminato mentre sono ancora presenti riferimenti in sospeso. Questa diagnosi viene ora eseguita tramite un'asserzione, per le compilazioni di debug. Anche se l'asserzione non rileva l'allocazione dello stack all'interno di una coroutine, è comunque utile per intercettare la maggior parte degli errori di questo tipo.

Per altre informazioni, vedi Diagnosi delle allocazioni dirette.

Helper di acquisizione e delegati variadic migliorati

Questo aggiornamento corregge la limitazione relativa agli helper di acquisizione supportando anche i tipi proiettati. Questo problema si verifica di tanto in tanto con le API di interoperabilità di Windows Runtime, quando restituiscono un tipo proiettato.

Questo aggiornamento aggiunge anche il supporto per get_strong e get_weak durante la creazione di un delegato variadic (non di Windows Runtime).

Supporto per la distruzione posticipata e uso sicuro di QI durante la distruzione

Nel distruttore di un oggetto di una classe di runtime non è insolito chiamare un metodo che avvia temporaneamente il conteggio dei riferimenti. Quando il conteggio dei riferimenti restituisce zero, l'oggetto viene distrutto una seconda volta. In un'applicazione XAML può essere necessario eseguire un metodo QueryInterface (QI) in un distruttore per chiamare un'implementazione per la pulizia verso l'alto o il basso nella gerarchia. Tuttavia, il conteggio dei riferimenti dell'oggetto ha già raggiunto lo zero e quindi QI determina un rimbalzo del conteggio dei riferimenti.

Questo aggiornamento permette di evitare che il numero dei riferimenti aumenti di nuovo dopo aver raggiunto lo zero, consentendo comunque a QI di usare eventuali riferimenti temporanei necessari durante la distruzione. Questa routine è inevitabile in determinati controlli e applicazioni XAML e C++/WinRT consente ora di gestirla correttamente.

Puoi posticipare la distruzione fornendo una funzione final_release statica per il tipo di implementazione. L'ultimo puntatore rimanente per l'oggetto, sotto forma di std::unique_ptr, viene passato alla funzione final_release. Puoi quindi scegliere di spostare la proprietà di tale puntatore in un altro contesto. Puoi chiamare senza alcun rischio un metodo QI sul puntatore senza attivare una doppia distruzione. Ma nel punto in cui l'oggetto viene distrutto la differenza del conteggio dei riferimenti deve essere zero.

Il valore restituito di final_release può essere void, un oggetto di operazione asincrona come IAsyncAction o winrt::fire_and_forget.

struct Sample : implements<Sample, IStringable>
{
    hstring ToString()
    {
        return L"Sample";
    }

    ~Sample()
    {
        // Called when the unique_ptr below is reset.
    }

    static void final_release(std::unique_ptr<Sample> self) noexcept
    {
        // Move 'self' as needed to delay destruction.
    }
};

Nell'esempio seguente, dopo il rilascio finale di MainPage, viene eseguita una chiamata a final_release. Questa funzione rimane cinque secondi in attesa (nel pool di thread) e quindi riprende l'esecuzione usando l'oggetto Dispatcher della pagina (per il cui funzionamento è necessario QI/AddRef/Release). Pulisce quindi una risorsa su tale thread dell'interfaccia utente. Infine esegue la cancellazione di unique_ptr, determinando in tal modo la chiamata al distruttore MainPage. Anche in questo distruttore viene chiamato DataContext e questo richiede l'esecuzione di QI per IFrameworkElement.

Non è indispensabile implementare final_release come una coroutine, ma questa soluzione può essere utile e consente di spostare la distruzione in un altro thread, come avviene in questo esempio.

struct MainPage : PageT<MainPage>
{
    MainPage()
    {
    }

    ~MainPage()
    {
        DataContext(nullptr);
    }

    static IAsyncAction final_release(std::unique_ptr<MainPage> self)
    {
        co_await 5s;

        co_await resume_foreground(self->Dispatcher());
        co_await self->resource.CloseAsync();

        // The object is destructed normally at the end of final_release,
        // when the std::unique_ptr<MyClass> destructs. If you want to destruct
        // the object earlier than that, then you can set *self* to `nullptr`.
        self = nullptr;
    }
};

Per altre informazioni, vedi Distruzione posticipata.

Supporto migliorato per l'ereditarietà delle interfacce singole di tipo COM

Come per la programmazione di Windows Runtime, C++/WinRT viene usato anche per creare e utilizzare API solo COM. Questo aggiornamento rende possibile l'implementazione di un server COM in cui è presente una gerarchia di interfacce. Questo non è necessario per Windows Runtime, ma lo è per alcune implementazioni di COM.

Gestione corretta dei parametri out

La gestione dei parametri out può talvolta presentare difficoltà, soprattutto per le matrici di Windows Runtime. Con questo aggiornamento, C++/WinRT è molto più affidabile e resiliente agli errori nella gestione di matrici e parametri out, indipendentemente dal fatto che tali parametri risultino da una proiezione del linguaggio o da uno sviluppatore di COM che sta usando l'interfaccia ABI non elaborata e ha commesso l'errore di non inizializzare le variabili in modo coerente. In entrambi i casi, C++/WinRT gestisce in modo corretto questa situazione, passando i tipi proiettati all'interfaccia ABI (ricordando di rilasciare le risorse) e azzerando o cancellando i parametri che arrivano attraverso l'interfaccia ABI.

Gestione affidabile dei token non validi da parte degli eventi

L'implementazione di winrt::event gestisce ora correttamente il caso in cui il metodo remove viene chiamato con un valore di token non valido, ovvero un valore non presente nella matrice.

Distruzione delle variabili locali della coroutine prima della restituzione del risultato

Il metodo tradizionale di implementazione di un tipo di coroutine può consentire la distruzione delle variabili locali all'interno della coroutine dopo la restituzione del risultato o il completamento della coroutine, anziché prima della sospensione finale. La ripresa di qualsiasi oggetto waiter viene ora posticipata fino alla sospensione finale, per evitare questo problema e offrire anche altri vantaggi.

Novità e modifiche in Windows SDK versione 10.0.17763.0 (Windows 10, versione 1809)

La tabella seguente contiene novità e modifiche per C++/WinRT in Windows SDK versione 10.0.17763.0 (Windows 10, versione 1809).

Funzionalità nuova o modificata Altre informazioni
Modifica importante. Per la compilazione, C++/WinRT non dipende da intestazioni di Windows SDK. Vedi più avanti Isolamento dai file di intestazione di Windows SDK.
Il formato del sistema dei progetti di Visual Studio è stato modificato. Vedi più avanti Come impostare una versione più recente di Windows SDK come destinazione per il progetto C++/WinRT.
Sono disponibili nuove funzioni e classi di base che consentono di passare un oggetto raccolta a una funzione di Windows Runtime o implementare proprietà e i tipi di raccolta personalizzati. Vedi Gruppi di prodotti con C++/WinRT.
Con le classi di runtime C++/WinRT può essere usata l'estensione di markup {Binding}. Per altre informazioni ed esempi di codice, vedi Panoramica del data binding.
Il supporto per l'annullamento di una coroutine consente di registrare un callback di annullamento. Per altre informazioni ed esempi di codice, vedere Annullamento di un'operazione asincrona e callback di annullamento.
Quando crei un delegato che punta a una funzione membro, puoi stabilire un riferimento sicuro o debole all'oggetto corrente (anziché usare un puntatore this non elaborato) nel punto in cui il gestore è registrato. Per altre informazioni ed esempi di codice, vedi la sottosezione Se una funzione membro viene usata come delegato nella sezione Accesso sicuro al puntatore this con un delegato di gestione degli eventi.
Sono stati corretti bug rivelati dalla maggiore conformità di Visual Studio allo standard C++. La toolchain LLVM and Clang viene inoltre sfruttata in modo più efficace per convalidare la conformità agli standard di C++/WinRT. Non si verificherà più il problema descritto in Per quale motivo il mio nuovo progetto non viene compilato? Sto usando Visual Studio 2017 (versione 15.8.0 o successiva), e SDK versione 17134

Altre modifiche

  • Modifica importante. winrt::get_abi(winrt::hstring const&) ora restituisce void* invece di HSTRING. Puoi usare static_cast<HSTRING>(get_abi(my_hstring)); per ottenere un HSTRING. Vedi Interoperabilità con HSTRING di ABI.
  • Modifica importante. winrt::put_abi(winrt::hstring&) ora restituisce void** invece di HSTRING*. Puoi usare reinterpret_cast<HSTRING*>(put_abi(my_hstring)); per ottenere un HSTRING*. Vedi Interoperabilità con HSTRING di ABI.
  • Modifica importante. HRESULT viene ora proiettato come winrt::hresult. Se ti serve un HRESULT (per eseguire la verifica di tipi o supportare tratti di tipo), puoi eseguire static_cast su un winrt::hresult. In alternativa, winrt::hresult viene convertito in HRESULT, purché venga incluso unknwn.h prima di qualsiasi intestazione C++/WinRT.
  • Modifica importante. GUID viene ora proiettato come winrt::guid. Per le API di cui esegui l'implementazione, devi usare winrt::guid per i parametri GUID. In alternativa, winrt::guid viene convertito in GUID, purché venga incluso unknwn.h prima di qualsiasi intestazione C++/WinRT. Vedi Interoperabilità con lo struct GUID di ABI.
  • Modifica importante. Il costruttore winrt::handle_type è stato protetto rendendolo esplicito. È ora più difficile scrivere codice non corretto con questo costruttore. Se devi assegnare un valore di handle non elaborato, chiama in alternativa la funzione handle_type::attach.
  • Modifica importante. Le firme di WINRT_CanUnloadNow e WINRT_GetActivationFactory sono cambiate. Queste funzioni non devono più essere dichiarate. In alternativa, includi winrt/base.h (che viene inserito automaticamente se includi file di intestazione di spazi dei nomi Windows C++/WinRT) per aggiungere le dichiarazioni di queste funzioni.
  • Per winrt::clock struct, from_FILETIME/to_FILETIME sono deprecati a favore di from_file_time/to_file_time.
  • API semplificate che prevedono parametri IBuffer. Quasi tutte le API preferiscono raccolte o matrici. Tuttavia, abbiamo sentito la necessità di semplificare la chiamata delle API basate su IBuffer. Questo aggiornamento consente di accedere direttamente ai dati sottostanti un'implementazione IBuffer. Usa la stessa convenzione di denominazione dei dati usata nei contenitori della libreria standard C++. Tale convenzione evita anche conflitti con i nomi di metadati che iniziano convenzionalmente con una lettera maiuscola.
  • Generazione del codice migliorata. Sono stati introdotti vari miglioramenti per ridurre la dimensione del codice, migliorare l'inlining e ottimizzare la memorizzazione di factory nella cache.
  • Rimozione della ricorsione non necessaria. Quando la riga di comando fa riferimento a una cartella, anziché a uno specifico file .winmd, lo strumento cppwinrt.exe non esegue più la ricerca di file .winmd in modo ricorsivo. Anche lo strumento cppwinrt.exe gestisce ora i duplicati in modo più intelligente ed è più resiliente agli errori degli utenti e agli errori di formato dei file .winmd.
  • Puntatori intelligenti con protezione. In precedenza, i revocatori di evento non riuscivano a eseguire la revoca in caso di assegnazione di un nuovo valore in seguito allo spostamento. Ciò ha consentito di individuare un problema, nel modello di struct winrt::com_ptr, a causa del quale le classi di puntatori intelligenti non gestivano in modo affidabile l'autoassegnazione. winrt::com_ptr è stato corretto e i revocatori di evento predefiniti sono stati modificati in modo da gestire correttamente la semantica di spostamento ed eseguire la revoca al momento dell'assegnazione.

Importante

Sono state apportate importanti modifiche all'estensione di Visual Studio C++/WinRT (VSIX), sia nella versione 1.0.181002.2 sia nella versione successiva 1.0.190128.4. Per informazioni dettagliate su queste modifiche e su come influiscono sui progetti esistenti, vedi Supporto di Visual Studio per C++/WinRT e Versioni precedenti dell'estensione VSIX.

Isolamento dai file di intestazione di Windows SDK

Questa è potenzialmente una modifica rilevante per il tuo codice.

Per la compilazione, C++/WinRT non dipende più da file di intestazione di Windows SDK. I file di intestazione della libreria di runtime C (CRT) e della libreria di modelli standard C++ (STL) non includono intestazioni di Windows SDK. Ciò consente di migliorare la conformità agli standard, evitare dipendenze accidentali e ridurre notevolmente il numero di macro da cui proteggersi.

Questa indipendenza significa che C++/WinRT è ora più flessibile e conforme agli standard e ha maggiori possibilità di diventare un compilatore e una libreria multipiattaforma. Significa inoltre che le intestazioni C++/WinRT non sono soggette a eventuali effettivi negativi delle macro.

Se in precedenza le intestazioni di Windows venivano incluse nel progetto direttamente da C++/WinRT, ora è compito tuo includerle. In ogni caso, è sempre consigliabile includere in modo esplicito le intestazioni da cui si dipende e non lasciare che sia un'altra libreria a includerle.

Attualmente le uniche eccezioni all'isolamento dei file di intestazione di SDK Windows sono rappresentate da valori intrinseci e numerici. Non vi sono problemi noti relativi a queste ultime dipendenze.

Nel tuo progetto puoi riabilitare l'interoperabilità con le intestazioni di Windows SDK, se necessario. Se, ad esempio, vuoi implementare un'interfaccia COM (in IUnknown), includi unknwn.h prima di qualsiasi intestazione C++/WinRT. In questo modo, la libreria di base di C++/WinRT abilita vari hook per il supporto di interfacce COM classiche. Per un esempio di codice, vedi Creare componenti COM con C++/WinRT. In modo analogo, includi esplicitamente eventuali altre intestazioni di Windows SDK che dichiarano tipi e/o funzioni che vuoi chiamare.

Come impostare una versione più recente di Windows SDK come destinazione per il progetto C++/WinRT

Il metodo per modificare la destinazione di un progetto che ha minori probabilità di causare problemi del compilatore e del linker è anche quello più impegnativo. Questo metodo comporta la creazione di un nuovo progetto (con la versione di Windows SDK selezionata come destinazione) e quindi la copia dei file dal progetto precedente a quello nuovo. Vi saranno sezioni dei tuoi file .vcxproj e .vcxproj.filters precedenti che puoi semplicemente sovrascrivere per evitare di aggiungere file in Visual Studio.

Vi sono tuttavia altri due modi per reimpostare la destinazione di un progetto in Visual Studio.

  • Passa alla proprietà del progetto Generale>Versione di Windows SDK e seleziona Tutte le configurazioni e Tutte le piattaforme. Imposta Versione di Windows SDK sulla versione che vuoi usare di destinazione.
  • In Esplora soluzioni fai doppio clic sul nodo del progetto, fare clic su Ridestina progetti, scegli una o più versioni da impostare come destinazione e quindi fai clic su OK.

Se vengono restituiti errori del compilatore o del linker dopo l'uso di uno di questi due metodi, puoi provare a pulire la soluzione (scegli Compila>Pulisci soluzione e/o elimina manualmente tutti i file e le cartelle temporanei) prima di provare a ripetere la compilazione.

Se il compilatore C++ genera l’errore "C2039: 'IUnknown': is not a member of 'global namespace''" ('IUnknown': non è un membro di "spazio dei nomi globale"), aggiungi #include <unknwn.h> all'inizio del file pch.h, prima di includere eventuali intestazioni C++/WinRT.

Può anche essere necessario aggiungere #include <hstring.h> dopo tale stringa.

Se il linker C++ genera l'errore "error LNK2019: unresolved external symbol _WINRT_CanUnloadNow@0 referenced in function _VSDesignerCanUnloadNow@0", puoi risolverlo aggiungendo #define _VSDESIGNER_DONT_LOAD_AS_DLL al file pch.h.