Tipi di dati C++ standard e C++/WinRT
Con C++/WinRT puoi chiamare API di Windows Runtime con tipi di dati C++ standard, inclusi alcuni tipi di dati della libreria standard C++. Puoi passare stringhe standard alle API (vedi Gestione delle stringhe in C++/WinRT) e puoi passare elenchi di inizializzatori e contenitori standard alle API che si aspettano una raccolta semanticamente equivalente.
Vedi anche Passaggio di parametri nel limite ABI.
Elenchi di inizializzatori standard
Un elenco di inizializzatori (std::initializer_list) è un costrutto della libreria standard C++. Puoi usare gli elenchi di inizializzatori quando chiami alcuni metodi e costruttori di Windows Runtime. Ad esempio, puoi chiamare DataWriter::WriteBytes con uno.
#include <winrt/Windows.Storage.Streams.h>
using namespace winrt::Windows::Storage::Streams;
int main()
{
winrt::init_apartment();
InMemoryRandomAccessStream stream;
DataWriter dataWriter{stream};
dataWriter.WriteBytes({ 99, 98, 97 }); // the initializer list is converted to a winrt::array_view before being passed to WriteBytes.
}
Esistono due parti coinvolte in questo processo. Prima di tutto, il metodo DataWriter::WriteBytes accetta un parametro di tipo winrt::array_view.
void WriteBytes(winrt::array_view<uint8_t const> value) const
winrt::array_view è un tipo C++/WinRT personalizzato che rappresenta in modo sicuro una serie di valori contigui (è definito nella libreria di base C++/WinRT, ovvero %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h
).
In secondo luogo, winrt::array_view ha un costruttore di elenco di inizializzatori.
template <typename T> winrt::array_view(std::initializer_list<T> value) noexcept
In molti casi, puoi scegliere se essere a conoscenza o meno di winrt::array_view nella tua programmazione. Se scegli di non esserne a conoscenza, non avrai codice da modificare se e quando viene visualizzato un tipo equivalente nella libreria standard C++.
Puoi passare un elenco di inizializzatori a un'API di Windows Runtime che prevede un parametro di raccolta. Prendiamo, ad esempio, StorageItemContentProperties::RetrievePropertiesAsync.
IAsyncOperation<IMap<winrt::hstring, IInspectable>> StorageItemContentProperties::RetrievePropertiesAsync(IIterable<winrt::hstring> propertiesToRetrieve) const;
Puoi chiamare l'API con un elenco di inizializzatori simile a questo.
IAsyncAction retrieve_properties_async(StorageFile const storageFile)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync({ L"System.ItemUrl" }) };
}
Qui vengono presi in considerazione due fattori. Prima di tutto, il computer chiamato costruisce uno std::vector dall'elenco di inizializzatori; questo computer chiamato è asincrono, pertanto può e deve essere il proprietario di tale oggetto. In secondo luogo, C++/WinRT esegue il binding in modo trasparente, e senza introdurre copie, di std::vector come un parametro di raccolta di Windows Runtime.
Vettori e matrici standard
winrt::array_view include anche costruttori di conversione da std::vector e std::array.
template <typename C, size_type N> winrt::array_view(std::array<C, N>& value) noexcept
template <typename C> winrt::array_view(std::vector<C>& vectorValue) noexcept
Pertanto, puoi chiamare invece DataWriter::WriteBytes con uno std::vector.
std::vector<byte> theVector{ 99, 98, 97 };
dataWriter.WriteBytes(theVector); // theVector is converted to a winrt::array_view before being passed to WriteBytes.
O con uno std::array.
std::array<byte, 3> theArray{ 99, 98, 97 };
dataWriter.WriteBytes(theArray); // theArray is converted to a winrt::array_view before being passed to WriteBytes.
C++/WinRT esegue il binding di std::vector come parametro di raccolta di Windows Runtime. Pertanto, puoi passare uno std::vector<winrt::hstring> e verrà convertito nella raccolta di Windows Runtime appropriata di winrt::hstring. C'è un dettaglio aggiuntivo da tenere presente se il computer chiamato è asincrono. A causa dei dettagli di implementazione di questo caso, dovrai fornire un rvalue, pertanto è necessario fornire una copia o uno spostamento del vettore. Nell'esempio di codice riportato di seguito spostiamo la proprietà del vettore all'oggetto del tipo di parametro accettato dal computer chiamato asincrono; quindi facciamo attenzione a non accedere nuovamente a vecH
dopo lo spostamento. Se vuoi saperne di più sugli rvalue, vedi Categorie di valore e riferimenti.
IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<winrt::hstring> vecH)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecH)) };
}
Ma non puoi passare uno std::vector<std::wstring> dove è prevista una raccolta di Windows Runtime. Questo perché, dopo la conversione nella raccolta di Windows Runtime appropriata di std::wstring, il linguaggio C++ non forzerà i parametri di tipo della raccolta. Perciò il codice seguente non verrà compilato e la soluzione consiste nel passare invece std::vector<winrt::hstring> come illustrato in precedenza.
IAsyncAction retrieve_properties_async(StorageFile const storageFile, std::vector<std::wstring> vecW)
{
auto properties{ co_await storageFile.Properties().RetrievePropertiesAsync(std::move(vecW)) }; // error! Can't convert from vector of wstring to async_iterable of hstring.
}
Matrici non elaborate e intervalli di puntatori
Tenendo presente che un tipo equivalente potrebbe esistere in futuro nella libreria standard C++, puoi anche usare direttamente winrt::array_view per scelta o per necessità.
winrt::array_view ha costruttori di conversione a partire da una matrice non elaborata e da un intervallo di T (puntatori al tipo di elemento).
using namespace winrt;
...
byte theRawArray[]{ 99, 98, 97 };
array_view<byte const> fromRawArray{ theRawArray };
dataWriter.WriteBytes(fromRawArray); // the winrt::array_view is passed to WriteBytes.
array_view<byte const> fromRange{ theArray.data(), theArray.data() + 2 }; // just the first two elements.
dataWriter.WriteBytes(fromRange); // the winrt::array_view is passed to WriteBytes.
Operatori e funzioni winrt::array_view
Una serie di costruttori, operatori, funzioni e iteratori è implementata per winrt::array_view. Un winrt::array_view è un intervallo, pertanto puoi usarlo con for
basato su intervallo o con std::for_each.
Per ulteriori esempi e informazioni, vedi l'argomento del riferimento sull'API winrt::array_view.
IVector<T> e costrutti di iterazione standard
SyndicationFeed.Items è un esempio di API di Windows Runtime che restituisce una raccolta di tipo IVector<T>, proiettata in C++/WinRT come winrt::Windows::Foundation::Collections::IVector<T>. Puoi usare questo tipo con costrutti di iterazione standard, ad esempio for
basato su intervallo.
// main.cpp
#include "pch.h"
#include <winrt/Windows.Web.Syndication.h>
#include <iostream>
using namespace winrt;
using namespace Windows::Web::Syndication;
void PrintFeed(SyndicationFeed const& syndicationFeed)
{
for (SyndicationItem const& syndicationItem : syndicationFeed.Items())
{
std::wcout << syndicationItem.Title().Text().c_str() << std::endl;
}
}
Coroutine C++ con API di Windows Runtime asincrone
Puoi continuare a usare la libreria PPL (Parallel Patterns Library) durante le chiamate delle API di Windows Runtime asincrone. Tuttavia, in molti casi, le coroutine C++ offrono un linguaggio più efficiente e più facile da codificare per l'interazione con gli oggetti asincroni. Per altre informazioni ed esempi di codice, vedi Concorrenza e operazioni asincrone con C++/WinRT.
API importanti
- Interfaccia IVector<T>
- Modello di struct winrt::array_view