데스크톱 앱에서 Windows 런타임 API 호출

이 항목에서는 Windows OS에서 제공하는 WinRT(Windows 런타임) API를 사용하도록 데스크톱 앱 프로젝트를 설정하고 최신 Windows 11 및 Windows 10 환경을 데스크톱 앱에 추가하는 방법을 설명합니다.

일부 WinRT(Windows 런타임) API는 데스크톱 앱에서 지원되지 않습니다. 자세한 내용은 데스크톱 앱에서 지원되지 않는 Windows 런타임 API를 참조하세요.

Windows 런타임 API를 사용하도록 .NET 프로젝트 수정

.NET 프로젝트에는 다음과 같은 몇 가지 옵션이 있습니다.

  • .NET 6부터 TFM(대상 프레임워크 모니커)을 프로젝트 파일에 지정하여 WinRT API에 액세스할 수 있습니다. 이 옵션은 Windows 10, 버전 1809 이상을 대상으로 하는 프로젝트에서 지원됩니다.
  • 이전 버전 .NET의 경우 Microsoft.Windows.SDK.Contracts NuGet 패키지를 설치하여 프로젝트에 필요한 모든 참조를 추가할 수 있습니다. 이 옵션은 Windows 10, 버전 1803 이상을 대상으로 하는 프로젝트에서 지원됩니다.
  • 프로젝트가 .NET 6 이상 버전 및 이전 버전의 .NET을 다중 대상으로 하는 경우 두 옵션을 모두 사용하도록 프로젝트 파일을 구성할 수 있습니다.

.NET 6 이상: 대상 프레임워크 Moniker 옵션 사용

이 옵션은 .NET 6 이상 및 대상 Windows 10, 버전 1809 이상 OS 릴리스를 사용하는 프로젝트에서만 지원됩니다. 프로젝트 파일에 Windows OS 버전별 TFM을 지정하면 패키지를 대상으로 하는 적절한 Windows SDK에 참조가 추가됩니다. 이 시나리오에 대한 자세한 배경 정보는 .NET에서 Windows API 호출 블로그 게시물을 참조하세요.

  1. Visual Studio에서 프로젝트를 연 상태로 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 프로젝트 파일 편집을 선택합니다. 프로젝트 파일은 다음과 유사하게 나타납니다.

    참고

    아래 예제에서는 Windows GUI 실행 파일을 지정하는 WinExeOutputType을 보여줍니다. 이를 통해 앱을 실행할 때 콘솔 창이 열리지 않습니다. 앱에 GUI가 없는 경우 OutputType의 값이 달라집니다. Windows GUI 앱, 콘솔 앱 및 라이브러리에서 WinRT API를 호출할 수 있습니다. 또한 TargetFramework의 값이 아래 예제와 정확히 일치하지 않을 수 있습니다.

    <Project Sdk="Microsoft.NET.Sdk">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net5.0</TargetFramework>
      </PropertyGroup>
    </Project>
    
  2. 다른 모든 설정은 그대로 두고 TargetFramework 요소의 값을 다음 문자열 중 하나로 바꿉니다.

    • net6.0-windows10.0.17763.0: 앱이 Windows 10 버전 1809를 대상으로 하는 경우.
    • net6.0-windows10.0.18362.0: 앱이 Windows 10 버전 1903을 대상으로 하는 경우.
    • net6.0-windows10.0.19041.0: 앱이 Windows 10 버전 2004를 대상으로 하는 경우.
    • net6.0-windows10.0.22000.0: 앱이 Windows 11을 대상으로 하는 경우.

    예를 들어, 다음 요소는 Windows 10, 버전 2004를 대상으로 하는 프로젝트를 위한 것입니다.

    <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
    

    이후 버전의 .NET에서는 값을 관련 버전(예: net6.0-windows10.0.19041.0)으로 바꿀 수 있습니다.

  3. 변경 내용을 저장하고 프로젝트 파일을 닫습니다.

.NET 6 이상에서 지원되지 않는 WinRT API

.NET 6 이상에는 Windows.UI 네임스페이스에서 지원되지 않는 여러 WinRT(Windows 런타임) API가 있습니다. 아래에 나열된 API의 경우 WinUI(Microsoft.UI) 네임스페이스(예: Microsoft.UI.Text)에 해당하는 버전의 API가 있습니다. 다음 WinRT API는 .NET 6 이상에서 지원되지 않습니다.

  • Windows.UI.Colors 클래스
  • Windows.UI.ColorHelper 클래스
  • Windows.UI.Text(Windows.UI.Text.FontStretch, Windows.UI.Text.FontStyle, Windows.UI.Text.FontWeight, Windows.UI.Text.UnderlineType제외한 이 네임스페이스의 모든 클래스 및 Windows.UI.Text.Core 네임스페이스 아래의 모든 클래스)
  • Windows.UI.Xaml(이 네임스페이스의 모든 클래스)

