Stränghantering i C++/WinRT

Med C++/WinRT kan du anropa Windows Runtime API:er med hjälp av breda strängtyper för C++-standardbiblioteket, till exempel std::wstring (obs! inte med smala strängtyper som std::string). C++/WinRT har en anpassad strängtyp som kallas winrt::hstring (definieras i C++/WinRT-basbiblioteket, som är %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). Och det är den strängtyp som Windows Runtime konstruktorer, funktioner och egenskaper faktiskt tar och returnerar. Men i många fall – tack vare Hstrings konverteringskonstruktorer och konverteringsoperatorer – kan du välja om du vill vara medveten om hstring i klientkoden eller inte. Om du redigerar API:er är det mer troligt att du behöver veta mer om hstring.

Det finns många strängtyper i C++. Varianter finns i många bibliotek utöver std::basic_string från C++-standardbiblioteket. C++17 har verktyg för strängkonvertering och std::basic_string_view för att överbrygga luckor mellan alla strängtyper. winrt::hstring ger konvertibilitet med std::wstring_view för att tillhandahålla samverkan som std::basic_string_view har utformats för.

Använda std::wstring (och valfritt winrt::hstring) med Uri

Windows::Foundation::Uri är konstruerad från en winrt::hstring.

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

Men hstring har konverteringskonstruktorer som gör att du kan arbeta med det utan att behöva vara medveten om det. Här är ett kodexempel som visar hur du skapar en Uri från en strängliteral med breda tecken, från en strängvy med breda tecken och från en 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 };
}

Egenskapsåtkomsten Uri::Domain är av typen hstring.

public:
    winrt::hstring Domain();

Men, återigen, är det valfritt att känna till den detaljen tack vare hstring:s konverteringsoperatorn till 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"

På samma sätt returnerar IStringable::ToString hstring.

public:
    hstring ToString() const;

Uri implementerar IStringable-gränssnittet .

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

Du kan använda funktionen hstring::c_str för att hämta en standardbreddssträng från en hstring (precis som du kan från en std::wstring).

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

Om du har en hstring kan du göra en Uri från den.

Uri awUriFromHstring{ tostringHstring };

Överväg en metod som tar en hstring.

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

Alla alternativ som du just har sett gäller även i sådana fall.

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

hstring har en medlems-std::wstring_view konverteringsoperator och konverteringen sker utan kostnad.

void legacy_print(std::wstring_view view);

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

winrt::hstring funktioner och operatorer

En mängd konstruktorer, operatorer, funktioner och iteratorer implementeras för winrt::hstring.

En hstring är ett intervall, så du kan använda det med intervallbaserad for, eller med std::for_each. Den tillhandahåller också jämförelseoperatorer för att på ett naturligt och effektivt sätt jämföra med dess motsvarigheter i C++-standardbiblioteket. Och den innehåller allt du behöver för att använda hstring som en nyckel för associativa containrar.

Vi inser att många C++-bibliotek använder std::string och arbetar uteslutande med UTF-8-text. Som en bekvämlighet tillhandahåller vi hjälpare, till exempel winrt::to_string och winrt::to_hstring, för konvertering fram och tillbaka.

WINRT_ASSERT är en makrodefinition och expanderas till _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!");

Fler exempel och information om hstring-funktioner och operatorer finns i referensavsnittet winrt::hstring API.

Bakgrunden till winrt::hstring och winrt::param::hstring

Windows Runtime implementeras med wchar_t-tecken, men Windows Runtimes binärgränssnitt för applikationer (ABI) är inte en delmängd av det som varken std::wstring eller std::wstring_view tillhandahåller. Användning av dessa skulle leda till betydande ineffektivitet. I stället tillhandahåller C++/WinRT winrt::hstring, som representerar en oföränderlig sträng som överensstämmer med den underliggande HSTRING och implementeras bakom ett gränssnitt som liknar std::wstring.

Du kanske märker att C++/WinRT-indataparametrar som logiskt bör acceptera winrt::hstring faktiskt förväntar sig winrt::p aram::hstring. Param-namnområdet innehåller en uppsättning typer som uteslutande används för att optimera indataparametrar för att naturligt binda till C++-standardbibliotekstyper och undvika kopior och andra ineffektiviteter. Du bör inte använda dessa typer direkt. Om du vill använda en optimering för dina egna funktioner använder du std::wstring_view. Se även Skicka parametrar till ABI-gränsen.

Resultatet är att du till stor del kan ignorera detaljerna i Windows Runtime stränghantering och bara arbeta med effektivitet med det du vet. Och det är viktigt, med tanke på hur mycket strängar används i Windows Runtime.

Formateringssträngar

Ett alternativ för strängformatering är std::wostringstream. Här är ett exempel som formaterar och visar ett enkelt felsökningsspårningsmeddelande.

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

Rätt sätt att ange en egenskap

Du anger en egenskap genom att skicka ett värde till en setter-funktion. Här följer ett exempel.

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

Koden nedan är felaktig. Det kompilerar, men det enda det gör är att ändra den tillfälliga winrt::hstring som returneras av åtkomstfunktionen Text() och sedan kasta bort resultatet.

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

Viktiga API:er