C++/WinRT 앱에서 사용할 C# Windows 런타임 구성 요소 작성

이 토픽에서는 C++/WinRT 프로젝트에 간단한 C# 구성 요소를 추가하는 과정을 안내합니다.

Visual Studio를 사용하면 간편하게 사용자 지정 Windows 런타임 형식을 작성하고 C# 또는 Visual Basic으로 작성된 WRC(Windows 런타임 구성 요소) 프로젝트 내에 배포한 다음, C++ 애플리케이션 프로젝트에서 해당 WRC를 참조하고 해당 애플리케이션에서 사용자 지정 형식을 사용할 수 있습니다.

내부적으로 Windows 런타임 형식은 UWP 애플리케이션에 허용되는 모든 .NET 기능을 사용할 수 있습니다.

참고 항목

자세한 내용은 C# 및 Visual Basic이 포함된 Windows 런타임 구성 요소UWP 앱용 .NET 개요를 참조하세요.

외부적으로 형식의 멤버는 매개 변수 및 반환 값에 대한 형식만 공개할 수 있습니다. 솔루션을 빌드할 때 Visual Studio는 .NET WRC 프로젝트를 빌드한 다음, Windows 메타데이터(.winmd) 파일을 만드는 빌드 단계를 실행합니다. 이는 Visual Studio가 앱에 포함시키는 WRC(Windows 런타임 구성 요소)입니다.

참고 항목

.NET은 기본 데이터 형식이나 컬렉션 형식처럼 널리 사용되는 일부 .NET 형식을 해당 Windows 런타임 형식에 자동으로 매핑합니다. 이러한 .NET 형식은 Windows 런타임 구성 요소의 공용 인터페이스에 사용할 수 있으며, 구성 요소 사용자에게 해당 Windows 런타임 형식으로 표시됩니다. C# 및 Visual Basic이 포함된 Windows 런타임 구성 요소를 참조하세요.

전제 조건

비어 있는 앱 만들기

Visual Studio에서 비어 있는 앱(C++/WinRT) 프로젝트 템플릿을 사용하여 새 프로젝트를 만듭니다. (유니버설 Windows) 템플릿이 아닌 (C++/WinRT) 템플릿을 사용하고 있는지 확인합니다.

폴더 구조가 연습과 일치하도록 새 프로젝트의 이름을 CppToCSharpWinRT로 설정합니다.

솔루션에 C# Windows 런타임 구성 요소 추가

Visual Studio에서 다음과 같이 구성 요소 프로젝트를 만듭니다. 먼저 솔루션 탐색기에서 CppToCSharpWinRT 솔루션의 바로 가기 메뉴를 열고 추가를 선택한 다음, 새 프로젝트를 선택하여 새 C# 프로젝트를 솔루션에 추가합니다. 새 프로젝트 추가 대화 상자의 설치된 템플릿 섹션에서 Visual C#을 선택하고 Windows, 유니버설을 차례로 선택합니다. Windows 런타임 구성 요소(유니버설 Windows) 템플릿을 선택하고 프로젝트 이름으로 SampleComponent를 입력합니다.

참고 항목

새 유니버설 Windows 플랫폼 프로젝트 대화 상자에서 최소 버전으로 Windows 10 크리에이터스 업데이트(10.0, 빌드 15063)를 선택합니다. 자세한 내용은 아래의 애플리케이션 최소 버전 섹션을 참조하세요.

C# GetMyString 메서드 추가

SampleComponent 프로젝트에서 클래스 이름을 Class1에서 Example로 변경합니다. 그런 다음, 두 개의 간단한 멤버, 즉, 프라이빗 int 필드와 GetMyString이라는 인스턴스 메서드를 이 클래스에 추가합니다.

    public sealed class Example
    {
        int MyNumber;

        public string GetMyString()
        {
            return $"This is call #: {++MyNumber}";
        }
    }

참고 항목

기본적으로 이 클래스는 public sealed로 표시됩니다. 구성 요소에서 공개하는 모든 Windows 런타임 클래스를 봉인해야 합니다.

참고 항목

선택 사항: 새로 추가된 멤버에 IntelliSense를 사용하도록 설정하려면 솔루션 탐색기에서 SampleComponent 프로젝트의 바로 가기 메뉴를 열고 빌드를 선택합니다.

CppToCSharpWinRT 프로젝트에서 C# SampleComponent 참조

솔루션 탐색기의 C++/WinRT 프로젝트에서 참조의 바로 가기 메뉴를 연 다음, 참조 추가를 선택하여 참조 추가 대화 상자를 엽니다. 프로젝트를 선택한 다음 솔루션을 선택합니다. SampleComponent 프로젝트의 확인란을 선택하고 확인을 선택하여 참조를 추가합니다.

참고 항목

