C++/CX에서 C++/WinRT로 이동Move to C++/WinRT from C++/CX

이 항목에서는 C++/CX 프로젝트의 코드를 C++/WinRT의 코드로 이식하는 방법을 보여 줍니다.This topic shows how to port the code in a C++/CX project to its equivalent in C++/WinRT.

이식 전략Porting strategies

C++/CX 코드를 C++/WinRT로 점진적으로 이식할 수 있습니다.If you want to gradually port your C++/CX code to C++/WinRT, then you can. C++/CX 및 C++/WinRT 코드는 같은 프로젝트에 공존할 수 있으며, XAML 컴파일러 지원 및 Windows 런타임 구성 요소의 예외가 있습니다.C++/CX and C++/WinRT code can coexist in the same project, with the exceptions of XAML compiler support and Windows Runtime components. 이 두 가지 예외를 위해 C++/CX 또는 C++/WinRT를 동일한 프로젝트 내에서 대상으로 지정해야 합니다.For those two exceptions, you'll need to target either C++/CX or C++/WinRT within the same project.

중요

프로젝트가 XAML 애플리케이션을 빌드하는 경우 권장하는 한 가지 워크플로는 먼저 C++/WinRT 프로젝트 템플릿 중 하나를 사용하여 Visual Studio에서 새 프로젝트를 만드는 것입니다(Visual Studio의 C++/WinRT 지원 참조).If your project builds a XAML application, then one workflow that we recommend is to first create a new project in Visual Studio using one of the C++/WinRT project templates (see Visual Studio support for C++/WinRT). 그런 다음, C++/CX 프로젝트에서 원본 코드 및 태그 복사를 시작합니다.Then, start copying source code and markup over from the C++/CX project. 프로젝트 > 새 항목 추가... > Visual C++ > 비어 있는 페이지(C++/WinRT) 를 사용하여 새 XAML 페이지를 추가할 수 있습니다.You can add new XAML pages with Project > Add New Item... > Visual C++ > Blank Page (C++/WinRT).

또는 Windows 런타임 구성 요소를 사용하여 이식할 때 XAML C++/CX 프로젝트에서 코드를 팩터링할 수 있습니다.Alternatively, you can use a Windows Runtime component to factor code out of the XAML C++/CX project as you port it. 최대한 많은 C++/CX 코드를 구성 요소로 이동한 다음, XAML 프로젝트를 C++/WinRT로 변경합니다.Either move as much C++/CX code as you can into a component, and then change the XAML project to C++/WinRT. 또는 XAML 프로젝트를 C++/CX로 남겨 두고, 새 C++/WinRT 구성 요소를 만들고, XAML 프로젝트에서 구성 요소로 C++/CX 코드 이식을 시작합니다.Or else leave the XAML project as C++/CX, create a new C++/WinRT component, and begin porting C++/CX code out of the XAML project and into the component. 또한 동일한 솔루션 내에 C++/WinRT 구성 요소 프로젝트와 함께 C++/CX 구성 요소 프로젝트를 포함하고, 애플리케이션 프로젝트에서 두 프로젝트를 모두 참조하고, 점진적으로 서로 이식할 수 있습니다.You could also have a C++/CX component project alongside a C++/WinRT component project within the same solution, reference both of them from your application project, and gradually port from one to the other. 동일한 프로젝트에서 두 언어 프로젝션을 사용하는 방법에 대한 자세한 내용은 C++/WinRT 및 C++/CX 사이의 Interop를 참조하세요.See Interop between C++/WinRT and C++/CX for more details on using the two language projections in the same project.

참고

C++/CX 및 Windows SDK는 둘 다 루트 네임스페이스인 Windows에서 형식을 선언합니다.Both C++/CX and the Windows SDK declare types in the root namespace Windows. C++/WinRT에 프로젝션된 Windows 형식은 Windows 형식과 동일한 정규화된 이름을 사용하지만 C++ winrt 네임스페이스에 배치됩니다.A Windows type projected into C++/WinRT has the same fully-qualified name as the Windows type, but it's placed in the C++ winrt namespace. 이렇게 네임스페이스를 구별하여 원하는 대로 C++/CX에서 C++/WinRT로 이식할 수 있습니다.These distinct namespaces let you port from C++/CX to C++/WinRT at your own pace.

위에 언급된 예외 사항을 고려하면서 C++/CX 프로젝트를 C++/WinRT로 이식하는 첫 번째 단계는 C++/WinRT 지원을 수동으로 추가하는 것입니다(Visual Studio의 C++/WinRT 지원 참조).Bearing in mind the exceptions mentioned above, the first step in porting a C++/CX project to C++/WinRT is to manually add C++/WinRT support to it (see Visual Studio support for C++/WinRT). 이 작업을 수행하려면 Microsoft.Windows.CppWinRT NuGet 패키지를 프로젝트에 설치합니다.To do that, install the Microsoft.Windows.CppWinRT NuGet package into your project. Visual Studio에서 프로젝트를 열고 프로젝트 > NuGet 패키지 관리... > 찾아보기를 클릭합니다. 검색 상자에 Microsoft.Windows.CppWinRT를 입력하거나 붙여넣고 검색 결과에서 항목을 선택한 다음, 설치를 클릭하여 해당 프로젝트용 패키지를 설치합니다.Open the project in Visual Studio, click Project > Manage NuGet Packages... > Browse, type or paste Microsoft.Windows.CppWinRT in the search box, select the item in search results, and then click Install to install the package for that project. 해당 변경의 효과 중 하나는 프로젝트에서 C++/CX에 대한 지원이 꺼진다는 것입니다.One effect of that change is that support for C++/CX is turned off in the project. 빌드 메시지가 C++/CX에서 모든 종속성을 찾고 이식하는 데 도움이 되도록 지원을 끈 채로 두는 것이 좋습니다. 또는 지원을 다시 켜고(프로젝트 속성에서 C/C++ > 일반 > Windows 런타임 확장 사용 > 예(/ZW) ) 점진적으로 이식할 수 있습니다.It's a good idea to leave support turned off so that build messages help you find (and port) all of your dependencies on C++/CX, or you can turn support back on (in project properties, C/C++ > General > Consume Windows Runtime Extension > Yes (/ZW)), and port gradually.

또는 Visual Studio의 C++/WinRT 프로젝트 속성 페이지를 사용하여 다음 속성을 .vcxproj 파일에 수동으로 추가합니다.Alternatively, manually add the following property to your .vcxproj file using the C++/WinRT project property page in Visual Studio. 비슷한 사용자 지정 옵션(cppwinrt.exe 도구의 동작을 미세 조정) 목록은 Microsoft.Windows.CppWinRT NuGet 패키지 추가 정보를 참조하세요.For a list of similar customization options (which fine-tune the behavior of the cppwinrt.exe tool), see the Microsoft.Windows.CppWinRT NuGet package readme.

<syntaxhighlight lang="xml">
  <PropertyGroup Label="Globals">
    <CppWinRTProjectLanguage>C++/CX</CppWinRTProjectLanguage>
  </PropertyGroup>
</syntaxhighlight>

다음으로, 일반 > 대상 플랫폼 버전의 프로젝트 속성이 10.0.17134.0(Windows 10 버전 1803) 이상으로 설정되었는지 확인합니다.Next, ensure that project property General > Target Platform Version is set to 10.0.17134.0 (Windows 10, version 1803) or greater.

