Compartilhar via


Manipulação de cadeia de caracteres em C++/WinRT

Com C++/WinRT, você pode chamar APIs do Windows Runtime usando tipos de cadeia de caracteres largos da Biblioteca Padrão C++, como std::wstring (observação: não com tipos de cadeia de caracteres estreitos, como std::string). O C++/WinRT tem um tipo de cadeia de caracteres personalizado chamado winrt::hstring (definido na biblioteca base C++/WinRT, que é %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). E esse é o tipo de cadeia de caracteres que construtores, funções e propriedades do Windows Runtime realmente tomam e retornam. Mas, em muitos casos, graças a construtores de conversão e operadores de conversão dode hstring, você pode escolher se deve ou não estar ciente de de hstring no código do cliente. Se você estiver criando APIs, é mais provável que precise saber sobre hstring.

Há muitos tipos de cadeia de caracteres no C++. Variantes existem em muitas bibliotecas, além de std::basic_string da Biblioteca Padrão C++. O C++17 tem utilitários de conversão de cadeia de caracteres e std::basic_string_view, para fazer a ponte entre todos os tipos de cadeia de caracteres. winrt::hstring oferece capacidade de conversão com std::wstring_view para fornecer a interoperabilidade para a qual std::basic_string_view foi projetado.

Usando std::wstring (e, opcionalmente, winrt::hstring) com Uri

Windows::Foundation::Uri é construído a partir de um winrt::hstring.

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

Mas hstring tem construtores de conversão que permitem que você trabalhe com ele sem precisar estar ciente disso. Aqui está um exemplo de código mostrando como criar um Uri a partir de uma string literal ampla, de uma visão de string ampla e de um 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 };
}

O acessador de propriedades Uri::Domain é do tipo hstring.

public:
    winrt::hstring Domain();

Mas, novamente, estar ciente desse detalhe é opcional graças a operador de conversão dede hstring para 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"

Da mesma forma, IStringable::ToString retorna hstring.

public:
    hstring ToString() const;

Uri implementa a interfaceIStringable.

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

Você pode usar a função hstring::c_str para obter uma cadeia de caracteres larga padrão de um hstring (da mesma forma que você pode a partir de um std::wstring).

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

Se você tiver um hstring , poderá criar um Uri a partir dele.

Uri awUriFromHstring{ tostringHstring };

Considere um método que recebe um hstring.

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

Todas as opções que você acabou de ver também se aplicam nesses casos.

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

de hstring tem um membro operador de conversão std::wstring_view e a conversão é obtida sem custo.

void legacy_print(std::wstring_view view);

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

funções e operadores de winrt::hstring

Um host de construtores, operadores, funções e iteradores são implementados para winrt::hstring.

Um hstring é um intervalo , portanto, você pode usá-lo com um intervalo baseado em ou com . Ele também fornece operadores de comparação para comparação natural e eficiente com seus equivalentes na Biblioteca Padrão do C++. E inclui tudo o que você precisa para usar hstring como chave para contêineres associativos.

Reconhecemos que muitas bibliotecas C++ usam std::string e funcionam exclusivamente com texto UTF-8. Como conveniência, fornecemos auxiliares, como winrt::to_string e winrt::to_hstring, para converter de ida e volta.

WINRT_ASSERT é uma definição de macro e se expande para _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 obter mais exemplos e informações sobre funções e operadores de hstring, consulte o tópico de referência da API winrt::hstring.

A lógica para winrt::hstring e winrt::p aram::hstring

O Windows Runtime é implementado em termos de wchar_t caracteres, mas a ABI (Interface Binária de Aplicativos) do Windows Runtime não é um subconjunto do que std::wstring ou std::wstring_view fornecem. Usá-los levaria a uma ineficiência significativa. Em vez disso, C++/WinRT fornece winrt::hstring, que representa uma string imutável consistente com a HSTRINGsubjacente e implementada por trás de uma interface semelhante à de std::wstring.

Você pode observar que os parâmetros de entrada C++/WinRT que devem aceitar logicamente winrt::hstring na verdade esperam winrt::param::hstring. O namespace do parâmetro contém um conjunto de tipos usados exclusivamente para otimizar os parâmetros de entrada para se alinharem naturalmente com os tipos da Standard Library do C++ e evitar cópias e outras ineficiências. Você não deve usar esses tipos diretamente. Se você quiser usar uma otimização para suas próprias funções, use std::wstring_view. Veja também Passando parâmetros para o limite da ABI.

O resultado é que você pode ignorar em grande parte as especificidades do gerenciamento de cadeias de caracteres do Windows Runtime e apenas trabalhar com eficiência com o que você sabe. E isso é importante, considerando o quanto as cadeias de caracteres são usadas no Windows Runtime.

Formatação de cadeias de caracteres

Uma opção para formatação de cadeia de caracteres é std::wostringstream. Aqui está um exemplo que formata e exibe uma mensagem de rastreamento de depuração simples.

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

A maneira correta de definir uma propriedade

Você define uma propriedade passando um valor para uma função setter. Aqui está um exemplo.

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

O código abaixo está incorreto. Compila, mas tudo o que faz é modificar o winrt::hstring temporário retornado pelo acessador Text(), e depois descartar o resultado.

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

APIs importantes