Introduzione a C++/WinRT
Importante
Per informazioni sulla configurazione di Visual Studio per lo sviluppo in C++/WinRT, compresi l'installazione e l'uso dell'estensione C++/WinRT per Visual Studio (VSIX) e del pacchetto NuGet, che insieme forniscono il modello di progetto e il supporto della compilazione, vedi Supporto di Visual Studio per C++/WinRT.
Per iniziare velocemente a usare C++/WinRT, questo argomento presenta un esempio di codice semplice basato su un nuovo progetto Applicazione console di Windows (C++/WinRT). Questo argomento illustra anche come aggiungere il supporto di C++/WinRT a un progetto di applicazione desktop di Windows.
Nota
Anche se è consigliabile usare le versioni più recenti di Visual Studio e Windows SDK per lo sviluppo, se usi Visual Studio 2017 (versione 15.8.0 o successive) con Windows SDK versione 10.0.17134.0 (Windows 10 versione 1803) come destinazione, è possibile che la compilazione di un nuovo progetto C++/WinRT non riesca con l'errore "errore C3861: 'from_abi': identificatore non trovato" e con altri errori con origine in base.h. La soluzione è selezionare una versione successiva (più conforme) di Windows SDK come destinazione oppure impostare la proprietà del progetto C/C++>Linguaggio>Modalità di conformità: No (elimina anche /permissive- se compare nella proprietà del progetto C/C++>Linguaggio>Riga di comando in Opzioni aggiuntive).
Guida introduttiva a C++/WinRT
Crea un nuovo progetto Applicazione console di Windows (C++/WinRT).
Modifica pch.h
e main.cpp
in modo che abbia questo aspetto.
// pch.h
#pragma once
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
// main.cpp
#include "pch.h"
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
int main()
{
winrt::init_apartment();
Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
SyndicationClient syndicationClient;
syndicationClient.SetRequestHeader(L"User-Agent", L"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0)");
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
for (const SyndicationItem syndicationItem : syndicationFeed.Items())
{
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
// A workaround to remove the trademark symbol from the title string, because it causes issues in this case.
std::wstring titleAsStdWstring{ titleAsHstring.c_str() };
titleAsStdWstring.erase(remove(titleAsStdWstring.begin(), titleAsStdWstring.end(), L'™'), titleAsStdWstring.end());
titleAsHstring = titleAsStdWstring;
std::wcout << titleAsHstring.c_str() << std::endl;
}
}
Vediamo in dettaglio il breve esempio di codice precedente e cosa succede in ogni parte.
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Web.Syndication.h>
Con le impostazioni di progetto predefinite, le intestazioni incluse provengono da Windows SDK , all'interno della cartella %WindowsSdkDir%Include<WindowsTargetPlatformVersion>\cppwinrt\winrt
. Visual Studio include il percorso nella relativa macro IncludePath. Non è però presente una dipendenza rigida da Windows SDK, perché il progetto (tramite lo strumento cppwinrt.exe
) genera le stesse intestazioni all'interno della cartella $(GeneratedFilesDir) del progetto. Le intestazioni verranno caricate da tale cartella se non è possibile trovarle altrove o se modifichi le impostazioni del progetto.
Le intestazioni contengono le API di Windows proiettate in C++/WinRT. In altre parole, per ogni tipo di Windows, C++/WinRT definisce un equivalente C++ adatto (chiamato tipo proiettato). Un tipo proiettato ha lo stesso nome completo del tipo Windows, ma viene posizionato nello spazio dei nomi winrt C++. L'inserimento di questi elementi nella tua intestazione precompilata riduce i tempi di compilazione incrementale.
Importante
Ogni volta che si vuole usare un tipo da uno spazio dei nomi di Windows, è necessario #include
il file di intestazione dello spazio dei nomi di Windows C++/WinRT corrispondente, come indicato in precedenza. L'intestazione corrispondente è quella con lo stesso nome dello spazio dei nomi del tipo. Ad esempio, per usare la proiezione C++/WinRT per la classe di runtime Windows::Foundation::Collections::PropertySet, includi l'intestazione winrt/Windows.Foundation.Collections.h
.
È comune che un'intestazione di proiezione C++/WinRT includa automaticamente i file di intestazione dello spazio dei nomi correlati. Ad esempio, winrt/Windows.Foundation.Collections.h
include winrt/Windows.Foundation.h
. Tuttavia, è consigliabile non fare affidamento su questo comportamento, poiché si tratta di un dettaglio di implementazione che cambia nel tempo. È necessario includere in modo esplicito tutte le intestazioni necessarie.
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Web::Syndication;
Le direttive using namespace
sono facoltative, ma utili. Il modello illustrato sopra per tali direttive (che consente la ricerca di nomi non qualificati per qualsiasi elemento all'interno dello spazio dei nomi winrt) è adatto per quando si sta iniziando un nuovo progetto e C++/WinRT è l'unica proiezione di linguaggio in uso all'interno di progetto. Se, invece, stai creando un mix di codice C++/WinRT con C++/CX e/o codice ABI (Application Binary Interface) dell'SDK (stai effettuando la conversione da o stai interoperando con uno o entrambi questi modelli), vedi gli argomenti Interoperabilità tra C++/WinRT e C++/CX, Passaggio a C++/WinRT da C++/CX e Interoperabilità tra C++/WinRT e l'ABI.
winrt::init_apartment();
La chiamata a winrt::init_apartment inizializza il thread in Windows Runtime in un apartment a thread multipli per impostazione predefinita. La chiamata inizializza anche COM.
Uri rssFeedUri{ L"https://blogs.windows.com/feed" };
SyndicationClient syndicationClient;
Esegui l'allocazione in stack di due oggetti: rappresentano l'URI del blog di Windows e un client di diffusione. È necessario creare l'URI con un semplice valore letterale di stringa estesa (vedi Gestione delle stringhe in C++/WinRT per altri modi di utilizzo delle stringhe).
SyndicationFeed syndicationFeed = syndicationClient.RetrieveFeedAsync(rssFeedUri).get();
SyndicationClient::RetrieveFeedAsync è un esempio di una funzione Windows Runtime asincrona. L'esempio di codice riceve un oggetto operazione asincrona da RetrieveFeedAsync e chiama get su tale oggetto per bloccare il thread di chiamata e attendere il risultato (un feed di diffusione, in questo caso). Per altre informazioni sulla concorrenza e per le tecniche non bloccanti, vedi Concorrenza e operazioni asincrone con C++/WinRT.
for (const SyndicationItem syndicationItem : syndicationFeed.Items()) { ... }
SyndicationFeed.Items è un intervallo, definito dagli iteratori restituiti dalle funzioni begin e end (o le relative varianti costante, inversa e costante-inversa). Per questo motivo, puoi enumerare Items con un'istruzione for
basata sull'intervallo o con la funzione modello std:: for_each. Ogni volta che esegui un'iterazione di una raccolta di Windows Runtime in questo modo, dovrai usare #include <winrt/Windows.Foundation.Collections.h>
.
winrt::hstring titleAsHstring = syndicationItem.Title().Text();
// Omitted: there's a little bit of extra work here to remove the trademark symbol from the title text.
std::wcout << titleAsHstring.c_str() << std::endl;
Ottiene il testo del titolo del feed, come oggetto winrt::hstring (altri dettagli sono disponibili in Gestione delle stringhe in C++/WinRT). Viene quindi effettuato l'output dell'oggetto hstring, tramite la funzione c_str che riflette il motivo usato con le stringhe della libreria C++ standard.
Come puoi vedere, C++/WinRT incoraggia espressioni C++ moderne e di tipo classe, come syndicationItem.Title().Text()
. Si tratta di uno stile di programmazione più fluido e diverso rispetto alla programmazione COM tradizionale. Non devi inizializzare direttamente COM, né usare i puntatori COM.
Non è neanche necessario gestire codici di restituzione HRESULT. C++/WinRT converte gli HRESULT di errore in eccezioni quali winrt::hresult-error per uno stile di programmazione naturale e moderno. Per altre informazioni sulla gestione degli errori e gli esempi di codice, vedi Gestione degli errori con C++/WinRT.
Modificare un progetto di applicazione desktop di Windows per aggiungere il supporto di C++/WinRT
Alcuni progetti desktop (ad esempio, i modelli WinUI 3 in Visual Studio) hanno il supporto C++/WinRT integrato.
Tuttavia questa sezione illustra come è possibile aggiungere il supporto di C++/WinRT a qualsiasi progetto di applicazione desktop di Windows esistente. Se non è disponibile un progetto di applicazione desktop di Windows, puoi seguire questi passaggi creandone prima di tutto uno. Ad esempio, apri Visual Studio e crea un progetto Visual C++ >Desktop di Windows>Applicazione desktop di Windows.
Puoi installare facoltativamente l'Estensione di Visual Studio C++/WinRT (VSIX) e il pacchetto NuGet. Per informazioni dettagliate, vedi Supporto di Visual Studio per C++/WinRT.
Impostare le proprietà del progetto
Passa alla proprietà del progetto Generale>Versione di Windows SDK e seleziona Tutte le configurazioni e Tutte le piattaforme. Assicurati che l'opzione Versione di Windows SDK sia impostata su 10.0.17134.0 (Windows 10, versione 1803) o versione successiva.
Verifica che non esistano le condizioni descritte in Per quale motivo il mio nuovo progetto non viene compilato?.
Dato che C++/WinRT usa funzionalità dallo standard C++17, imposta la proprietà del progetto C/C++>Linguaggio>Standard del linguaggio C++ su Standard C++17 ISO (/std:c++17).
Intestazione precompilata
Il modello di progetto predefinito crea un'intestazione precompilata, denominata framework.h
o stdafx.h
. Rinominala pch.h
. Se hai un file stdafx.cpp
rinominalo pch.cpp
. Imposta la proprietà del progetto C/C++>Intestazioni precompilate>Intestazione precompilata su Crea (/Yc) e File di intestazione precompilato su pch.h.
Trova e sostituisci tutte le occorrenze di #include "framework.h"
(o #include "stdafx.h"
) con #include "pch.h"
.
In pch.h
includi winrt/base.h
.
// pch.h
...
#include <winrt/base.h>
Collegamento
La proiezione del linguaggio C++/WinRT dipende da determinate funzioni libere (non membro) di Windows Runtime e da punti di ingresso, che richiedono il collegamento della libreria generica WindowsApp.lib. In questa sezione vengono descritti tre modi per soddisfare il linker.
La prima opzione consiste nell'aggiungere al progetto di Visual Studio tutte le proprietà e le destinazioni MSBuild C++/WinRT. A tale scopo, installa il pacchetto NuGet Microsoft.Windows.CppWinRT nel progetto. Aprire il progetto in Visual Studio, fare clic su Progetto>Gestisci pacchetti NuGet...>Sfoglia, digitare o incollare Microsoft.Windows.CppWinRT nella casella di ricerca, selezionare l'elemento nei risultati della ricerca, quindi fare clic su Installa per installare il pacchetto per tale progetto.
Puoi anche usare le impostazioni dei collegamenti di progetto per il collegamento esplicito di WindowsApp.lib
. In alternativa, puoi farlo nel codice sorgente (in pch.h
, ad esempio) come indicato di seguito.
#pragma comment(lib, "windowsapp")
Puoi ora eseguire la compilazione e il collegamento, quindi aggiungere codice C++/WinRT al progetto (ad esempio codice simile a quello nella sezione precedente Guida introduttiva a C++/WinRT).
Tre scenari principali per C++/WinRT
Man mano che usi C++/WinRT acquisendo familiarità con questa proiezione di linguaggio e che esamini il resto di questa documentazione, probabilmente noterai che si verificano tre scenari principali, come illustrato nelle sezioni seguenti.
Utilizzo di API e tipi di Windows
In questo caso, si fa riferimento all'uso o alla chiamata di API, ad esempio l'esecuzione di chiamate API per la comunicazione tramite Bluetooth, per lo streaming e la presentazione di video, per l'integrazione con la shell di Windows e così via. C++/WinRT supporta completamente questa categoria di scenario. Per altre info, vedi Usare API con C++/WinRT.
Creazione di API e tipi di Windows
In questo caso, per creazione si intende la produzione di API e di tipi, ad esempio la produzione di API come quelle illustrate nella sezione precedente oppure di API grafiche, API di archiviazione e del file system, API per le funzionalità di rete e così via. Per altre info, vedi Creare API con C++/WinRT.
La creazione di API con C++/WinRT è un'attività leggermente più complessa rispetto al semplice utilizzo perché devi usare IDL per definire la forma dell'API prima di poterla implementare. Per comprendere come procedere, vedi la procedura dettagliata in Controlli XAML, binding a una proprietà C++/WinRT.
Applicazioni XAML
Questo scenario riguarda la creazione di applicazioni e controlli nel framework interfaccia utente XAML. L'attività di sviluppo di un'applicazione XAML è il risultato di una combinazione di utilizzo e creazione. Tuttavia, dal momento che XAML attualmente è il framework interfaccia utente predominante in Windows e che la relativa influenza su Windows Runtime è proporzionale a tale predominanza, è opportuno parlare di una categoria di scenario a parte.
Tieni presente che XAML funziona in modo ottimale con linguaggi di programmazione che offrono la reflection. In C++/WinRT devi a volte eseguire alcune operazioni aggiuntive per interagire con il framework XAML. Tutti questi casi vengono trattati nella documentazione. Per iniziare, vedi Controlli XAML, binding a una proprietà C++/WinRT e Controlli (basati su modelli) personalizzati XAML con C++/WinRT.
App di esempio scritte in C++ /WinRT
Vedere Dove si possono trovare app di esempio C++/WinRT?.
API importanti
- Metodo SyndicationClient::RetrieveFeedAsync
- Proprietà SyndicationFeed.Items
- Struct winrt::hstring
- Struct winrt::hresult-error