미리 컴파일된 헤더 파일에(일반적으로 pch.h) winrt/base.h를 포함합니다.In your precompiled header file (usually pch.h), include winrt/base.h.

#include <winrt/base.h>

C++/WinRT 프로젝션된 Windows API 헤더를 포함하는 경우(예: winrt/Windows.Foundation.h) 자동으로 포함되기 때문에 명시적으로 이와 같은 winrt/base.h를 포함할 필요가 없습니다.If you include any C++/WinRT projected Windows API headers (for example, winrt/Windows.Foundation.h), then you don't need to explicitly include winrt/base.h like this because it will be included automatically for you.

프로젝트가 Windows 런타임 C++ 템플릿 라이브러리(WRL) 형식도 사용하는 경우 WRL에서 C++/WinRT로 이동을 참조하세요.If your project is also using Windows Runtime C++ Template Library (WRL) types, then see Move to C++/WinRT from WRL.

파일 명명 규칙File-naming conventions

XAML 태그 파일XAML markup files

C++/CXC++/CX C++/WinRTC++/WinRT
개발자 XAML 파일Developer XAML files MyPage.xamlMyPage.xaml
MyPage.xaml.hMyPage.xaml.h
MyPage.xaml.cppMyPage.xaml.cpp
MyPage.xamlMyPage.xaml
MyPage.hMyPage.h
MyPage.cppMyPage.cpp
MyPage.idl(아래 참조)MyPage.idl (see below)
생성된 XAML 파일Generated XAML files MyPage.xaml.g.hMyPage.xaml.g.h
MyPage.xaml.g.hppMyPage.xaml.g.hpp
MyPage.xaml.g.hMyPage.xaml.g.h
MyPage.xaml.g.hppMyPage.xaml.g.hpp
MyPage.g.hMyPage.g.h

C++/WinRT는 *.h*.cpp 파일 이름에서 .xaml을 제거합니다.Notice that C++/WinRT removes the .xaml from the *.h and *.cpp file names.

C++/WinRT는 추가 개발자 파일인 Midl 파일(.idl) 을 추가합니다.C++/WinRT adds an additional developer file, the Midl file (.idl). C++/CX는 이 파일을 내부적으로 자동 생성하여 모든 public 및 protected 멤버를 추가합니다.C++/CX autogenerates this file internally, adding to it every public and protected member. C++/WinRT에서는 파일을 직접 추가하고 작성합니다.In C++/WinRT, you add and author the file yourself. IDL 작성에 대한 자세한 내용, 코드 예제 및 연습은 XAML 컨트롤, C++/WinRT 속성에 바인딩을 참조하세요.For more details, code examples, and a walkthrough of authoring IDL, see XAML controls; bind to a C++/WinRT property.

또한 런타임 클래스를 Midl 파일(.idl)로 팩터링도 참조하세요.Also see Factoring runtime classes into Midl files (.idl)

런타임 클래스Runtime classes

C++/CX는 헤더 파일의 이름에 제한 사항을 적용하지 않습니다. 특히 작은 클래스의 경우 여러 런타임 클래스 정의를 단일 헤더 파일에 배치하는 것이 일반적입니다.C++/CX doesn't impose restrictions on the names of your header files; it's common to put multiple runtime class definitions into a single header file, especially for small classes. 그러나 C++/WinRT에서 각 런타임 클래스에는 클래스 이름 뒤에 명명된 고유한 헤더 파일이 있어야 합니다.But C++/WinRT requires that each runtime class has its own header file named after the class name.

C++/CXC++/CX C++/WinRTC++/WinRT
Common.hCommon.h
ref class A { ... }
ref class B { ... }
Common.idlCommon.idl
runtimeclass A { ... }
runtimeclass B { ... }
A.hA.h
namespace implements {
  struct A { ... };
}
B.hB.h
namespace implements {
  struct B { ... };
}

C++/CX에서 일반적이지 않지만 여전히 유효한 방법은 XAML 사용자 지정 컨트롤에 대해 다른 이름의 헤더 파일을 사용하는 것입니다.Less common (but still legal) in C++/CX is to use differently-named header files for XAML custom controls. 클래스 이름과 일치하도록 이러한 헤더 파일의 이름을 변경해야 합니다.You'll need to rename these header file to match the class name.

C++/CXC++/CX C++/WinRTC++/WinRT
A.xamlA.xaml
<Page x:Class="LongNameForA" ...>
A.xamlA.xaml
<Page x:Class="LongNameForA" ...>
A.hA.h
partial ref class LongNameForA { ... }
LongNameForA.hLongNameForA.h
namespace implements {
  struct LongNameForA { ... };
}

헤더 파일 요구 사항Header file requirements

C++/CX는 .winmd 파일의 헤더 파일을 내부적으로 자동 생성하므로 특별한 헤더 파일이 포함될 필요가 없습니다.C++/CX doesn't require you to include any special header files, because it internally autogenerates header files from .winmd files. C++/CX에서는 이름으로 사용하는 네임스페이스에 using 지시문을 사용하는 것이 일반적입니다.It's common in C++/CX to use using directives for namespaces that you consume by name.

using namespace Windows::Media::Playback;

String^ NameOfFirstVideoTrack(MediaPlaybackItem^ item)
{
    return item->VideoTracks->GetAt(0)->Name;
}

using namespace Windows::Media::Playback 지시문을 사용하면 네임스페이스 접두사 없이 MediaPlaybackItem을 작성할 수 있습니다.The using namespace Windows::Media::Playback directive lets us write MediaPlaybackItem without a namespace prefix. item->VideoTracks->GetAt(0)에서 Windows.Media.Core.VideoTrack을 반환하므로 Windows.Media.Core 네임스페이스도 수정했습니다.We also touched the Windows.Media.Core namespace, because item->VideoTracks->GetAt(0) returns a Windows.Media.Core.VideoTrack. 그러나 VideoTrack이라는 이름을 아무 곳에도 입력할 필요가 없으므로 using Windows.Media.Core 지시문이 필요하지 않았습니다.But we didn't have to type the name VideoTrack anywhere, so we didn't need a using Windows.Media.Core directive.

그러나 C++/WinRT에서는 이름을 지정하지 않더라도 사용하는 각 네임스페이스에 해당하는 헤더 파일을 포함시켜야 합니다.But C++/WinRT requires you to include a header file corresponding to each namespace that you consume, even if you don't name it.

#include <winrt/Windows.Media.Playback.h>
#include <winrt/Windows.Media.Core.h> // !!This is important!!

using namespace winrt;
using namespace Windows::Media::Playback;

winrt::hstring NameOfFirstVideoTrack(MediaPlaybackItem const& item)
{
    return item.VideoTracks().GetAt(0).Name();
}

반면, MediaPlaybackItem.AudioTracksChanged 이벤트가 TypedEventHandler<MediaPlaybackItem, Windows.Foundation.Collections.IVectorChangedEventArgs> 형식인 경우에도 해당 이벤트를 사용하지 않았으므로 winrt/Windows.Foundation.Collections.h를 포함할 필요가 없습니다.On the other hand, even though the MediaPlaybackItem.AudioTracksChanged event is of type TypedEventHandler<MediaPlaybackItem, Windows.Foundation.Collections.IVectorChangedEventArgs>, we don't need to include winrt/Windows.Foundation.Collections.h because we didn't use that event.