여러 Windows OS 버전 지원

Windows OS 버전별 TargetFramework 속성은 앱이 컴파일되는 Windows SDK의 버전을 결정합니다. 이 속성은 빌드 시 액세스 가능한 API 집합을 결정하고, TargetPlatformVersionTargetPlatformMinVersion 모두에 기본값을 제공합니다(명시적으로 설정하지 않은 경우). TargetPlatformVersion 속성은 TargetFramework OS 버전에 따라 자동으로 설정되므로 프로젝트 파일에 명시적으로 정의할 필요가 없습니다.

TargetPlatformMinVersionTargetFramework 속성의 버전에 따라 결정되는 TargetPlatformVersion보다 작게 재정의할 수 있습니다. 이렇게 하면 이전 OS 버전에서 앱을 실행할 수 있습니다. 예를 들어 프로젝트 파일에서 다음을 설정하여 앱 하위 수준을 Windows 10, 버전 1809까지 지원할 수 있습니다.

<Project Sdk="Microsoft.NET.Sdk">
 <PropertyGroup>
   <OutputType>WinExe</OutputType>
   <TargetFramework>net6.0-windows10.0.19041.0</TargetFramework>
   <TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
 </PropertyGroup>
</Project>

TargetPlatformMinVersionTargetPlatformVersion 미만의 버전으로 설정하면 사용할 수 없는 API를 호출할 가능성이 있습니다. 지원되는 모든 OS 버전에서 사용할 수 없는 WinRT API를 호출하는 경우 ApiInformation 검사를 통해 이러한 호출을 보호하는 것이 좋습니다. 자세한 내용은 버전 적응 앱을 참조하세요.

이전 버전의 .NET: Microsoft.Windows.SDK.Contracts NuGet 패키지 설치

앱에서 .NET Core 3.x 또는 .NET Framework를 사용하는 경우 이 옵션을 사용합니다. 이 옵션은 Windows 10, 버전 1803 이상을 대상으로 하는 프로젝트에서 지원됩니다.

  1. 패키지 참조를 사용하도록 설정했는지 확인합니다.

    1. Visual Studio에서 도구 -> NuGet 패키지 관리자 -> 패키지 관리자 설정을 클릭합니다.
    2. 기본 패키지 관리 형식에 대해 PackageReference를 선택했는지 확인합니다.
  2. Visual Studio에서 프로젝트를 연 상태로 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 NuGet 패키지 관리를 선택합니다.

  3. NuGet 패키지 관리자 창에서 찾아보기 탭을 선택하고 Microsoft.Windows.SDK.Contracts을(를) 검색합니다.

  4. Microsoft.Windows.SDK.Contracts 패키지가 검색되면 NuGet 패키지 관리자의 오른쪽 창에서 대상으로 지정할 Windows 10 버전에 따라 설치하려는 패키지의 버전을 선택합니다.

    • 10.0.19041.xxxx: Windows 10 버전 2004가 대상이면 이 버전을 선택합니다.
    • 10.0.18362.xxxx: Windows 10 버전 1903이 대상이면 이 버전을 선택합니다.
    • 10.0.17763.xxxx: Windows 10 버전 1809가 대상이면 이 버전을 선택합니다.
    • 10.0.17134.xxxx: Windows 10 버전 1803이 대상이면 이 버전을 선택합니다.
  5. Install을 클릭합니다.

여러 버전의 .NET을 다중 대상으로 하는 프로젝트 구성

