Udostępnij za pomocą


Obsługa ciągów w języku C++/WinRT

Za pomocą C++/WinRTmożna wywoływać interfejsy API środowiska uruchomieniowego systemu Windows przy użyciu standardowych typów ciągów biblioteki C++, takich jak std::wstring (uwaga: nie z wąskimi typami ciągów, takimi jak std::string). Język C++/WinRT ma niestandardowy typ ciągu o nazwie winrt::hstring (zdefiniowany w bibliotece podstawowej C++/WinRT, która jest %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). I to jest typ ciągu, który konstruktory, funkcje i właściwości środowiska wykonawczego systemu Windows rzeczywiście przyjmują i zwracają. Jednak w wielu przypadkach — dzięki konstruktorów konwersji i operatorów konwersji — możesz zdecydować, czy w kodzie klienta. Jeśli jesteś twórcą interfejsów API, to bardziej prawdopodobne, że będziesz musiał wiedzieć o hstring.

W języku C++istnieje wiele typów ciągów. Warianty istnieją w wielu bibliotekach oprócz std::basic_string z standardowej biblioteki języka C++. Język C++17 ma narzędzia konwersji ciągów i std::basic_string_view, aby wypełnić luki między wszystkimi typami ciągów. winrt::hstring zapewnia możliwość konwersji z std::wstring_view, zapewniając interoperacyjność, do której został zaprojektowany std::basic_string_view.

Używanie std::wstring (i opcjonalnie winrt::hstring) z Uri

Windows::Foundation::Uri jest tworzony z winrt::hstring.

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

Jednak hstring ma konstruktory konwersji , które pozwalają pracować z nim bez konieczności ich świadomego rozumienia. Oto przykład kodu pokazujący, jak utworzyć identyfikator URI z szerokiego literału ciągu, z szerokiego widoku ciągów i z 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 };
}

Właściwość dostępu Uri::Domain jest typu hstring.

public:
    winrt::hstring Domain();

Ale ponownie, świadomość tego szczegółu jest opcjonalna dzięki hstringoperator konwersji do 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"

Podobnie funkcja IStringable::ToString zwraca wartość hstring.

public:
    hstring ToString() const;

Uri implementuje interfejs 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/"

Możesz użyć funkcji hstring::c_str, aby uzyskać standardowy szeroki łańcuch znaków z hstring (tak jak z std::wstring).

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

Jeśli masz hstring, możesz utworzyć identyfikator URI.

Uri awUriFromHstring{ tostringHstring };

Rozważ metodę, która przyjmuje hstring.

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

Wszystkie widoczne opcje mają zastosowanie również w takich przypadkach.

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

hstring ma operatora konwersji elementu członkowskiego std::wstring_view, a konwersja jest osiągana bez ponoszenia kosztów.

void legacy_print(std::wstring_view view);

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

funkcje i operatory winrt::hstring

Host konstruktorów, operatorów, funkcji i iteratorów jest implementowany dla winrt::hstring.

to zakres, więc można go używać z konstrukcjami opartymi na zakresie lub z . Udostępnia również operatory porównania do naturalnego i wydajnego porównywania ze swoimi odpowiednikami w Bibliotece Standardowej C++. Obejmuje to wszystko, czego potrzebujesz, aby użyć hstring jako klucza do kontenerów asocjacyjnych.

Wiemy, że wiele bibliotek języka C++ używa std::stringi działa wyłącznie z tekstem UTF-8. Dla wygody zapewniamy pomocników, takich jak winrt::to_string i winrt::to_hstring, do konwersji tam iz powrotem.

WINRT_ASSERT jest definicją makra i rozwija się do _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!");

Aby uzyskać więcej przykładów i informacji na temat funkcji i operatorów hstring, zobacz temat referencyjny API winrt::hstring.

Uzasadnienie winrt::hstring i winrt::param::hstring

Środowisko uruchomieniowe systemu Windows jest implementowane w odniesieniu do znaków wchar_t, ale interfejs binarny aplikacji środowiska uruchomieniowego systemu Windows (ABI) nie jest podzbiorem tego, co dostarczają std::wstring lub std::wstring_view. Użycie tych doprowadziłoby do znacznej nieefektywności. Zamiast tego język C++/WinRT udostępnia winrt::hstring, który reprezentuje niezmienny ciąg zgodny z bazowymi HSTRINGi zaimplementowany w ramach interfejsu podobnego do std::wstring.

Można zauważyć, że parametry wejściowe C++/WinRT, które powinny logicznie akceptować winrt::hstring, rzeczywiście oczekują winrt::param::hstring. param przestrzeni nazw zawiera zestaw typów używanych wyłącznie do optymalizowania parametrów wejściowych dla naturalnego powiązania z typami Standardowej Biblioteki C++ oraz unikania kopiowania i innych nieefektywności. Nie należy używać tych typów bezpośrednio. Jeśli chcesz użyć optymalizacji dla własnych funkcji, użyj polecenia std::wstring_view. Zobacz również Przekazywanie parametrów przez granicę ABI.

Podsumowując, można w dużej mierze zignorować szczegóły dotyczące zarządzania ciągami w środowisku uruchomieniowym systemu Windows i po prostu skutecznie pracować na podstawie swojej wiedzy. I to ważne, biorąc pod uwagę, jak mocno ciągi są używane w środowisku uruchomieniowym systemu Windows.

Formatowanie ciągów

Jedną z opcji formatowania ciągów jest std::wostringstream. Oto przykład, który formatuje i wyświetla prosty ślad debugowania.

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

Prawidłowy sposób ustawiania właściwości

Właściwość można ustawić, przekazując wartość do funkcji ustawiającej. Oto przykład.

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

Poniższy kod jest niepoprawny. Kompiluje, ale wszystko, co robi, to zmiana tymczasowego winrt::hstring zwróconego przez funkcję dostępową Text(), a następnie wyrzucenie wyniku.

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

Ważne interfejsy API