Compartir a través de


Control de cadenas en C++/WinRT

Con de C++/WinRT, puedes llamar a las API de Windows Runtime mediante tipos de cadena ancha de la biblioteca estándar de C++, como std::wstring (nota: no con tipos de cadenas estrechas, como std::string). C++/WinRT tiene un tipo de cadena personalizado denominado winrt::hstring (definido en la biblioteca base de C++/WinRT, que es %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). Y es el tipo de cadena que los constructores, funciones y propiedades de Windows Runtime toman y devuelven realmente. Pero en muchos casos, gracias a los constructores y operadores de conversión de hstring, puede elegir si desea tener en cuenta o no hstring en su código cliente. Si está creación de API de, es más probable que tenga que conocer hstring.

Hay muchos tipos de cadena en C++. Existen variantes en muchas bibliotecas además de std::basic_string de la biblioteca estándar de C++. C++17 tiene utilidades de conversión de cadenas y std::basic_string_view, para salvar las brechas entre todos los tipos de cadena. winrt::hstring proporciona la convertibilidad con std::wstring_view para ofrecer la interoperabilidad para la cual fue diseñado std::basic_string_view.

Uso de std::wstring (y, opcionalmente, winrt::hstring) con Uri

Windows::Foundation::Uri se construye a partir de un winrt::hstring.

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

Pero hstring tiene constructores de conversión que te permiten trabajar con él sin necesidad de ser consciente de ello. Este es un ejemplo de código que muestra cómo crear un Uri a partir de un literal de cadena amplia, desde una vista de cadena amplia y desde una 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 };
}

El descriptor de acceso de propiedad Uri::Domain es de tipo hstring.

public:
    winrt::hstring Domain();

Pero, de nuevo, tener en cuenta que los detalles son opcionales gracias a hstringoperador de conversión de a 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"

Del mismo modo, IStringable::ToString devuelve hstring.

public:
    hstring ToString() const;

Uri implementa la interfaz 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/"

Puede usar la función hstring::c_str para obtener una cadena de caracteres ancha estándar de un hstring (igual que puede con un std::wstring).

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

Si tiene un hstring, entonces puede crear un Uri a partir de él.

Uri awUriFromHstring{ tostringHstring };

Considere un método que recibe un hstring.

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

Todas las opciones que acaba de ver también se aplican en estos casos.

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

hstring tiene un miembro std::wstring_view operador de conversión y la conversión se logra sin costo alguno.

void legacy_print(std::wstring_view view);

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

winrt::hstring funciones y operadores

Se implementa un host de constructores, operadores, funciones e iteradores para winrt::hstring.

Un hstring es un intervalo, por lo que, basándose en intervalos, puede usarlo con foro con std::for_each. También proporciona operadores de comparación para comparar de forma natural y eficaz sus homólogos en la biblioteca estándar de C++. Además, incluye todo lo que necesita para usar hstring como clave para los contenedores asociativos.

Reconocemos que muchas bibliotecas de C++ usan std::stringy funcionan exclusivamente con texto UTF-8. Para su conveniencia, proporcionamos utilidades, como winrt::to_string y winrt::to_hstring, para convertir hacia atrás y hacia delante.

WINRT_ASSERT es una definición de macro y se expande a _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!");

Para obtener más ejemplos e información sobre las funciones y operadores de hstring, consulta el tema de referencia de la API winrt::hstring .

La justificación de winrt::hstring y winrt::param::hstring

La Runtime de Windows se implementa en términos de caracteres de wchar_t, pero la interfaz binaria de aplicaciones (ABI) de la Runtime de Windows no es un subconjunto de lo que proporcionan ni std::wstring ni std::wstring_view. El uso de estos provocaría una ineficacia significativa. En su lugar, C++/WinRT proporciona winrt::hstring, que representa una cadena inmutable coherente con el HSTRING subyacentee implementado detrás de una interfaz similar a la de std::wstring.

Puede observar que los parámetros de entrada de C++/WinRT que deberían aceptar lógicamente winrt::hstring en realidad esperan winrt::param::hstring. El espacio de nombres param contiene un conjunto de tipos usados exclusivamente para optimizar los parámetros de entrada para enlazar naturalmente a tipos de biblioteca estándar de C++ y evitar copias y otras ineficiencias. No deberías usar estos tipos directamente. Si desea usar una optimización para sus propias funciones, use std::wstring_view. Consulte también Pasar parámetros al límite de ABI.

El resultado es que puedes ignorar en gran medida los detalles de la administración de cadenas de Windows Runtime y trabajar con eficacia con lo que sabes. Y eso es importante, dada la cantidad de cadenas que se usan en Windows Runtime.

Formato de cadenas

Una opción para el formato de cadena es std::wostringstream. Este es un ejemplo que formatea y muestra un simple mensaje de seguimiento de depuración.

#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 manera correcta de establecer una propiedad

Para establecer una propiedad, pase un valor a una función set. Este es un ejemplo.

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

El código siguiente es incorrecto. Compila, pero lo único que hace es modificar el temporal winrt::hstring devuelto por la función accesora Text() y luego descartar el resultado.

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

API importantes