Strings (C++/CX)

Text in the Windows Runtime is represented in C++/CX by the Platform::String Class. Use the Platform::String Class when you pass strings back and forth to methods in Windows Runtime classes, or when you are interacting with other Windows Runtime components across the application binary interface (ABI) boundary. The Platform::String Class provides methods for several common string operations, but it's not designed to be a full-featured string class. In your C++ module, use standard C++ string types such as wstring for any significant text processing, and then convert the final result to Platform::String^ before you pass it to or from a public interface. It's easy and efficient to convert between wstring or wchar_t* and Platform::String.

Fast pass

In some cases, the compiler can verify that it can safely construct a Platform::String or pass a String to a function without copying the underlying string data. Such operations are known as fast pass and they occur transparently.

String construction

The value of a String object is an immutable (read-only) sequence of char16 (16-bit Unicode) characters. Because a String object is immutable, assignment of a new string literal to a String variable actually replaces the original String object with a new String object. Concatenation operations involve the destruction of the original String object and the creation of a new object.

Literals

A literal character is a character that's enclosed in single quotation marks, and a literal string is a sequence of characters that's enclosed in double quotation marks. If you use a literal to initialize a String^ variable, the compiler assumes that the literal consists of char16 characters. That is, you don't have to precede the literal with the 'L' string modifier or enclose the literal in a _T() or TEXT() macro. For more information about C++ support for Unicode, see Unicode Programming Summary.

The following example shows various ways to construct String objects.

// Initializing a String^ by using string literals
String^ str1 = "Test"; // ok for ANSI text only. uses current code page
String^ str2("Test");
String^ str3 = L"Test";
String^ str4(L"Test");


//Initialize a String^ by using another String^
String^ str6(str1);
auto str7 = str2;

// Initialize a String from wchar_t* and wstring
wchar_t msg[] = L"Test";
String^ str8 = ref new String(msg);
std::wstring wstr1(L"Test");
String^ str9 = ref new String(wstr1.c_str());
String^ str10 = ref new String(wstr1.c_str(), wstr1.length());

String handling operations

The String class provides methods and operators for concatenating, comparing strings, and other basic string operations. To perform more extensive string manipulations, use the String::Data() member function to retrieve the value of the String^ object as a const wchar_t*. Then use that value to initialize a std::wstring, which provides rich string handling functions.


 // Concatenation 
 auto str1 = "Hello" + " World";
 auto str2 = str1 + " from C++/CX!";    
 auto str3 = String::Concat(str2, " and the String class");
 
 // Comparison
 if (str1 == str2) { /* ... */ }
 if (str1->Equals(str2)) { /* ... */ }
 if (str1 != str2) { /* ... */ }
 if (str1 < str2 || str1 > str2) { /* ... */};
 int result = String::CompareOrdinal(str1, str2);
 
 if(str1 == nullptr) { /* ...*/};
 if(str1->IsEmpty()) { /* ...*/};

// Accessing individual characters in a String^
 auto it = str1->Begin();
 char16 ch = it[0];

String conversions

A Platform::String can contain only char16 characters, or the NULL character. If your application has to work with 8-bit characters, use the String::Data to extract the text as a const wchar_t*. You can then use the appropriate Windows functions or Standard Library functions to operate on the data and convert it back to a wchar_t* or wstring, which you can use to construct a new Platform::String.

The following code fragment shows how to convert a String^ variable to and from a wstring variable. For more information about the string manipulation that's used in this example, see basic_string::replace.

// Create a String^ variable statically or dynamically from a literal string. 
String^ str1 = "AAAAAAAA";

// Use the value of str1 to create the ws1 wstring variable.
std::wstring ws1( str1->Data() ); 
// The value of ws1 is L"AAAAAAAA".

// Manipulate the wstring value.
std::wstring replacement( L"BBB" );
ws1 = ws1.replace ( 1, 3, replacement );
// The value of ws1 is L"ABBBAAAA".

// Assign the modified wstring back to str1. 
str1 = ref new String( ws1.c_str() ); 

String length and embedded NULL values

The String::Length returns the number of characters in the string, not the number of bytes. The terminating NULL character is not counted unless you explicitly specify it when you use stack semantics to construct a string.

A Platform::String can contain embedded NULL values, but only when the NULL is a result of a concatenation operation. Embedded NULLs are not supported in string literals; therefore, you cannot use embedded NULLs in that manner to initialize a Platform::String. Embedded NULL values in a Platform::String are ignored when the string is displayed, for example, when it is assigned to a TextBlock::Text property. Embedded NULLs are removed when the string value is returned by the Data property.

StringReference

In some cases your code (a) receives a std::wstring, or wchar_t string or L"" string literal and just passes it on to another method that takes a String^ as input parameter. As long as the original string buffer itself remains valid and does not mutate before the function returns, you can convert the wchar_t* string or string literal to a Platform::StringReference, and pass in that instead of a Platform::String^. This is allowed because StringReference has a user-defined conversion to Platform::String^. By using StringReference you can avoid making an extra copy of the string data. In loops where you are passing large numbers of strings, or when passing very large strings, you can potentially achieve a significant performance improvement by using StringReference. But because StringReference essentially borrows the original string buffer, you must use extreme care to avoid memory corruption. You should not pass a StringReference to an asynchronous method unless the original string is guaranteed to be in scope when that method returns. A String^ that is initialized from a StringReference will force an allocation and copy of the string data if a second assignment operation occurs. In this case, you will lose the performance benefit of StringReference.

Note that StringReference is a standard C++ class type, not a ref class, you cannot use it in the public interface of ref classes that you define.

The following example shows how to use StringReference:

void GetDecodedStrings(std::vector<std::wstring> strings)
{
    using namespace Windows::Security::Cryptography;
    using namespace Windows::Storage::Streams;

    for (auto&& s : strings)
    {
        // Method signature is IBuffer^ CryptographicBuffer::DecodeFromBase64String (Platform::String^)
        // Call using StringReference:
        IBuffer^ buffer = CryptographicBuffer::DecodeFromBase64String(StringReference(s.c_str()));

        //...do something with buffer
    }
}