선택 사항: C++/WinRT 프로젝트에 IntelliSense를 사용하도록 설정하려면 솔루션 탐색기에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 빌드를 선택합니다.

MainPage.h 편집

CppToCSharpWinRT 프로젝트에서 MainPage.h를 열고 두 항목을 추가합니다. 먼저 #include 문의 끝에 #include "winrt/SampleComponent.h"를 추가한 다음, MainPage 구조체에 winrt::SampleComponent::Example 필드를 추가합니다.

// MainPage.h
...
#include "winrt/SampleComponent.h"

namespace winrt::CppToCSharpWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
...
        winrt::SampleComponent::Example myExample;
...
    };
}

참고 항목

Visual Studio에서 MainPage.xaml 아래에 MainPage.h가 나열됩니다.

MainPage.cpp 편집

C# 메서드 GetMyString을 호출하도록 MainPage.cpp에서 Mainpage::ClickHandler 구현을 변경합니다.

void MainPage::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
    //myButton().Content(box_value(L"Clicked"));

    hstring myString = myExample.GetMyString();

    myButton().Content(box_value(myString));
}

프로젝트 실행

이제 프로젝트를 빌드하고 실행할 수 있습니다. 단추를 클릭할 때마다 단추의 숫자가 증가합니다.

C++/WinRT Windows calling into a C# component screenshot

Visual Studio에서 다음과 같이 구성 요소 프로젝트를 만듭니다. 먼저 솔루션 탐색기에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 속성을 선택한 다음, 구성 속성에서 디버깅을 선택합니다. C#(관리) 및 C++(네이티브) 코드를 모두 디버그하려면 디버거 형식을 관리 및 네이티브로 설정합니다. C++ Debugging Properties

애플리케이션 최소 버전

C# 프로젝트의 애플리케이션 최소 버전은 애플리케이션을 컴파일하는 데 사용되는 .NET 버전을 제어합니다. 예를 들어 Windows 10 Fall Creators Update(10.0, 빌드 16299) 이상을 선택하면 .NET Standard 2.0 및 Windows Arm64 프로세서를 지원할 수 있습니다.

.NET Standard 2.0 또는 Arm64 지원이 필요 없는 경우에는 추가 빌드 구성을 방지할 수 있도록 16299보다 낮은 애플리케이션 최소 버전을 사용하는 것이 좋습니다.

Windows 10 Fall Creators Update(10.0, 빌드 16299) 구성

C++/WinRT 프로젝트에서 참조하는 C# 프로젝트에서 .NET Standard 2.0 또는 Windows Arm64를 지원하려면 다음 단계를 수행합니다.

Visual Studio에서 솔루션 탐색기로 이동하여 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 엽니다. 속성을 선택하고 유니버설 Windows 앱 최소 버전을 Windows 10 Fall Creators Update(10.0, 빌드 16299) 이상으로 설정합니다. SampleComponent 프로젝트에 대해서도 동일한 작업을 수행합니다.

Visual Studio에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 프로젝트 언로드를 선택하여 텍스트 편집기에서 CppToCSharpWinRT.vcxproj를 엽니다.

다음 XML을 복사하여 CPPWinRTCSharpV2.vcxproj의 첫 번째 PropertyGroup에 붙여넣습니다.

   <!-- Start Custom .NET Native properties -->
   <DotNetNativeVersion>2.2.12-rel-31116-00</DotNetNativeVersion>
   <DotNetNativeSharedLibrary>2.2.8-rel-31116-00</DotNetNativeSharedLibrary>
   <UWPCoreRuntimeSdkVersion>2.2.14</UWPCoreRuntimeSdkVersion>
   <!--<NugetPath>$(USERPROFILE)\.nuget\packages</NugetPath>-->
   <NugetPath>$(ProgramFiles)\Microsoft SDKs\UWPNuGetPackages</NugetPath>
   <!-- End Custom .NET Native properties -->

DotNetNativeVersion, DotNetNativeSharedLibraryUWPCoreRuntimeSdkVersion의 값은 Visual Studio 버전에 따라 다를 수 있습니다. 올바른 값으로 설정하려면 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages를 열고 아래 표에 나와 있는 각 값의 하위 디렉터리를 확인합니다. %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler 디렉터리에는 설치된 .NET 네이티브 버전(2.2로 시작)이 포함된 하위 디렉터리가 있습니다. 아래 예제에서는 2.2.12-rel-31116-00입니다.

MSBuild 변수 디렉터리
DotNetNativeVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.Native.Compiler 2.2.12-rel-31116-00
DotNetNativeSharedLibrary %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-x64.microsoft.net.native.sharedlibrary 2.2.8-rel-31116-00
UWPCoreRuntimeSdkVersion %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\Microsoft.Net.UWPCoreRuntimeSdk 2.2.14