프로젝트에서 .NET 6 이상 및 이전 버전(.NET Core 3.x 및 .NET Framework 포함)을 다중 대상으로 하는 경우 TFM(대상 프레임워크 모니커)을 사용하여 .NET 6 이상용 WinRT API 참조를 자동으로 끌어오도록 프로젝트 파일을 구성하고 이전 버전의 경우 Microsoft.Windows.SDK.Contracts NuGet 패키지를 사용할 수 있습니다.

  1. Visual Studio에서 프로젝트를 연 상태로 솔루션 탐색기에서 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 프로젝트 파일 편집을 선택합니다. 다음 예제에서는 .NET Core 3.1을 사용하는 앱에 대한 프로젝트 파일을 보여 줍니다.

    참고

    아래 예제에서는 Windows GUI 실행 파일을 지정하는 WinExeOutputType을 보여줍니다. 이를 통해 앱을 실행할 때 콘솔 창이 열리지 않습니다. 앱에 GUI가 없는 경우 OutputType의 값은 달라집니다. Windows GUI 앱, 콘솔 앱 및 라이브러리에서 WinRT API를 호출할 수 있습니다. 또한 TargetFramework의 값은 아래 예제와 정확히 일치하지 않을 수 있습니다.

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <UseWindowsForms>true</UseWindowsForms>
      </PropertyGroup>
    </Project>
    
  2. 파일의 TargetFramework 요소를 TargetFrameworks 요소(복수형)로 바꿉니다. 이 요소에서 대상으로 지정할 .NET의 모든 버전에 대한 TFM(대상 프레임워크 모니커)은 세미콜론으로 구분하여 지정합니다.

    • .NET 6 이상에서는 다음 TFM(대상 프레임워크 Monikers) 중 하나를 사용합니다.
      • net6.0-windows10.0.17763.0: 앱이 Windows 10 버전 1809를 대상으로 하는 경우.
      • net6.0-windows10.0.18362.0: 앱이 Windows 10 버전 1903을 대상으로 하는 경우.
      • net6.0-windows10.0.19041.0: 앱이 Windows 10 버전 2004를 대상으로 하는 경우.
    • .NET Core 3.x의 경우 netcoreapp3.0 또는 netcoreapp3.1을 사용합니다.
    • .NET Framework의 경우 net46을 사용합니다.

    다음 예제에서는 .NET Core 3.1 및 .NET 6(Windows 10, 버전 2004)를 다중 대상으로 하는 방법을 보여 줍니다.

    <TargetFrameworks>netcoreapp3.1;net6.0-windows10.0.19041.0</TargetFrameworks>
    
  3. PropertyGroup 요소 뒤에 모든 버전의 .NET Core 3.x 또는 앱이 대상으로 하는 .NET Framework용 Microsoft.Windows.SDK.Contracts NuGet 패키지를 설치하는 조건문이 포함된 PackageReference 요소를 추가합니다. PackageReference 요소는 ItemGroup 요소의 하위 요소여야 합니다. 다음 예제에서는 .NET Core 3.1에 대해 이 작업을 수행하는 방법을 보여 줍니다.

    <ItemGroup>
      <PackageReference Condition="'$(TargetFramework)' == 'netcoreapp3.1'"
                        Include="Microsoft.Windows.SDK.Contracts"
                        Version="10.0.19041.0" />
    </ItemGroup>
    

    완료되면 프로젝트 파일은 다음과 유사하게 나타납니다.

    <Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
      <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFrameworks>netcoreapp3.1;net6.0-windows10.0.19041.0</TargetFrameworks>
        <UseWPF>true</UseWPF>
      </PropertyGroup>
      <ItemGroup>
        <PackageReference Condition="'$(TargetFramework)' == 'netcoreapp3.1'"
                         Include="Microsoft.Windows.SDK.Contracts"
                         Version="10.0.19041.0" />
      </ItemGroup>
    </Project>
    
  4. 변경 내용을 저장하고 프로젝트 파일을 닫습니다.

Windows 런타임 API를 사용하도록 C++ 데스크톱(Win32) 프로젝트 수정

C++/WinRT를 통해 WinRT API를 사용합니다. C++/WinRT는 헤더 파일 기반 라이브러리로 구현된 WinRT API용 완전한 최신 표준 C++17 언어 프로젝션이며, 최신 Windows API에 최고 수준의 액세스를 제공하도록 설계되었습니다.

다음과 같이 C++/WinRT에 사용할 프로젝트를 구성합니다.

이러한 옵션에 대한 자세한 내용은 C++/WinRT 및 VSIX를 위한 Visual Studio 지원을 참조하세요.

Windows 10 환경 추가

사용자가 Windows 10에서 애플리케이션을 실행할 때 만족을 주는 최신 환경을 추가할 준비가 되었습니다. 다음과 같은 디자인 흐름을 사용합니다.

첫째, 추가하고 싶은 환경 결정

선택할 수 있는 환경은 많습니다. 예를 들어 수익 창출 API를 사용하여 구매 주문 흐름을 간소화할 수 있습니다. 또는 다른 사용자가 추가한 새 사진처럼 공유하면 재미있는 콘텐츠가 있을 때 애플리케이션으로 직접 관심을 유도할 수 있습니다.

Toast notification