또한 C++/WinRT에서는 XAML 태그에서 사용되는 네임스페이스에 대한 헤더 파일을 포함해야 합니다.C++/WinRT also requires you to include header files for namespaces that are consumed by XAML markup.

<!-- MainPage.xaml -->
<Rectangle Height="400"/>

Rectangle 클래스를 사용하면 다음 include를 추가해야 합니다.Using the Rectangle class means that you have to add this include.

// MainPage.h
#include <winrt/Windows.UI.Xaml.Shapes.h>

헤더 파일을 잊어버린 경우 모든 것이 정상적으로 컴파일되지만 consume_ 클래스가 누락되어 링커 오류가 발생합니다.If you forget a header file, then everything will compile okay but you'll get linker errors because the consume_ classes are missing.

매개 변수 전달Parameter-passing

C++/CX 원본 코드를 작성할 때 C++/CX 형식을 hat(^) 참조로 함수 매개 변수로 전달합니다.When writing C++/CX source code, you pass C++/CX types as function parameters as hat (^) references.

void LogPresenceRecord(PresenceRecord^ record);

C++/WinRT에서 동기 함수를 위해 기본적으로 const& 매개 변수를 사용해야 합니다.In C++/WinRT, for synchronous functions, you should use const& parameters by default. 이를 통해 복사본과 연동된 오버헤드를 방지할 수 있습니다.That will avoid copies and interlocked overhead. 하지만 사용자 코루틴이 값으로 캡처하고 수명 문제를 방지할 수 있도록 값으로 전달을 사용해야 합니다(자세한 내용은 C++/WinRT 동시성 및 비동기 작업 참조).But your coroutines should use pass-by-value to ensure that they capture by value and avoid lifetime issues (for more details, see Concurrency and asynchronous operations with C++/WinRT).

void LogPresenceRecord(PresenceRecord const& record);
IASyncAction LogPresenceRecordAsync(PresenceRecord const record);

C++/WinRT 개체는 기본적으로 지원 Windows 런타임 개체에 대한 인터페이스 포인터를 보유하는 값입니다.A C++/WinRT object is fundamentally a value that holds an interface pointer to the backing Windows Runtime object. C++/WinRT 개체를 복사할 때 컴파일러는 캡슐화된 인터페이스 포인터를 복사하여 참조 횟수가 증가합니다.When you copy a C++/WinRT object, the compiler copies the encapsulated interface pointer, incrementing its reference count. 복사의 최종 소멸은 감소 참조 수를 포함합니다.Eventual destruction of the copy involves decrementing the reference count. 따라서 필요한 경우에만 오버헤드가 복사됩니다.So, only incur the overhead of a copy when necessary.

변수 및 필드 참조Variable and field references

C++/CX 원본 코드를 작성할 때 hat(^) 변수를 사용하여 Windows 런타임 개체를 참조하고, 화살표(->) 연산자를 사용하여 hat 변수를 역참조합니다.When writing C++/CX source code, you use hat (^) variables to reference Windows Runtime objects, and the arrow (->) operator to dereference a hat variable.

IVectorView<User^>^ userList = User::Users;

