C++/WinRT 中的字串處理String handling in C++/WinRT

有了 C++/WinRT,您可以使用 C++ 標準程式庫寬字串類型 (例如 std::wstring) ,來呼叫 Windows 執行階段 API (請注意:無法與縮小字串類型例如 std::string 共用)。With C++/WinRT, you can call Windows Runtime APIs using C++ Standard Library wide string types such as std::wstring (note: not with narrow string types such as std::string). C++/WinRT 有一個稱為 winrt::hstring 的自訂字串類型 (在 C++/WinRT 基底程式庫中定義,也就是 %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h)。C++/WinRT does have a custom string type called winrt::hstring (defined in the C++/WinRT base library, which is %WindowsSdkDir%Include\<WindowsTargetPlatformVersion>\cppwinrt\winrt\base.h). 且這是 Windows 執行階段建構函式、函式和屬性確實採用與傳回的字串類型。And that's the string type that Windows Runtime constructors, functions, and properties actually take and return. 但在許多情況下,—由於 hstring 的轉換建構函式和轉換運算子—您可以選擇是否要注意用戶端程式碼中的 hstringBut in many cases—thanks to hstring's conversion constructors and conversion operators—you can choose whether or not to be aware of hstring in your client code. 如果您正在撰寫 API,更需要深入了解 hstringIf you're authoring APIs, then you're more likely to need to know about hstring.

C++ 有許多字串類型。There are many string types in C++. 許多程式庫裡存在著變體,除了來自 C++ 標準程式庫的 std::basic_string 以外。Variants exist in many libraries in addition to std::basic_string from the C++ Standard Library. C++17 有字串轉換公用程式,以及 std::basic_string_view,來橋接所有字串類型間的間隔。C++17 has string conversion utilities, and std::basic_string_view, to bridge the gaps between all of the string types. winrt::hstring 提供 std::wstring_view 的轉換性,以提供 std::basic_string_view 為設計目的的互通性。winrt::hstring provides convertibility with std::wstring_view to provide the interoperability that std::basic_string_view was designed for.

std::wstring (並選擇性地使用 winrt::hstring) 與 Uri 搭配使用Using std::wstring (and optionally winrt::hstring) with Uri

Windows::Foundation::Uri 建構自 winrt::hstringWindows::Foundation::Uri is constructed from a winrt::hstring.

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

但是 hstring轉換建構函式,讓您在不知不覺中使用它。But hstring has conversion constructors that let you work with it without needing to be aware of it. 以下是程式碼範例顯示如何從寬字串常值、寬字串檢視,以及 std::wstring,製作一個 UriHere's a code example showing how to make a Uri from a wide string literal, from a wide string view, and from a 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 };
}

屬性存取子 Uri::Domain 的類型為 hstringThe property accessor Uri::Domain is of type hstring.

public:
    winrt::hstring Domain();

但是,由於 hstringstd::wstring_view 的轉換運算子,可注意到該詳細資料是選擇性的。But, again, being aware of that detail is optional thanks to hstring's conversion operator to 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"

同樣地,IStringable::ToString 傳回 hstring。Similarly, IStringable::ToString returns hstring.

public:
    hstring ToString() const;

Uri 實作 IStringable 介面。Uri implements the IStringable interface.

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

您可以使用 hstring::c_str 函式 以從 hstring 取得標準寬字串 (就像您可以從 std::wstring 一樣)。You can use the hstring::c_str function to get a standard wide string from an hstring (just as you can from a std::wstring).

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

如果您有 hstring,然後您可以從其製作 UriIf you have an hstring then you can make a Uri from it.

Uri awUriFromHstring{ tostringHstring };

請考慮採用 hstring 的方法。Consider a method that takes an hstring.

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

所有您方才看到的選項也適用於此類案例。All of the options you've just seen also apply in such cases.

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

hstring 有一個成員 std::wstring_view 轉換運算子,而且可以免費進行轉換。hstring has a member std::wstring_view conversion operator, and the conversion is achieved at no cost.

void legacy_print(std::wstring_view view);

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

winrt::hstring 函式和運算子winrt::hstring functions and operators

winrt::hstring 實作許多建構函式、運算子、函式和迭代器。A host of constructors, operators, functions, and iterators are implemented for winrt::hstring.