사용자가 메시지를 무시 또는 해제하는 경우에도 알림 센터에서 다시 메시지를 확인한 후 메시지를 클릭하여 앱을 열 수 있습니다. 이렇게 하면 애플리케이션 참여도를 높일 수 있으며 애플리케이션이 운영 체제와 긴밀하게 통합된 것처럼 보이게 하는 부가적인 효과가 있습니다. 이 문서의 뒷부분에서 이러한 환경의 코드를 보여드리겠습니다.

자세한 내용은 UWP 설명서를 참조하세요.

강화할 것인지 아니면 확장할 것인지 결정

당사는 강화확장이라는 용어를 자주 사용합니다. 각 용어의 의미를 정확히 설명하겠습니다.

패키지 앱인지 여부에 관계없이 강화라는 용어는 데스크톱 앱에서 직접 호출할 수 있는 WinRT API를 설명할 때 사용됩니다(애플리케이션을 MSIX 패키지에 패키징하기로 선택했는지 여부는 관계 없음). Windows 10 환경을 선택할 때 환경을 만들기 위해 필요한 API를 식별하고 해당 API가 이 목록에 표시되는지 확인하세요. 이 목록은 데스크톱 앱에서 직접 호출할 수 있는 API 목록입니다. API와 연결된 기능을 UWP 프로세스에서만 실행할 수 있는 경우에는 이 목록에 API가 표시되지 않습니다. UWP 지도 컨트롤이나 Windows Hello 보안 프롬프트 같은 UWP XAML을 렌더링하는 API가 여기에 자주 포함됩니다.

참고

UWP XAML을 렌더링하는 API는 일반적으로 데스크톱에서 직접 호출할 수 없지만, 다른 방법을 사용할 수 있습니다. UWP XAML 컨트롤 또는 다른 사용자 지정 시각적 환경을 호스팅하려면 XAML Islands(Windows 10 버전 1903부터) 및 시각적 레이어(Windows 10 버전 1803부터)를 사용할 수 있습니다. 이러한 기능은 패키징 또는 패키징되지 않은 데스크톱 앱에서 사용할 수 있습니다.

데스크톱 앱을 패키징하기로 선택한 경우 또 다른 옵션으로 솔루션에 UWP 프로젝트를 추가하여 애플리케이션을 확장할 수 있습니다. 데스크톱 프로젝트는 여전히 애플리케이션의 진입점이지만, UWP 프로젝트를 통해 이 목록에 표시되지 않는 모든 API에 액세스할 수 있습니다. 데스크톱 앱은 앱 서비스를 사용하여 UWP 프로세스와 통신할 수 있으며, 이렇게 설정하는 방법에 대한 여러 지침이 제공됩니다. UWP 프로젝트가 필요한 환경을 추가하려면 UWP 구성 요소를 사용하여 확장을 참조하세요.

참조 API 계약

데스크톱 앱에서 직접 API를 호출할 수 있다면 브라우저를 열고 해당 API의 참조 토픽을 검색합니다. 아래의 API 요약 정보에서 해당 API의 API 계약에 대해 설명하는 표를 찾을 수 있습니다. 다음은 해당 표의 예입니다.

API contract table

.NET 기반 데스크톱 앱을 갖고 있다면 API 계약에 참조를 추가한 다음, 해당 파일의 로컬 복사 속성을 False로 설정합니다. C++ 기반 프로젝트를 사용하는 경우 이 계약이 포함된 폴더의 경로인 Additional Include Directories에 추가합니다.

API를 호출하여 환경 추가

다음은 앞에서 살펴본 알림 창을 표시하는 데 사용할 코드입니다. 지금 바로 데스크톱 앱에 이 코드를 추가하고 실행할 수 있도록 다음 API가 이 목록에 표시됩니다.

using Windows.Foundation;
using Windows.System;
using Windows.UI.Notifications;
using Windows.Data.Xml.Dom;
...

private void ShowToast()
{
    string title = "featured picture of the day";
    string content = "beautiful scenery";
    string image = "https://picsum.photos/360/180?image=104";
    string logo = "https://picsum.photos/64?image=883";

    string xmlString =
    $@"<toast><visual>
       <binding template='ToastGeneric'>
       <text>{title}</text>
       <text>{content}</text>
       <image src='{image}'/>
       <image src='{logo}' placement='appLogoOverride' hint-crop='circle'/>
       </binding>
      </visual></toast>";

    XmlDocument toastXml = new XmlDocument();
    toastXml.LoadXml(xmlString);

    ToastNotification toast = new ToastNotification(toastXml);

    ToastNotificationManager.CreateToastNotifier().Show(toast);
}
#include <sstream>
#include <winrt/Windows.Data.Xml.Dom.h>
#include <winrt/Windows.UI.Notifications.h>

