Condividi tramite


Gestione delle stringhe in C++/WinRT

Con C++/WinRT, è possibile chiamare le API di Windows Runtime usando tipi di stringa wide della libreria standard C++, come std::wstring (nota: non con tipi di stringa narrow, come std::string). C++/WinRT dispone di un tipo stringa personalizzato denominato winrt::hstring (definito nella libreria di base C++/WinRT, che è %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). E questo è il tipo stringa che i costruttori, le funzioni e le proprietà di Windows Runtime accettano e restituiscono effettivamente. Tuttavia, in molti casi, grazie a costruttori di conversione e operatori di conversione di hstring, è possibile scegliere se hstring nel codice client. Se stai creando API, avrai più probabilità di avere bisogno di sapere hstring.

Esistono molti tipi di stringa in C++. Le varianti esistono in molte librerie oltre a std::basic_string dalla libreria standard C++. C++17 include utilità di conversione di stringhe e std::basic_string_view, per colmare le lacune tra tutti i tipi di stringa. winrt::hstring fornisce la convertibilità con std::wstring_view per fornire l'interoperabilità per cui è stato progettato std::basic_string_view.

Utilizzo di std::wstring (e facoltativamente winrt::hstring) con Uri

Windows::Foundation::Uri è costruito da un winrt::hstring.

public:
    Uri(winrt::hstring uri) const;

Ma hstring ha costruttori di conversione che consentono di usarlo senza bisogno di esserne consapevoli. Di seguito è riportato un esempio di codice che illustra come creare un URI di da un valore letterale stringa wide, da una visualizzazione stringa estesa e da un std::wstring.

#include <winrt/Windows.Foundation.h>
#include <string_view>

using namespace winrt;
using namespace Windows::Foundation;

int main()
{
    using namespace std::literals;

    winrt::init_apartment();

    // You can make a Uri from a wide string literal.
    Uri contosoUri{ L"http://www.contoso.com" };

    // Or from a wide string view.
    Uri contosoSVUri{ L"http://www.contoso.com"sv };

    // Or from a std::wstring.
    std::wstring wideString{ L"http://www.adventure-works.com" };
    Uri awUri{ wideString };
}

La funzione di accesso della proprietà Uri::Domain è di tipo hstring.

public:
    winrt::hstring Domain();

Tuttavia, anche in questo caso, tenere presente che il dettaglio è facoltativo grazie all'operatore di conversione hstring a std::wstring_view.

// Access a property of type hstring, via a conversion operator to a standard type.
std::wstring domainWstring{ contosoUri.Domain() }; // L"contoso.com"
domainWstring = awUri.Domain(); // L"adventure-works.com"

// Or, you can choose to keep the hstring unconverted.
hstring domainHstring{ contosoUri.Domain() }; // L"contoso.com"
domainHstring = awUri.Domain(); // L"adventure-works.com"

Analogamente, IStringable::ToString restituisce hstring.

public:
    hstring ToString() const;

URI implementa l'interfaccia IStringable.

// Access hstring's IStringable::ToString, via a conversion operator to a standard type.
std::wstring tostringWstring{ contosoUri.ToString() }; // L"http://www.contoso.com/"
tostringWstring = awUri.ToString(); // L"http://www.adventure-works.com/"

// Or you can choose to keep the hstring unconverted.
hstring tostringHstring{ contosoUri.ToString() }; // L"http://www.contoso.com/"
tostringHstring = awUri.ToString(); // L"http://www.adventure-works.com/"

È possibile usare la funzione hstring::c_str per ottenere una stringa larga standard da un hstring (proprio come si può fare da un std::wstring).

#include <iostream>
std::wcout << tostringHstring.c_str() << std::endl;

Se hai un hstring, allora puoi creare un Uri a partire da esso.

Uri awUriFromHstring{ tostringHstring };

Si consideri un metodo che accetta un hstring.

public:
    Uri CombineUri(winrt::hstring relativeUri) const;

Tutte le opzioni appena visualizzate si applicano anche in questi casi.

std::wstring contact{ L"contact" };
contosoUri = contosoUri.CombineUri(contact);
    
