Gestion des chaînes en C++/WinRT

Avec C++/WinRT, vous pouvez appeler des API Windows Runtime à l’aide de types de chaînes étendues de la bibliothèque C++ standard comme std::wstring (remarque : pas avec des types de chaînes étroites comme std::string). C++/WinRT possède un type de chaîne personnalisée appelé winrt::hstring (défini dans la bibliothèque de base C++/WinRT, à savoir %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). Et c’est en fait le type de chaîne que les constructeurs, fonctions et propriétés Windows Runtime prennent et renvoient. Mais, dans de nombreux cas, grâce aux constructeurs de conversion et aux opérateurs de conversion de hstring, vous pouvez choisir de tenir compte ou non de hstring dans votre code client. Si vous créez des API, vous devrez probablement connaître hstring.

Il existe de nombreux types de chaîne en C++. Des variantes existent dans de nombreuses bibliothèques en plus de std::basic_string de la bibliothèque C++ standard. C++17 possède des utilitaires de conversion de chaînes et std::basic_string_view pour combler les écarts entre tous les types de chaîne. winrt::hstring fournit une convertibilité avec std::wstring_view afin de garantir l’interopérabilité pour laquelle std::basic_string_view a été conçu.

Utilisation de std::wstring (et éventuellement winrt::hstring) avec Uri

Windows::Foundation::Uri est construit à partir d’un winrt::hstring.

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

Mais hstring a des constructeurs de conversion qui vous permettent de l’utiliser sans avoir besoin d’en tenir compte. Voici un exemple de code illustrant comment créer un Uri à partir d’un littéral de chaîne étendue, à partir d’une vue de chaîne étendue et à partir d’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 };
}

L’accesseur de propriété Uri::Domain est de type hstring.

public:
    winrt::hstring Domain();

Mais, là encore, vous devez prendre conscience que ce détail est optionnel grâce à l’opérateur de conversion vers std::wstring_view de hstring.

// 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"

De même, IStringable::ToString renvoie hstring.

public:
    hstring ToString() const;

Uri implémente l’interface 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/"

Vous pouvez utiliser la fonction hstring::c_str pour obtenir une chaîne étendue standard à partir d’un hstring (comme à partir d’un std::wstring).

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

Si vous avez un hstring, vous pouvez créer un Uri à partir de celui-ci.

Uri awUriFromHstring{ tostringHstring };

Envisagez d’une méthode qui prend un hstring.

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

Toutes les options que vous venez de voir s’appliquent également dans de tels cas.

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

hstring a un opérateur de conversion std::wstring_view membre, et la conversion est obtenue sans effort.

void legacy_print(std::wstring_view view);

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

Fonctions et opérateurs winrt::hstring

Une série de constructeurs, d’opérateurs, de fonctions et d’itérateurs sont implémentés pour winrt::hstring.

Un hstring étant une plage, vous pouvez l’utiliser avec for basé sur les plages, ou avec std::for_each. Il fournit également des opérateurs de comparaison pour effectuer des comparaisons naturelles et efficaces à ses homologues dans la bibliothèque C++ standard. Et il inclut tout ce dont vous avez besoin pour utiliser hstring comme clé pour les conteneurs associatifs.

Nous reconnaissons que de nombreuses bibliothèques C++ utilisent std::string et fonctionnent exclusivement avec du texte UTF-8. Pour votre commodité, nous fournissons des programmes d’assistance, tels que winrt::to_string et winrt::to_hstring, pour la conversion arrière et dans les deux sens.

WINRT_ASSERT est une définition de macro qui est développée en _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!");

Pour obtenir plus d’informations et des exemples sur les fonctions et opérateurs hstring, consultez la rubrique sur les informations de référence API winrt::hstring.

Logique pour winrt::hstring et winrt::param::hstring

Windows Runtime est implémenté en termes de caractères wchar_t, mais l’interface binaire d’application (ABI) de Windows Runtime n’est pas un sous-ensemble de ce que fournit std::wstring ou std::wstring_view. L’utilisation de ceux-ci entraînerait des inefficacités importantes. Au lieu de cela, C++/WinRT fournit winrt::hstring, qui représente une chaîne immuable cohérente avec le HSTRING sous-jacent et implémenté derrière une interface similaire à celle de std::wstring.

Vous pouvez remarquer que les paramètres d’entrée C++/WinRT qui doivent accepter logiquement winrt::hstring attendent en fait winrt::param::hstring. L’espace de nom param contient un ensemble de types utilisés exclusivement pour optimiser les paramètres d’entrée afin d’effectuer la liaison naturelle aux types de la bibliothèque C++ standard et d’éviter des copies et autres inefficacités. Vous ne devez pas utiliser ces types directement. Si vous voulez utiliser une optimisation pour vos propres fonctions, utilisez std::wstring_view. Consultez également Passage de paramètres à la frontière ABI.

Le résultat est que vous pouvez ignorer les spécificités de la gestion des chaînes Windows Runtime, et travailler efficacement avec ce que vous connaissez. Et c’est important étant donné l’utilisation intensive des chaînes dans Windows Runtime.

Mise en forme des chaînes

Une des options de mise en forme des chaînes est std::wostringstream. Voici un exemple qui met en forme et affiche un message de suivi de débogage simple.

#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());
}

La bonne méthode pour définir une propriété

Vous définissez une propriété en passant une valeur à une fonction setter. Voici un exemple.

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

Le code ci-dessous est incorrect. Il se compile, mais il ne fait que modifier la winrt::hstring temporaire retournée par la fonction d’accesseur Text(), puis supprimer le résultat.

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

API importantes