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