hstring 是一個範圍,讓您可以與範圍架構的 for 或與 std::for_each 搭配使用。An hstring is a range, so you can use it with range-based for, or with std::for_each. 它也提供比較運算子,可以自然且有效率地與 C++ 標準程式庫中的對應項目進行比較。It also provides comparison operators for naturally and efficiently comparing against its counterparts in the C++ Standard Library. 而且它包含您使用 hstring 做為關聯容器之金鑰所需的所有項目。And it includes everything you need to use hstring as a key for associative containers.

我們了解,許多 C++ 程式庫使用 std::string,以及單獨搭配 UTF-8 文字。We recognize that many C++ libraries use std::string, and work exclusively with UTF-8 text. 為了方便起見,我們提供可向前與向後轉換的協助程式,例如 winrt::to_stringwinrt::to_hstringAs a convenience, we provide helpers, such as winrt::to_string and winrt::to_hstring, for converting back and forth.

WINRT_ASSERT 是巨集定義,而且會發展為 _ASSERTEWINRT_ASSERT is a macro definition, and it expands to _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!");

如需有關 hstring 函式和運算子的詳細範例與資訊,請參閱 winrt::hstring API 參考主題。For more examples and info about hstring functions and operators, see the winrt::hstring API reference topic.

winrt::hstringwinrt::param::hstring 的原理The rationale for winrt::hstring and winrt::param::hstring

wchar_t 字元實作 Windows 執行階段,但 Windows 執行階段的應用程式二進位介面 (ABI) 不是 std::wstringstd::wstring_view 提供的子集。The Windows Runtime is implemented in terms of wchar_t characters, but the Windows Runtime's Application Binary Interface (ABI) is not a subset of what either std::wstring or std::wstring_view provide. 使用這些會導致嚴重的效率不彰。Using those would lead to significant inefficiency. 反之,C++/WinRT 提供 winrt::hstring,用來表示與基礎 HSTRING 一致的不可變更字串,且在類似於 std::wstring 的介面後面實作。Instead, C++/WinRT provides winrt::hstring, which represents an immutable string consistent with the underlying HSTRING, and implemented behind an interface similar to that of std::wstring.

您可能會注意到, 邏輯上應該接受 winrt::hstring 的 C++/ WinRT 輸入參數,實際預期為 winrt::param::hstringYou may notice that C++/WinRT input parameters that should logically accept winrt::hstring actually expect winrt::param::hstring. param 命名空間包含一組專門用於最佳化輸入參數的類型,以自然繫結至 C++ 標準程式庫類型,並避免複製及其它效率不彰。The param namespace contains a set of types used exclusively to optimize input parameters to naturally bind to C++ Standard Library types and avoid copies and other inefficiencies. 您不應該直接使用這些類型。You shouldn't use these types directly. 如果要對自己的函式使用最佳化,請使用 std::wstring_viewIf you want to use an optimization for your own functions then use std::wstring_view. 另請參閱將參數傳入 ABI 界限Also see Passing parameters into the ABI boundary.

結論是您可以大致忽略特定的 Windows 執行階段字串管理,並只搭配使用您知道的效率。The upshot is that you can largely ignore the specifics of Windows Runtime string management, and just work with efficiency with what you know. 了解在 Windows 執行階段中重度使用字串的程度,這一點很重要。And that's important, given how heavily strings are used in the Windows Runtime.

格式化字串Formatting strings

字串格式化的一個選項是 std::wostringstreamOne option for string-formatting is std::wostringstream. 以下是格式與顯示簡單偵錯追蹤訊息的範例。Here's an example that formats and displays a simple debug trace message.

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

設定屬性的正確方式The correct way to set a property

您可以藉由將值傳遞至 setter 函式來設定屬性。You set a property by passing a value to a setter function. 以下是範例。Here's an example.

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

下列是不正確的程式碼。The code below is incorrect. 其會進行編譯,但只是修改由 Text() 存取子函式傳回的暫存 winrt::hstring,然後捨棄結果。It compiles, but all it does is to modify the temporary winrt::hstring returned by the Text() accessor function, and then to throw the result away.

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

重要 APIImportant APIs