Gestion des chaînes en C++/WinRT

Avec C++/WinRT, vous pouvez appeler Windows Runtime API à l’aide de types de chaînes larges de la bibliothèque C++ standard tels que std ::wstring (remarque : pas avec des types de chaîne étroits tels que std ::string). C++/WinRT a un type de chaîne personnalisé appelé winrt ::hstring (défini dans la bibliothèque de base C++/WinRT, autrement dit %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). Et c’est le type de chaîne que les constructeurs, les fonctions et les propriétés de Windows Runtime acceptent et renvoient réellement. Toutefois, dans de nombreux cas, grâce aux constructeurs de conversion et aux opérateurs de conversion de hstring, vous pouvez choisir d’avoir ou non à vous soucier de hstring dans le code client. Si vous concevez des API, vous aurez probablement besoin de connaître hstring.

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

Utiliser 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 travailler avec lui sans avoir besoin de le connaître. Voici un exemple de code montrant comment créer un URI à partir d’un littéral de chaîne large, d’une vue de chaîne large et 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, encore une fois, sachez que ce détail est facultatif grâce à l’opérateur de conversion de hstringen 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"

De même, IStringable ::ToString retourne 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 large standard à partir d’une chaîne hstring (comme vous pouvez à partir d’un std ::wstring).

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

Si vous avez une chaîne hstring , vous pouvez créer un URI à partir de celui-ci.

Uri awUriFromHstring{ tostringHstring };

Considérez une méthode qui prend une hstring.

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

Toutes les options que vous venez de voir s’appliquent également dans ce 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 coût.

void legacy_print(std::wstring_view view);

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

fonctions et opérateurs winrt ::hstring

De nombreux constructeurs, opérateurs, fonctions et itérateurs sont implémentés pour winrt::hstring.

Un hstring est un intervalle, vous pouvez donc l’utiliser avec for basées sur les intervalles, ou avec std::for_each. Il fournit également des opérateurs de comparaison pour comparer naturellement et efficacement ses équivalents dans la bibliothèque C++ Standard. 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. Par commodité, nous fournissons des fonctions utilitaires, comme winrt::to_string et winrt::to_hstring, pour effectuer les conversions dans les deux sens.

WINRT_ASSERT est une définition de macro, et elle s’étend à _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 plus d’exemples et d’informations sur les fonctions et opérateurs hstring , consultez la rubrique de référence de l’API winrt ::hstring .

Justification de winrt ::hstring et winrt ::p aram ::hstring

La Windows Runtime est implémentée 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 fournissent std ::wstring ou std ::wstring_view. L’utilisation de ces éléments entraînerait une inefficacité importante. 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ée derrière une interface similaire à celle de std ::wstring.

Vous remarquerez peut-être que les paramètres d’entrée C++/WinRT qui doivent accepter logiquement winrt ::hstring attendent réellement winrt ::p aram ::hstring. L’espace de noms param contient un ensemble de types utilisés exclusivement pour optimiser les paramètres d’entrée afin de lier naturellement aux types de bibliothèque standard C++ et éviter les copies et d’autres inefficacités. Vous ne devez pas utiliser ces types directement. Si vous souhaitez utiliser une optimisation pour vos propres fonctions, utilisez std ::wstring_view. Voir également Passage de paramètres dans la limite ABI.

En fin de compte, vous pouvez en grande partie ignorer les spécificités de la gestion des chaînes de Windows Runtime et simplement travailler efficacement avec ce que vous connaissez déjà. Et c'est important, étant donné la grande quantité de chaînes utilisées dans le Windows Runtime.

Chaînes de mise en forme

Une option pour la mise en forme de chaîne est std ::wostringstream. Voici un exemple qui met en forme et affiche un message de trace de débogage simple.

#include <sstream>
#include <winrt/Microsoft.UI.Input.h>
#include <winrt/Microsoft.UI.Xaml.Input.h>
...
void MainPage::OnPointerPressed(winrt::Microsoft::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 façon de définir une propriété

Vous définissez une propriété en transmettant 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 compile, mais tout cela consiste à modifier le winrt ::hstring temporaire retourné par la fonction d’accesseur Text(), puis à lever le résultat.

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

API importantes