Freigeben über


Zeichenfolgenbehandlung in C++/WinRT

Mit C++/WinRT-können Sie Windows-Runtime-APIs unter Verwendung der breiten Zeichenfolgentypen der C++-Standardbibliothek wie std::wstring aufrufen (beachten Sie: nicht mit schmalen Zeichenfolgentypen wie std::string). C++/WinRT verfügt über einen benutzerdefinierten Zeichenfolgentyp namens winrt::hstring (definiert in der C++/WinRT-Basisbibliothek, die %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.hist). Und das ist der Zeichenfolgentyp, den Windows-Runtime-Konstruktoren, -Funktionen und -Eigenschaften tatsächlich übernehmen und zurückgeben. Aber in vielen Fällen – dank der Konvertierungskonstruktoren und Konvertierungsoperatoren von hstring– können Sie auswählen, ob Sie sich hstring in Ihrem Client-Code bewusst sein möchten. Wenn Sie APIs erstellen, müssen Sie wahrscheinlich mehr über "hstring" wissen.

Es gibt viele Zeichenfolgentypen in C++. Varianten sind in vielen Bibliotheken zusätzlich zu std::basic_string aus der C++-Standardbibliothek vorhanden. C++17 verfügt über Hilfsprogramme für die Zeichenfolgenkonvertierung und std::basic_string_view, um die Lücken zwischen allen Zeichenfolgentypen zu überbrücken. winrt::hstring bietet Konvertierungsmöglichkeiten mit std::wstring_view, um die Interoperabilität bereitzustellen, für die std::basic_string_view entwickelt wurde.

Verwenden von std::wstring (und optional winrt::hstring) mit URI-

Windows::Foundation::Uri wird aus einem winrt::hstringerstellt.

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

hstring- verfügt jedoch über Konvertierungskonstruktoren, mit denen Sie arbeiten können, ohne sich dessen bewusst zu sein. Hier ist ein Codebeispiel, das zeigt, wie ein - URI aus einem breiten Zeichenfolgenliteral, aus einer breiten Zeichenfolgenansicht und aus einer std::wstringerstellt wird.

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

Der Eigenschaftsaccessor Uri::Domain ist vom Typ hstring.

public:
    winrt::hstring Domain();

Aber auch hier ist dieses Detail dank hstringKonvertierungsoperator in std::wstring_viewoptional.

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

Ebenso gibt IStringable::ToString hstring zurück.

public:
    hstring ToString() const;

Uri implementiert die IStringable Schnittstelle.

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

Sie können die hstring::c_str-Funktion verwenden, um eine Standard-Breitzeichenfolge aus einer hstring abzurufen (genau wie aus einer std::wstring).

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

Wenn Sie über eine hstring verfügen, können Sie daraus eine Uri erstellen.

Uri awUriFromHstring{ tostringHstring };

Betrachten Sie eine Methode, die eine hstring-verwendet.

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

Alle Optionen, die Sie gerade gesehen haben, gelten auch in solchen Fällen.

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

hstring- verfügt über einen std::wstring_view Konvertierungsoperator, und die Konvertierung erfolgt kostenlos.

void legacy_print(std::wstring_view view);

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

winrt::hstring Funktionen und Operatoren

Für winrt::hstringwerden eine Vielzahl von Konstruktoren, Operatoren, Funktionen und Iteratoren implementiert.

Ein ist ein Bereich, sodass Sie ihn mit reichweitenbasierten foroder mit std::for_eachverwenden können. Es stellt auch Vergleichsoperatoren für den natürlichen und effizienten Vergleich mit seinen Gegenstücken in der C++-Standardbibliothek bereit. Außerdem enthält es alles, was Sie benötigen, um hstring als Schlüssel für assoziative Container zu verwenden.

Wir erkennen, dass viele C++-Bibliotheken std::stringverwenden und ausschließlich mit UTF-8-Text arbeiten. Zur Vereinfachung bieten wir Hilfsfunktionen wie winrt::to_string und winrt::to_hstringfür die Konvertierung hin und her.

WINRT_ASSERT ist eine Makrodefinition und expandiert zu _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!");

Weitere Beispiele und Informationen zu hstring- Funktionen und Operatoren finden Sie im winrt::hstring API-Referenzthema.

Die Begründung für winrt::hstring und winrt::param::hstring

Die Windows-Runtime wird im Sinne von wchar_t Zeichen implementiert, aber das Application Binary Interface (ABI) der Windows-Runtime ist keine Teilmenge dessen, was entweder std::wstring oder std::wstring_view bereitstellen. Die Verwendung dieser Faktoren würde zu erheblichen Ineffizienzen führen. Stattdessen stellt C++/WinRT winrt::hstringbereit, die eine unveränderliche Zeichenfolge repräsentiert, die mit dem zugrunde liegenden HSTRINGkonsistent ist und hinter einer Schnittstelle implementiert ist, die der von std::wstringähnelt.

Möglicherweise stellen Sie fest, dass C++/WinRT-Eingabeparameter, die winrt::hstring tatsächlich erwarten, winrt::param::hstring. Der Param--Namespace enthält eine Reihe von Typen, die ausschließlich zum Optimieren von Eingabeparametern verwendet werden, um eine natürliche Bindung an C++-Standardbibliothekstypen zu ermöglichen und Kopien und andere Ineffizienzen zu vermeiden. Sie sollten diese Arten nicht direkt verwenden. Wenn Sie eine Optimierung für Ihre eigenen Funktionen verwenden möchten, verwenden Sie std::wstring_view. Siehe auch Übermittlung von Parametern an die ABI-Grenze.

Das Ergebnis ist, dass Sie die Besonderheiten der Windows-Runtime-Zeichenfolgenverwaltung weitgehend ignorieren können und einfach effizient mit dem arbeiten, was Sie bereits wissen. Und das ist wichtig, da in der Windows-Runtime stark Zeichenfolgen verwendet werden.

Formatieren von Zeichenfolgen

Eine Option für die Zeichenfolgenformatierung ist std::wostringstream. Hier ist ein Beispiel, das eine einfache Debugablaufverfolgungsmeldung formatiert und anzeigt.

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

Die richtige Methode zum Festlegen einer Eigenschaft

Sie legen eine Eigenschaft fest, indem Sie einen Wert an eine Setterfunktion übergeben. Hier ist ein Beispiel.

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

Der folgende Code ist falsch. Es wird kompiliert, aber alles, was es tut, ist die temporäre winrt::hstring, die von der Text() accessor function zurückgegeben wird, zu modifizieren, und dann wird das Ergebnis weggeworfen.

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

Wichtige APIs