if (userList != nullptr)
{
    for (UINT32 iUser = 0; iUser < userList->Size; ++iUser)
    ...

해당 C++/WinRT 코드에 이식할 때 먼저 hat을 제거하고 화살표 연산자(->)를 점 연산자(.)로 변경합니다.When porting to the equivalent C++/WinRT code, you can get a long way by removing the hats, and changing the arrow operator (->) to the dot operator (.). C++/WinRT 프로젝션된 형식은 포인터가 아니라 값입니다.C++/WinRT projected types are values, and not pointers.

IVectorView<User> userList = User::Users();

if (userList != nullptr)
{
    for (UINT32 iUser = 0; iUser < userList.Size(); ++iUser)
    ...

C++/CX hat 참조의 기본 생성자는 이 형식을 null로 초기화합니다.The default constructor for a C++/CX hat reference initializes it to null. 다음은 올바른 형식이지만 초기화되지 않는 변수/필드를 만드는 C++/CX 코드 예제입니다.Here's a C++/CX code example in which we create a variable/field of the correct type, but one that's uninitialized. 즉, 초기에 TextBlock을 참조하지 않으며, 나중에 참조를 할당하려고 합니다.In other words, it doesn't initially refer to a TextBlock; we intend to assign a reference later.

TextBlock^ textBlock;

class MyClass
{
    TextBlock^ textBlock;
};

C++/WinRT의 해당 형식에 대해서는 지연된 초기화를 참조하세요.For the equivalent in C++/WinRT, see Delayed initialization.

속성Properties

C++/CX 언어 확장은 속성의 개념을 포함합니다.The C++/CX language extensions include the concept of properties. C++/CX 원본 코드를 작성할 때 필드처럼 속성에 액세스할 수 있습니다.When writing C++/CX source code, you can access a property as if it were a field. 표준 C++는 속성의 개념을 가지지 않으므로 C++/WinRT에서 get 및 set 함수를 호출합니다.Standard C++ does not have the concept of a property so, in C++/WinRT, you call get and set functions.

다음 예제에서 XboxUserId, UserState, PresenceDeviceRecordsSize는 모두 속성입니다.In the examples that follow, XboxUserId, UserState, PresenceDeviceRecords, and Size are all properties.

속성에서 값 검색Retrieving a value from a property

여기서 C++/CX에서 속성 값을 가져오는 방법을 설명합니다.Here's how you get a property value in C++/CX.

void Sample::LogPresenceRecord(PresenceRecord^ record)
{
    auto id = record->XboxUserId;
    auto state = record->UserState;
    auto size = record->PresenceDeviceRecords->Size;
}

해당 C++/WinRT 원본 코드는 매개 변수 없이 속성과 동일한 이름의 함수를 호출합니다.The equivalent C++/WinRT source code calls a function with the same name as the property, but with no parameters.

void Sample::LogPresenceRecord(PresenceRecord const& record)
{
    auto id = record.XboxUserId();
    auto state = record.UserState();
    auto size = record.PresenceDeviceRecords().Size();
}

PresenceDeviceRecords 함수는 자체에 Size 함수를 가지는 Windows 런타임 개체를 반환합니다.Note that the PresenceDeviceRecords function returns a Windows Runtime object that itself has a Size function. 반환된 개체가 C++/WinRT 프로젝션된 형식이기도 하므로 점 연산자를 사용하여 역참조하여 Size를 호출합니다.As the returned object is also a C++/WinRT projected type, we dereference using the dot operator to call Size.

속성을 새 값으로 설정Setting a property to a new value

속성을 새 값으로 설정하는 것은 비슷한 패턴을 따릅니다.Setting a property to a new value follows a similar pattern. 먼저 C++/CX의 경우 다음과 같습니다.First, in C++/CX.

record->UserState = newValue;

C++/WinRT에서 해당하는 작업을 수행하려면, 속성과 동일한 이름으로 함수를 호출하고 인수를 전달합니다.To do the equivalent in C++/WinRT, you call a function with the same name as the property, and pass an argument.

record.UserState(newValue);

클래스 인스턴스 만들기Creating an instance of a class

일반적으로 hat(^) 참조로 알려진 이에 대한 핸들을 통해 C++/CX 개체를 작업합니다.You work with a C++/CX object via a handle to it, commonly known as a hat (^) reference. ref new 키워드를 통해 새로운 개체를 만들면 RoActivateInstance를 호출하여 런타임 클래스의 새로운 인스턴스를 활성화합니다.You create a new object via the ref new keyword, which in turn calls RoActivateInstance to activate a new instance of the runtime class.

using namespace Windows::Storage::Streams;

class Sample
{
private:
    Buffer^ m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
};

C++/WinRT 개체는 값입니다. 따라서 스택에 또는 개체의 필드로 이를 할당할 수 있습니다.A C++/WinRT object is a value; so you can allocate it on the stack, or as a field of an object. C++/WinRT 개체를 할당하기 위해 ‘절대’ ref new(또는 new)를 사용해서는 안 됩니다. You never use ref new (nor new) to allocate a C++/WinRT object. 백그라운드에서 RoActivateInstance는 여전히 호출되고 있습니다.Behind the scenes, RoActivateInstance is still being called.

using namespace winrt::Windows::Storage::Streams;

struct Sample
{
private:
    Buffer m_gamerPicBuffer{ MAX_IMAGE_SIZE };
};

리소스가 초기화하기에 비싼 경우 초기화가 실제로 필요할 때까지 초기화를 지연하는 것이 일반적입니다.If a resource is expensive to initialize, then it's common to delay initialization of it until it's actually needed. 이미 언급한 대로 C++/CX hat 참조의 기본 생성자는 이를 null로 초기화합니다.As already mentioned, the default constructor for a C++/CX hat reference initializes it to null.

using namespace Windows::Storage::Streams;

class Sample
{
public:
    void DelayedInit()
    {
        // Allocate the actual buffer.
        m_gamerPicBuffer = ref new Buffer(MAX_IMAGE_SIZE);
    }

private:
    Buffer^ m_gamerPicBuffer;
};

C++/WinRT로 이식된 동일한 코드.The same code ported to C++/WinRT. std::nullptr_t 생성자 사용에 유의하세요.Note the use of the std::nullptr_t constructor. 해당 생성자에 대한 자세한 내용은 지연된 초기화를 참조하세요.For more info about that constructor, see Delayed initialization.

using namespace winrt::Windows::Storage::Streams;

struct Sample
{
    void DelayedInit()
    {
        // Allocate the actual buffer.
        m_gamerPicBuffer = Buffer(MAX_IMAGE_SIZE);
    }

private:
    Buffer m_gamerPicBuffer{ nullptr };
};

기본 생성자가 컬렉션에 미치는 영향How the default constructor affects collections

C++ 컬렉션 형식은 기본 생성자를 사용하므로 의도하지 않은 개체가 생성될 수 있습니다.C++ collection types use the default constructor, which can result in unintended object construction.

시나리오Scenario C++/CXC++/CX C++/WinRT(잘못됨)C++/WinRT (incorrect) C++/WinRT(올바름)C++/WinRT (correct)
로컬 변수, 처음에는 비어 있음Local variable, initially empty TextBox^ textBox; TextBox textBox; // Creates a TextBox! TextBox textBox{ nullptr };
멤버 변수, 처음에는 비어 있음Member variable, initially empty class C {
  TextBox^ textBox;
};
class C {
  TextBox textBox; // Creates a TextBox!
};
class C {
  TextBox textbox{ nullptr };
};
글로벌 변수, 처음에는 비어 있음Global variable, initially empty TextBox^ g_textBox; TextBox g_textBox; // Creates a TextBox! TextBox g_textBox{ nullptr };
빈 참조의 벡터Vector of empty references std::vector<TextBox^> boxes(10); // Creates 10 TextBox objects!
std::vector<TextBox> boxes(10);
std::vector<TextBox> boxes(10, nullptr);
맵에 값 설정Set a value in a map std::map<int, TextBox^> boxes;
boxes[2] = value;
std::map<int, TextBox> boxes;
// Creates a TextBox at 2,
// then overwrites it!
boxes[2] = value;
std::map<int, TextBox> boxes;
boxes.insert_or_assign(2, value);
빈 참조의 배열Array of empty references TextBox^ boxes[2]; // Creates 2 TextBox objects!
TextBox boxes[2];
TextBox boxes[2] = { nullptr, nullptr };
페어링Pair std::pair<TextBox^, String^> p; // Creates a TextBox!
std::pair<TextBox, String> p;
std::pair<TextBox, String> p{ nullptr, nullptr };

빈 참조의 배열을 만드는 것은 간단하지 않습니다.There's no shorthand for creating an array of empty references. 배열의 각 요소에 대해 nullptr을 반복해야 합니다.You have to repeat nullptr for each element in the array. 너무 작으면 여분의 항목이 기본적으로 생성됩니다.If you have too few, then the extras will be default-constructed.

std::map 예제에 대한 자세한 정보More about the std::map example

std::map에 대한 [] 첨자 연산자는 다음과 같이 작동합니다.The [] subscript operator for std::map behaves like this.

  • 맵에 키가 있는 경우 기존 값(덮어쓸 수 있음)에 대한 참조를 반환합니다.If the key is found in the map, return a reference to the existing value (which you can overwrite).
  • 맵에 키가 없는 경우 키(이동 가능한 경우 이동됨)와 기본 생성 값으로 구성된 새 항목을 맵에 만들고 해당 값에 대한 참조를 반환합니다(이 경우 덮어쓸 수 있음).If the key isn't found in the map, then create a new entry in the map consisting of the key (moved, if movable) and a default-constructed value, and return a reference to the value (which you can then overwrite).

[] 연산자는 항상 항목을 맵에 만듭니다.In other words, the [] operator always creates an entry in the map. 이는 C#, Java 및 JavaScript와 다릅니다.This is different from C#, Java, and JavaScript.

기본 런타임 클래스에서 파생된 항목 클래스로 변환Converting from a base runtime class to a derived one

파생된 형식의 개체를 참조하는 기본에 대한 참조를 포함하는 것이 일반적입니다.It's common to have a reference-to-base that you know refers to an object of a derived type. C++/CX에서는 dynamic_cast를 사용하여 기본에 대한 참조를 파생에 대한 참조로 ‘캐스팅’합니다. In C++/CX, you use dynamic_cast to cast the reference-to-base into a reference-to-derived. dynamic_cast는 실제로 QueryInterface에 대한 숨겨진 호출입니다.The dynamic_cast is really just a hidden call to QueryInterface. 다음은 종속성 속성 변경 이벤트를 처리하며 DependencyObject에서 다시 종속성 속성을 소유하는 실제 형식으로 캐스팅하려는 일반적인 예제입니다.Here's a typical example—you're handling a dependency property changed event, and you want to cast from DependencyObject back to the actual type that owns the dependency property.

void BgLabelControl::OnLabelChanged(Windows::UI::Xaml::DependencyObject^ d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs^ e)
{
    BgLabelControl^ theControl{ dynamic_cast<BgLabelControl^>(d) };

    if (theControl != nullptr)
    {
        // succeeded ...
    }
}

해당하는 C++/WinRT 코드는 dynamic_castIUnknown::try_as 함수 호출(QueryInterface를 캡슐화함)로 바꿉니다.The equivalent C++/WinRT code replaces the dynamic_cast with a call to the IUnknown::try_as function, which encapsulates QueryInterface. 필수 인터페이스(요청하는 형식의 기본 인터페이스)에 대한 쿼리가 반환되지 않는 경우 대신에 예외를 throw하는 IUnknown::as를 호출하는 옵션도 있습니다.You also have the option to call IUnknown::as, instead, which throws an exception if querying for the required interface (the default interface of the type you're requesting) is not returned. 다음은 C++/WinRT 코드 예제입니다.Here's a C++/WinRT code example.

void BgLabelControl::OnLabelChanged(Windows::UI::Xaml::DependencyObject const& d, Windows::UI::Xaml::DependencyPropertyChangedEventArgs const& e)
{
    if (BgLabelControlApp::BgLabelControl theControl{ d.try_as<BgLabelControlApp::BgLabelControl>() })
    {
        // succeeded ...
    }

    try
    {
        BgLabelControlApp::BgLabelControl theControl{ d.as<BgLabelControlApp::BgLabelControl>() };
        // succeeded ...
    }
    catch (winrt::hresult_no_interface const&)
    {
        // failed ...
    }
}

파생 클래스Derived classes

런타임 클래스에서 파생하려면 기본 클래스를 구성할 수 있어야 합니다.In order to derive from a runtime class, the base class must be composable. C++/CX에서는 클래스를 구성할 수 있게 하는 특별한 단계를 수행할 필요가 없지만, C++/WinRT는 이를 수행합니다.C++/CX doesn't require that you take any special steps to make your classes composable, but C++/WinRT does. unsealed 키워드를 사용하여 클래스를 기본 클래스로 사용할 수 있도록 지정합니다.You use the unsealed keyword to indicate that you want your class to be usable as a base class.

unsealed runtimeclass BasePage : Windows.UI.Xaml.Controls.Page
{
    ...
}
runtimeclass DerivedPage : BasePage
{
    ...
}

구현 헤더 클래스에서 먼저 기본 클래스 헤더 파일을 포함해야 파생 클래스에 대해 자동 생성된 헤더를 포함할 수 있습니다.In your implementation header class, you must include the base class header file before you include the autogenerated header for the derived class. 그렇지 않으면 "이 형식을 식으로 잘못 사용했습니다"와 같은 오류가 발생합니다.Otherwise you'll get errors such as "Illegal use of this type as an expression".

// DerivedPage.h
#include "BasePage.h"       // This comes first.
#include "DerivedPage.g.h"  // Otherwise this header file will produce an error.

namespace winrt::MyNamespace::implementation
{
    struct DerivedPage : DerivedPageT<DerivedPage>
    {
        ...
    }
}

대리자로 이벤트 처리Event-handling with a delegate

여기에 람다 함수를 대리자로 사용하여 C++/CX에서 이벤트를 처리하는 일반적인 예제가 나와 있습니다.Here's a typical example of handling an event in C++/CX, using a lambda function as a delegate in this case.

auto token = myButton->Click += ref new RoutedEventHandler([=](Platform::Object^ sender, RoutedEventArgs^ args)
{
    // Handle the event.
    // Note: locals are captured by value, not reference, since this handler is delayed.
});

C++/WinRT에서와 동일합니다.This is the equivalent in C++/WinRT.

auto token = myButton().Click([=](IInspectable const& sender, RoutedEventArgs const& args)
{
    // Handle the event.
    // Note: locals are captured by value, not reference, since this handler is delayed.
});

람다 함수 대신 대리자를 자유 함수 또는 멤버 포인터 함수로 구현할 수 있습니다.Instead of a lambda function, you can choose to implement your delegate as a free function, or as a pointer-to-member-function. 자세한 내용은 C++/WinRT의 대리자를 사용한 이벤트 처리를 참조하세요.For more info, see Handle events by using delegates in C++/WinRT.

이벤트 및 대리자가 내부적으로 사용되는(이진 전체에서가 아니라) C++/CX 코드베이스에서 이식하는 경우 winrt::delegate는 C++/WinRT에서 해당 패턴을 복제하는 데 도움이 됩니다.If you're porting from a C++/CX codebase where events and delegates are used internally (not across binaries), then winrt::delegate will help you to replicate that pattern in C++/WinRT. 프로젝트 내의 매개 변수가 있는 대리자, 단순 신호 및 콜백을 참조하세요.Also see Parameterized delegates, simple signals, and callbacks within a project.

대리자 취소Revoking a delegate

C++/CX에서-= 연산자를 사용하여 이전 이벤트 등록을 취소합니다.In C++/CX you use the -= operator to revoke a prior event registration.

myButton->Click -= token;

C++/WinRT에서와 동일합니다.This is the equivalent in C++/WinRT.

myButton().Click(token);

자세한 내용과 옵션은 등록된 대리자 취소를 참조하세요.For more info and options, see Revoke a registered delegate.

boxing 및 unboxingBoxing and unboxing

C++/CX는 자동으로 스칼라를 개체에 boxing합니다.C++/CX automatically boxes scalars into objects. C++/WinRT에서는 winrt::box_value 함수를 명시적으로 호출해야 합니다.C++/WinRT requires you to call the winrt::box_value function explicitly. 두 언어에서 모두 명시적으로 unboxing해야 합니다.Both languages require you to unbox explicitly. C++/WinRT를 사용하여 boxing 및 unboxing을 참조하세요.See Boxing and unboxing with C++/WinRT.

다음 표에서는 이러한 정의를 사용합니다.In the tables that follows, we'll use these definitions.

C++/CXC++/CX C++/WinRTC++/WinRT
int i; int i;
String^ s; winrt::hstring s;
Object^ o; IInspectable o;
작업Operation C++/CXC++/CX C++/WinRTC++/WinRT
boxingBoxing o = 1;
o = "string";
o = box_value(1);
o = box_value(L"string");
unboxingUnboxing i = (int)o;
s = (String^)o;
i = unbox_value<int>(o);
s = unbox_value<winrt::hstring>(o);

C++/CX 및 C#에서는 값 형식에 대한 null 포인터를 unboxing하려고 하면 예외가 발생합니다.C++/CX and C# raise exceptions if you try to unbox a null pointer to a value type. C++/WinRT는 이를 프로그래밍 오류로 간주하여 작동이 중단됩니다.C++/WinRT considers this a programming error, and it crashes. C++/WinRT에서 개체가 예상한 형식이 아닌 경우를 처리하려면 winrt::unbox_value_or 함수를 사용합니다.In C++/WinRT, use the winrt::unbox_value_or function if you want to handle the case where the object is not of the type that you thought it was.

시나리오Scenario C++/CXC++/CX C++/WinRTC++/WinRT
알려진 정수 unboxingUnbox a known integer i = (int)o; i = unbox_value<int>(o);
o가 null인 경우If o is null Platform::NullReferenceException 작동 중단Crash
o가 boxing된 정수가 아닌 경우If o is not a boxed int Platform::InvalidCastException 작동 중단Crash
정수 unboxing, null인 경우 대체 사용, 다른 항목이 있는 경우 작동 중단Unbox int, use fallback if null; crash if anything else i = o ? (int)o : fallback; i = o ? unbox_value<int>(o) : fallback;
가능한 경우 정수 unboxing, 다른 항목이 있는 경우 대체 사용Unbox int if possible; use fallback for anything else auto box = dynamic_cast<IBox<int>^>(o);
i = box ? box->Value : fallback;
i = unbox_value_or<int>(o, fallback);

문자열 boxing 및 unboxingBoxing and unboxing a string

문자열은 어떤 방식에서는 값 형식이고, 다른 방식에서는 참조 형식입니다.A string is in some ways a value type, and in other ways a reference type. C++/CX 및 C++/WinRT는 문자열을 다르게 처리합니다.C++/CX and C++/WinRT treat strings differently.

HSTRING ABI 형식은 참조 횟수가 계산되는 문자열에 대한 포인터입니다.The ABI type HSTRING is a pointer to a reference-counted string. 그러나 IInspectable에서 파생되지 않으므로 기술적으로는 개체가 아닙니다.But it doesn't derive from IInspectable, so it's not technically an object. 또한 null HSTRING은 빈 문자열을 나타냅니다.Furthermore, a null HSTRING represents the empty string. IInspectable에서 파생되지 않은 것에 대한 boxing은 IReference<T> 안에 래핑하여 수행되며, Windows 런타임에서 표준 구현을 PropertyValue 개체 형식으로 제공합니다(사용자 지정 형식은 PropertyType::OtherType으로 보고됨).Boxing of things not derived from IInspectable is done by wrapping them inside an IReference<T>, and the Windows Runtime provides a standard implementation in the form of the PropertyValue object (custom types are reported as PropertyType::OtherType).

C++/CX는 Windows 런타임 문자열을 참조 형식으로 나타내는 반면, C++/WinRT는 문자열을 값 형식으로 프로젝션합니다.C++/CX represents a Windows Runtime string as a reference type; while C++/WinRT projects a string as a value type. 즉, boxing된 null 문자열은 해당 문자열을 가져온 방식에 따라 다르게 표현될 수 있습니다.This means that a boxed null string can have different representations depending how you got there.

또한 C++/CX를 사용하면 null String^ 을 역참조할 수 있으며, 이 경우 "" 문자열처럼 작동합니다.Furthermore, C++/CX allows you to dereference a null String^, in which case it behaves like the string "".

작업Operation C++/CXC++/CX C++/WinRTC++/WinRT
문자열 형식 범주String type category 참조 형식Reference type 값 유형Value type
null HSTRING에서 프로젝션하는 형식null HSTRING projects as (String^)nullptr hstring{}
null 및 ""가 동일한가요?Are null and "" identical? Yes Yes
null의 유효성Validity of null s = nullptr;
s->Length == 0(유효)s->Length == 0 (valid)
s = nullptr;
s.size() == 0(유효)s.size() == 0 (valid)
문자열 boxingBox a string o = s; o = box_value(s);
snull인 경우If s is null o = (String^)nullptr;
o == nullptr
o = box_value(hstring{});
o != nullptr
s""인 경우If s is "" o = "";
o == nullptr
o = box_value(hstring{L""});
o != nullptr;
null을 유지하는 문자열 boxingBox a string preserving null o = s; o = s.empty() ? nullptr : box_value(s);
문자열 강제 boxingForce-box a string o = PropertyValue::CreateString(s); o = box_value(s);
알려진 문자열 unboxingUnbox a known string s = (String^)o; s = unbox_value<hstring>(o);
o가 null인 경우If o is null s == nullptr; // equivalent to "" 작동 중단Crash
o가 boxing된 문자열이 아닌 경우If o is not a boxed string Platform::InvalidCastException 작동 중단Crash
문자열 unboxing, null인 경우 대체 사용, 다른 항목이 있는 경우 작동 중단Unbox string, use fallback if null; crash if anything else s = o ? (String^)o : fallback; s = o ? unbox_value<hstring>(o) : fallback;
가능한 경우 문자열 unboxing, 다른 항목이 있는 경우 대체 사용Unbox string if possible; use fallback for anything else auto box = dynamic_cast<IBox<String^>^>(o);
s = box ? box->Value : fallback;
s = unbox_value_or<hstring>(o, fallback);

위에 있는 두 개의 대체 사용 unboxing의 경우에서는 null 문자열이 강제 boxing되었을 수 있으며, 이 경우 대체가 사용되지 않습니다.In the two unbox with fallback cases above, it's possible that a null string was force-boxed, in which case the fallback won't be used. 결과 값은 boxing된 문자열이므로 빈 문자열이 됩니다.The resulting value will be an empty string because that is what was in the box.

동시성 및 비동기 작업Concurrency and asynchronous operations

PPL(병렬 패턴 라이브러리)(예: concurrency::task)이 C++/CX hat 참조를 지원하도록 업데이트되었습니다.The Parallel Patterns Library (PPL) (concurrency::task, for example) was updated to support C++/CX hat references.

C++/WinRT의 경우 코루틴과 co_await를 대신 사용해야 합니다.For C++/WinRT, you should use coroutines and co_await instead. 자세한 내용과 코드 예제는 C++/WinRT로 동시성 및 비동기 작업을 참조하세요.For more info, and code examples, see Concurrency and asynchronous operations with C++/WinRT.

XAML 태그에서 개체 사용Consuming objects from XAML markup

C++/CX 프로젝트에서는 XAML 태그에서 프라이빗 멤버 및 명명된 요소를 사용할 수 있습니다.In a C++/CX project, you can consume private members and named elements from XAML markup. 그러나 C++/WinRT에서 XAML {x:Bind} 태그 확장을 통해 사용되는 모든 엔터티는 IDL에 공개적으로 노출되어야 합니다.But in C++/WinRT, all entities consumed by using the XAML {x:Bind} markup extension must be exposed publicly in IDL.

또한 부울에 바인딩하면 C++/CX에서 true 또는 false가 표시되지만, C++/WinRT에서는 Windows.Foundation.IReference`1<Boolean> 이 표시됩니다.Also, binding to a Boolean displays true or false in C++/CX, but it shows Windows.Foundation.IReference`1<Boolean> in C++/WinRT.

자세한 내용과 코드 예제는 태그에서 개체 사용을 참조하세요.For more info, and code examples, see Consuming objects from markup.

C++/WinRT 형식에 C++/CX Platform 형식 매핑Mapping C++/CX Platform types to C++/WinRT types

C++/CX는 Platform 네임스페이스에서 몇 가지 데이터 형식을 제공합니다.C++/CX provides several data types in the Platform namespace. 이 형식은 표준 C++가 아니므로 Windows 런타임 언어 확장을 활성화한 경우에만 이를 사용할 수 있습니다(Visual Studio 프로젝트 속성 C/C++ > 일반 > Windows 런타임 확장 사용 > 예(/ZW) ).These types are not standard C++, so you can only use them when you enable Windows Runtime language extensions (Visual Studio project property C/C++ > General > Consume Windows Runtime Extension > Yes (/ZW)). 아래 표는 Platform 형식에서 C++/WinRT의 해당 형식으로 이식하는 데 도움이 됩니다.The table below helps you port from Platform types to their equivalents in C++/WinRT. 이를 수행하면 C++/WinRT가 표준 C++이이기 때문에 /ZW 옵션을 끌 수 있습니다.Once you've done that, since C++/WinRT is standard C++, you can turn off the /ZW option.

C++/CXC++/CX C++/WinRTC++/WinRT
Platform::Agile^Platform::Agile^ winrt::agile_refwinrt::agile_ref
Platform::Array^Platform::Array^ Platform::Array^ 이식 참조See Port Platform::Array^
Platform::Exception^Platform::Exception^ winrt::hresult_errorwinrt::hresult_error
Platform::InvalidArgumentException^Platform::InvalidArgumentException^ winrt::hresult_invalid_argumentwinrt::hresult_invalid_argument
Platform::Object^Platform::Object^ winrt::Windows::Foundation::IInspectablewinrt::Windows::Foundation::IInspectable
Platform::String^Platform::String^ winrt::hstringwinrt::hstring

Platform::Agile^winrt::agile_ref로 이식Port Platform::Agile^ to winrt::agile_ref

C++/CX의 Platform::Agile^ 형식은 스레드에서 액세스할 수 있는 Windows 런타임 클래스를 나타냅니다.The Platform::Agile^ type in C++/CX represents a Windows Runtime class that can be accessed from any thread. C++/WinRT의 해당 항목은 winrt::agile_ref입니다.The C++/WinRT equivalent is winrt::agile_ref.

C++/CX에서.In C++/CX.

Platform::Agile<Windows::UI::Core::CoreWindow> m_window;

C++/WinRT에서.In C++/WinRT.

winrt::agile_ref<Windows::UI::Core::CoreWindow> m_window;

Platform::Array^ 이식Port Platform::Array^

옵션에는 이니셜라이저 목록, std::array 또는 std::vector 사용이 포함됩니다.Your options include using an initializer list, a std::array, or a std::vector. 자세한 내용과 코드 예제는 표준 이니셜라이저 목록표준 배열 및 벡터를 참조하세요.For more info, and code examples, see Standard initializer lists and Standard arrays and vectors.

Platform::Exception^winrt::hresult_error로 이식Port Platform::Exception^ to winrt::hresult_error

Windows 런타임 API가 S_OK HRESULT가 아닌 값을 반환하면 Platform::Exception^ 형식이 C++/CX에서 생성됩니다.The Platform::Exception^ type is produced in C++/CX when a Windows Runtime API returns a non S_OK HRESULT. C++/WinRT의 해당 항목은 winrt::hresult_error입니다.The C++/WinRT equivalent is winrt::hresult_error.

C++/WinRT로 이식하려면 Platform::Exception^ 을 사용하는 모든 코드를 winrt::hresult_error를 사용하도록 변경합니다.To port to C++/WinRT, change all code that uses Platform::Exception^ to use winrt::hresult_error.

C++/CX에서.In C++/CX.

catch (Platform::Exception^ ex)

C++/WinRT에서.In C++/WinRT.

catch (winrt::hresult_error const& ex)

C++/WinRT는 이 예외 클래스를 제공합니다.C++/WinRT provides these exception classes.

예외 유형Exception type 기본 클래스Base class HRESULTHRESULT
winrt::hresult_errorwinrt::hresult_error hresult_error::to_abi 호출call hresult_error::to_abi
winrt::hresult_access_deniedwinrt::hresult_access_denied winrt::hresult_errorwinrt::hresult_error E_ACCESSDENIEDE_ACCESSDENIED
winrt::hresult_canceledwinrt::hresult_canceled winrt::hresult_errorwinrt::hresult_error ERROR_CANCELLEDERROR_CANCELLED
winrt::hresult_changed_statewinrt::hresult_changed_state winrt::hresult_errorwinrt::hresult_error E_CHANGED_STATEE_CHANGED_STATE
winrt::hresult_class_not_availablewinrt::hresult_class_not_available winrt::hresult_errorwinrt::hresult_error CLASS_E_CLASSNOTAVAILABLECLASS_E_CLASSNOTAVAILABLE
winrt::hresult_illegal_delegate_assignmentwinrt::hresult_illegal_delegate_assignment winrt::hresult_errorwinrt::hresult_error E_ILLEGAL_DELEGATE_ASSIGNMENTE_ILLEGAL_DELEGATE_ASSIGNMENT
winrt::hresult_illegal_method_callwinrt::hresult_illegal_method_call winrt::hresult_errorwinrt::hresult_error E_ILLEGAL_METHOD_CALLE_ILLEGAL_METHOD_CALL
winrt::hresult_illegal_state_changewinrt::hresult_illegal_state_change winrt::hresult_errorwinrt::hresult_error E_ILLEGAL_STATE_CHANGEE_ILLEGAL_STATE_CHANGE
winrt::hresult_invalid_argumentwinrt::hresult_invalid_argument winrt::hresult_errorwinrt::hresult_error E_INVALIDARGE_INVALIDARG
winrt::hresult_no_interfacewinrt::hresult_no_interface winrt::hresult_errorwinrt::hresult_error E_NOINTERFACEE_NOINTERFACE
winrt::hresult_not_implementedwinrt::hresult_not_implemented winrt::hresult_errorwinrt::hresult_error E_NOTIMPLE_NOTIMPL
winrt::hresult_out_of_boundswinrt::hresult_out_of_bounds winrt::hresult_errorwinrt::hresult_error E_BOUNDSE_BOUNDS
winrt::hresult_wrong_threadwinrt::hresult_wrong_thread winrt::hresult_errorwinrt::hresult_error RPC_E_WRONG_THREADRPC_E_WRONG_THREAD

각 클래스(hresult_error 기본 클래스를 통해)는 오류의 HRESULT를 반환하는 to_abi 함수와 해당 HRESULT의 문자열 표현을 반환하는 message 함수를 제공합니다.Note that each class (via the hresult_error base class) provides a to_abi function, which returns the HRESULT of the error, and a message function, which returns the string representation of that HRESULT.

C++/CX에서 예외를 throw하는 예제는 다음과 같습니다.Here's an example of throwing an exception in C++/CX.

throw ref new Platform::InvalidArgumentException(L"A valid User is required");

그리고 C++/WinRT의 해당 항목.And the equivalent in C++/WinRT.

throw winrt::hresult_invalid_argument{ L"A valid User is required" };

Platform::Object^winrt::Windows::Foundation::IInspectable로 이식Port Platform::Object^ to winrt::Windows::Foundation::IInspectable

모든 C++/WinRT 형식과 마찬가지로, winrt::Windows::Foundation::IInspectable은 값 형식입니다.Like all C++/WinRT types, winrt::Windows::Foundation::IInspectable is a value type. 해당 형식의 변수를 null로 초기화하는 방법은 다음과 같습니다.Here's how you initialize a variable of that type to null.

winrt::Windows::Foundation::IInspectable var{ nullptr };

Platform::String^winrt::hstring으로 이식Port Platform::String^ to winrt::hstring

Platform::String^ 은 Windows 런타임 HSTRING ABI 형식에 해당합니다.Platform::String^ is equivalent to the Windows Runtime HSTRING ABI type. C++/WinRT의 해당 항목은 winrt::hstring입니다.For C++/WinRT, the equivalent is winrt::hstring. 그러나 C++/WinRT에서는 std::wstring 같은 C++ 표준 라이브러리 와이드 문자열 형식 및/또는 와이드 문자열 리터럴을 사용해 Windows 런타임 API를 호출할 수 있습니다.But with C++/WinRT, you can call Windows Runtime APIs using C++ Standard Library wide string types such as std::wstring, and/or wide string literals. 자세한 내용과 코드 예제는 C++/WinRT의 문자열 처리를 참조하세요.For more details, and code examples, see String handling in C++/WinRT.

C++/CX에서 Platform::String::Data 속성에 액세스하여 문자열을 C 스타일 const wchar_t* 배열로 검색할 수 있습니다(예를 들면 이를 std::wcout에 전달).With C++/CX, you can access the Platform::String::Data property to retrieve the string as a C-style const wchar_t* array (for example, to pass it to std::wcout).

auto var{ titleRecord->TitleName->Data() };

C++/WinRT에서 같은 작업을 수행하려면 hstring::c_str 함수를 이용하여 std::wstring에서와 마찬가지로 null 종료 C 스타일 문자열 버전을 가져옵니다.To do the same with C++/WinRT, you can use the hstring::c_str function to get a null-terminated C-style string version, just as you can from std::wstring.

auto var{ titleRecord.TitleName().c_str() };

문자열을 가져오거나 반환하는 API 구현에서는 일반적으로 Platform::String^ 을 사용하는 모든 C++/CX 코드를 변경하여 winrt::hstring을 대신 사용합니다.When it comes to implementing APIs that take or return strings, you typically change any C++/CX code that uses Platform::String^ to use winrt::hstring instead.

문자열을 가져오는 C++/CX API의 예제는 다음과 같습니다.Here's an example of a C++/CX API that takes a string.

void LogWrapLine(Platform::String^ str);

C++/WinRT의 경우 이처럼 MIDL 3.0에서 API를 선언할 수 있습니다.For C++/WinRT you could declare that API in MIDL 3.0 like this.

// LogType.idl
void LogWrapLine(String str);

C++/WinRT 도구 체인이 다음과 같이 사용자를 위해 원본 코드를 생성합니다.The C++/WinRT toolchain will then generate source code for you that looks like this.

void LogWrapLine(winrt::hstring const& str);

ToString()ToString()

C++/CX 형식은 Object::ToString 메서드를 제공합니다.C++/CX types provide the Object::ToString method.

int i{ 2 };
auto s{ i.ToString() }; // s is a Platform::String^ with value L"2".

C++/WinRT는 이 기능을 직접 제공하지 않지만 대체 기능으로 전환할 수 있습니다.C++/WinRT doesn't directly provide this facility, but you can turn to alternatives.

int i{ 2 };
auto s{ std::to_wstring(i) }; // s is a std::wstring with value L"2".

또한 C++/WinRT는 제한된 수의 형식에 대해 winrt::to_hstring도 지원합니다.C++/WinRT also supports winrt::to_hstring for a limited number of types. 문자열화하려는 추가 형식에 대한 오버로드를 추가해야 합니다.You'll need to add overloads for any additional types you want to stringify.

외국어Language 정수 문자열화Stringify int 열거형 문자열화Stringify enum
C++/CXC++/CX String^ result = "hello, " + intValue.ToString(); String^ result = "status: " + status.ToString();
C++/WinRTC++/WinRT hstring result = L"hello, " + to_hstring(intValue); // must define overload (see below)
hstring result = L"status: " + to_hstring(status);

열거형을 문자열화하는 경우 winrt::to_hstring의 구현을 제공해야 합니다.In the case of stringifying an enum, you will need to provide the implementation of winrt::to_hstring.

namespace winrt
{
    hstring to_hstring(StatusEnum status)
    {
        switch (status)
        {
        case StatusEnum::Success: return L"Success";
        case StatusEnum::AccessDenied: return L"AccessDenied";
        case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
        default: return to_hstring(static_cast<int>(status));
        }
    }
}

이러한 문자열화는 데이터 바인딩에서 암시적으로 사용되는 경우가 많습니다.These stringifications are often consumed implicitly by data binding.

<TextBlock>
You have <Run Text="{Binding FlowerCount}"/> flowers.
</TextBlock>
<TextBlock>
Most recent status is <Run Text="{x:Bind LatestOperation.Status}"/>.
</TextBlock>

이러한 바인딩은 bound 속성의 winrt::to_hstring을 수행합니다.These bindings will perform winrt::to_hstring of the bound property. 두 번째 예제(StatusEnum)의 경우 winrt::to_hstring에 대한 사용자 고유의 오버로드를 제공해야 합니다. 그렇지 않으면 컴파일러 오류가 발생합니다.In the case of the second example (the StatusEnum), you must provide your own overload of winrt::to_hstring, otherwise you'll get a compiler error.

문자열 작성String-building

C++/CX 및 C++/WinRT는 문자열 작성을 위해 표준 std::wstringstream을 따릅니다.C++/CX and C++/WinRT defer to the standard std::wstringstream for string building.

C++/CXC++/CX C++/WinRTC++/WinRT
문자열 추가, null 유지Append string, preserving nulls stream.print(s->Data(), s->Length); stream << std::wstring_view{ s };
문자열 추가, 첫 번째 null에서 중지Append string, stop on first null stream << s->Data(); stream << s.c_str();
결과 추출Extract result ws = stream.str(); ws = stream.str();

추가 예제More examples

아래 예제에서 wsstd::wstring 형식의 변수입니다.In the examples below, ws is a variable of type std::wstring. 또한 C++/CX는 8비트 문자열에서 Platform::String을 생성할 수 있지만, C++/WinRT는 이 작업을 수행하지 않습니다.Also, while C++/CX can construct a Platform::String from an 8-bit string, C++/WinRT doesn't do that.

작업Operation C++/CXC++/CX C++/WinRTC++/WinRT
리터럴에서 문자열 생성Construct string from literal String^ s = "hello";
String^ s = L"hello";
// winrt::hstring s{ "hello" }; // Doesn't compile
winrt::hstring s{ L"hello" };
std::wstring에서 변환, null 유지Convert from std::wstring, preserving nulls String^ s = ref new String(ws.c_str(),
  (uint32_t)ws.size());
winrt::hstring s{ ws };
s = winrt::hstring(ws);
// s = ws; // Doesn't compile
std::wstring에서 변환, 첫 번째 null에서 중지Convert from std::wstring, stop on first null String^ s = ref new String(ws.c_str()); winrt::hstring s{ ws.c_str() };
s = winrt::hstring(ws.c_str());
// s = ws.c_str(); // Doesn't compile
std::wstring으로 변환, null 유지Convert to std::wstring, preserving nulls std::wstring ws{ s->Data(), s->Length };
ws = std::wstring(s>Data(), s->Length);
std::wstring ws{ s };
ws = s;
std::wstring으로 변환, 첫 번째 null에서 중지Convert to std::wstring, stop on first null std::wstring ws{ s->Data() };
ws = s->Data();
std::wstring ws{ s.c_str() };
ws = s.c_str();
메서드에 리터럴 전달Pass literal to method Method("hello");
Method(L"hello");
// Method("hello"); // Doesn't compile
Method(L"hello");
메서드에 std::wstring 전달Pass std::wstring to method Method(ref new String(ws.c_str(),
  (uint32_t)ws.size()); // Stops on first null
Method(ws);
// param::winrt::hstring accepts std::wstring_view

중요 APIImportant APIs