std::wcout << contosoUri.ToString().c_str() << std::endl;

hstring ha un membro operatore di conversione std::wstring_view e la conversione viene eseguita senza costi aggiuntivi.

void legacy_print(std::wstring_view view);

void Print(winrt::hstring const& hstring)
{
    legacy_print(hstring);
}

funzioni e operatori winrt::hstring

Per winrt::hstringvengono implementati un host di costruttori, operatori, funzioni e iteratori.

Un hstring è un intervallo, quindi è possibile usarlo con intervalli basati su foro con std::for_each. Fornisce anche operatori di confronto per effettuare confronti in modo naturale ed efficiente con i suoi omologhi nella Libreria Standard C++. E include tutto ciò necessario per utilizzare hstring come chiave di contenitori associativi.

Si riconosce che molte librerie C++ usano std::stringe funzionano esclusivamente con il testo UTF-8. Per comodità, forniamo strumenti di supporto, ad esempio winrt::to_string e winrt::to_hstring, per la conversione bidirezionale.

WINRT_ASSERT è una definizione di macro e si espande fino a _ASSERTE.

winrt::hstring w{ L"Hello, World!" };

std::string c = winrt::to_string(w);
WINRT_ASSERT(c == "Hello, World!");

w = winrt::to_hstring(c);
WINRT_ASSERT(w == L"Hello, World!");

Per altri esempi e informazioni su funzioni e operatori hstring, vedi l'argomento di riferimento sull'API winrt::hstring.

La logica per winrt::hstring e winrt::param::hstring

La Windows Runtime è implementata tramite caratteri wchar_t, ma l'interfaccia Application Binary (ABI) di Windows Runtime non è un sottoinsieme di quanto fornito da std::wstring o std::wstring_view. L'uso di queste causerebbe un'inefficienza significativa. C++/WinRT fornisce invece winrt::hstring, che rappresenta una stringa non modificabile coerente con l'HSTRINGe implementata dietro un'interfaccia simile a quella di std::wstring.

È possibile notare che i parametri di input C++/WinRT che devono accettare logicamente winrt::hstring in realtà ci si aspetta che accettino winrt::param::hstring. Lo spazio dei nomi param contiene un insieme di tipi utilizzati esclusivamente per ottimizzare i parametri di input e legarsi naturalmente ai tipi della libreria standard C++ ed evitare copie e altre inefficienze. Questi tipi non devono essere usati direttamente. Se si vuole usare un'ottimizzazione per le proprie funzioni, usare std::wstring_view. Consulta anche Passaggio di parametri nel limite ABI.

Il risultato è che puoi in gran parte ignorare le specifiche della gestione delle stringhe di Windows Runtime e lavorare con maggiore efficienza con ciò che conosci. Ed è importante, data la quantità di stringhe usate in Windows Runtime.

Formattazione di stringhe

Un'opzione per la formattazione delle stringhe è std::wostringstream. Ecco un esempio che formatta e visualizza un semplice messaggio di traccia di debug.

#include <sstream>
#include <winrt/Windows.UI.Input.h>
#include <winrt/Windows.UI.Xaml.Input.h>
...
void MainPage::OnPointerPressed(winrt::Windows::UI::Xaml::Input::PointerRoutedEventArgs const& e)
{
    winrt::Windows::Foundation::Point const point{ e.GetCurrentPoint(nullptr).Position() };
    std::wostringstream wostringstream;
    wostringstream << L"Pointer pressed at (" << point.X << L"," << point.Y << L")" << std::endl;
    ::OutputDebugString(wostringstream.str().c_str());
}

Il modo corretto per impostare una proprietà

Per impostare una proprietà, passare un valore a una funzione setter. Ecco un esempio.

// The right way to set the Text property.
myTextBlock.Text(L"Hello!");

Il codice seguente non è corretto. Il codice viene compilato, ma tutto ciò che fa consiste nel modificare il temporaneo winrt::hstring restituito dalla funzione di accesso Text() e poi scartare il risultato.

// *Not* the right way to set the Text property.
myTextBlock.Text() = L"Hello!";

API importanti