using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::System;
using namespace winrt::Windows::UI::Notifications;
using namespace winrt::Windows::Data::Xml::Dom;

void UWP::ShowToast()
{
    std::wstring const title = L"featured picture of the day";
    std::wstring const content = L"beautiful scenery";
    std::wstring const image = L"https://picsum.photos/360/180?image=104";
    std::wstring const logo = L"https://picsum.photos/64?image=883";

    std::wostringstream xmlString;
    xmlString << L"<toast><visual><binding template='ToastGeneric'>" <<
        L"<text>" << title << L"</text>" <<
        L"<text>" << content << L"</text>" <<
        L"<image src='" << image << L"'/>" <<
        L"<image src='" << logo << L"'" <<
        L" placement='appLogoOverride' hint-crop='circle'/>" <<
        L"</binding></visual></toast>";

    XmlDocument toastXml;

    toastXml.LoadXml(xmlString.str().c_str());

    ToastNotificationManager::CreateToastNotifier().Show(ToastNotification(toastXml));
}
using namespace Windows::Foundation;
using namespace Windows::System;
using namespace Windows::UI::Notifications;
using namespace Windows::Data::Xml::Dom;

void UWP::ShowToast()
{
	Platform::String ^title = "featured picture of the day";
	Platform::String ^content = "beautiful scenery";
	Platform::String ^image = "https://picsum.photos/360/180?image=104";
	Platform::String ^logo = "https://picsum.photos/64?image=883";

	Platform::String ^xmlString =
		L"<toast><visual><binding template='ToastGeneric'>" +
		L"<text>" + title + "</text>" +
		L"<text>"+ content + "</text>" +
		L"<image src='" + image + "'/>" +
		L"<image src='" + logo + "'" +
		L" placement='appLogoOverride' hint-crop='circle'/>" +
		L"</binding></visual></toast>";

	XmlDocument ^toastXml = ref new XmlDocument();

	toastXml->LoadXml(xmlString);

	ToastNotificationManager::CreateToastNotifier()->Show(ref new ToastNotification(toastXml));
}

알림에 대한 자세한 정보는 적응형 및 대화형 알림 메시지를 참조하세요.

Windows XP, Windows Vista, Windows 7/8 설치 기반 지원

새 분기를 만들고 별도의 코드 기반을 유지할 필요 없이 Windows 10용 애플리케이션을 현대화할 수 있습니다.

Windows 10 사용자를 위한 별도의 바이너리를 빌드하려면 조건부 컴파일을 사용합니다. 모든 Windows 사용자에게 배포할 단일 바이너리 세트를 빌드하려면 런타임 검사를 사용합니다.

각 옵션을 간단하게 살펴보겠습니다.

조건부 컴파일

Windows 10 사용자만을 위한 한 가지 코드 기반을 유지하고 바이너리 세트를 컴파일할 수 있습니다.

먼저 프로젝트에 새 빌드 구성을 추가합니다.

Build Configuration

해당 빌드 구성에서 WinRT API를 호출하는 코드를 식별하는 상수를 만듭니다.

.NET 기반 프로젝트의 상수는 Conditional Compilation Constant입니다.

Conditional Compilation constant

C++ 기반 프로젝트의 상수는 Preprocessor Definition입니다.

Preprocessor Definition constant

UWP 코드 블록 앞에 해당 상수를 추가합니다.

[System.Diagnostics.Conditional("_UWP")]
private void ShowToast()
{
 ...
}
#if _UWP
void UWP::ShowToast()
{
 ...
}
#endif

활성 빌드 구성에서 상수를 정의한 경우에만 컴파일러가 코드를 빌드합니다.

런타임 검사

실행 중인 Windows 버전에 관계 없이 모든 Windows 사용자를 위한 바이너리 세트를 컴파일 할 수 있습니다. 사용자가 애플리케이션을 Windows 10에서 패키징된 애플리케이션으로 실행하는 경우에만 애플리케이션이 WinRT API를 호출합니다.

가장 쉽게 런타임 검사를 코드에 추가하는 방법은 Nuget 패키지: 데스크톱 브리지 도우미를 설치한 후 IsRunningAsUWP() 메서드를 사용하여 WinRT API를 호출하는 모든 코드를 해제하는 것입니다. 자세한 내용은 블로그 게시물 Desktop Bridge - Identify the application's context(데스크톱 브리지 - 애플리케이션 컨텍스트 식별)을 참조하세요.

질문에 대한 답변 찾기

질문이 있으세요? Stack Overflow에서 질문하세요. 저희 팀은 이러한 태그를 모니터링합니다. 포럼에 문의할 수도 있습니다.