참고 항목

Microsoft.Net.Native.SharedLibrary에 지원되는 여러 아키텍처가 있습니다. x64는 적절한 아키텍처로 바꾸세요. 예를 들어 arm64 아키텍처는 %ProgramFiles(x86)%\Microsoft SDKs\UWPNuGetPackages\runtime.win10-arm64.microsoft.net.native.sharedlibrary 디렉터리에 있습니다.

다음으로 첫 번째 PropertyGroup 바로 뒤에 다음 내용을 변경 없이 그대로 추가합니다.

  <!-- Start Custom .NET Native targets -->
  <!-- Import all of the .NET Native / CoreCLR props at the beginning of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.props" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.props" />
  <!-- End Custom .NET Native targets -->

프로젝트 파일의 끝부분에서 닫는 Project 태그 바로 앞에 다음 내용을 변경 없이 그대로 추가합니다.

  <!-- Import all of the .NET Native / CoreCLR targets at the end of the project -->
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x86.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-x64.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk\$(UWPCoreRuntimeSdkVersion)\build\runtime.win10-arm.Microsoft.Net.UWPCoreRuntimeSdk.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x86.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-x64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.Compiler\$(DotNetNativeVersion)\build\runtime.win10-arm64.Microsoft.Net.Native.Compiler.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x86.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-x64.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm.Microsoft.Net.Native.SharedLibrary.targets" />
  <Import Condition="'$(WindowsTargetPlatformMinVersion)' &gt;= '10.0.16299.0'" Project="$(NugetPath)\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary\$(DotNetNativeSharedLibrary)\build\runtime.win10-arm64.Microsoft.Net.Native.SharedLibrary.targets" />
  <!-- End Custom .NET Native targets -->

Visual Studio에서 프로젝트 파일을 다시 로드합니다. 다시 로드하려면 Visual Studio 솔루션 탐색기에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 프로젝트 다시 로드를 선택합니다.

.NET 네이티브용 빌드

.NET 네이티브를 대상으로 빌드된 C# 구성 요소를 사용하여 애플리케이션을 빌드하고 테스트하는 것이 좋습니다. Visual Studio에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 프로젝트 언로드를 선택하여 텍스트 편집기에서 CppToCSharpWinRT.vcxproj를 엽니다.

그런 다음, C++ 프로젝트 파일의 릴리스 및 Arm64 구성에서 UseDotNetNativeToolchain 속성을 true로 설정합니다.

Visual Studio 솔루션 탐색기에서 CppToCSharpWinRT 프로젝트의 바로 가기 메뉴를 열고 프로젝트 다시 로드를 선택합니다.

  <PropertyGroup Condition="'$(Configuration)'=='Release'" Label="Configuration">
...
    <UseDotNetNativeToolchain>true</UseDotNetNativeToolchain>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Platform)'=='Arm64'" Label="Configuration">
    <UseDotNetNativeToolchain Condition="'$(UseDotNetNativeToolchain)'==''">true</UseDotNetNativeToolchain>
  </PropertyGroup>

다른 C# nuget 패키지 참조

C# 구성 요소가 다른 nuget 패키지를 참조하는 경우 애플리케이션의 프로젝트 파일에 배포 콘텐츠로 사용할 nuget 패키지의 목록 파일 종속성이 필요할 수 있습니다. 예를 들어 C# 구성 요소가 Newtonsoft.Json nuget 패키지를 참조하는 경우 애플리케이션 프로젝트에서도 동일한 nuget 패키지 및 파일 종속성을 참조해야 합니다.

SampleComponent.csproj 파일에서 nuget 패키지 참조를 추가합니다.

    <PackageReference Include="Newtonsoft.Json">
      <Version>13.0.1</Version>
    </PackageReference>

CppToCSharpWinRT 프로젝트에서 packages.config 파일을 찾아 적절한 nuget 참조를 추가합니다. 그러면 nuget 패키지가 솔루션의 패키지 폴더에 설치됩니다.

packages.config에서 동일한 nuget 패키지 참조를 추가합니다.

  <package id="Newtonsoft.Json" version="13.0.1" targetFramework="native" developmentDependency="true" />

그런 다음, 애플리케이션 프로젝트 파일에 다음을 추가하여 솔루션의 패키지 폴더에서 적절한 파일 종속성을 참조합니다. 예를 들어 CppToCSharpWinRT.vcxproj에서 다음을 추가합니다.

  <ItemGroup>
    <None Include="..\packages\Newtonsoft.Json.13.0.1\lib\netstandard2.0\Newtonsoft.Json.dll">
      <Link>%(Filename)%(Extension)</Link>
      <DeploymentContent>true</DeploymentContent>
    </None>
  </ItemGroup>