방법: 유니버설 Windows 플랫폼 앱에서 기존 C++ 코드 사용

UWP(유니버설 Windows 플랫폼) 프로젝트에서 기존 C++ 코드를 사용할 수 있는 다양한 방법이 있습니다. 일부 방법에서는 구성 요소 확장(C++/CX)을 사용하도록 설정된(즉, 옵션과 함께 /ZW ) 코드를 다시 컴파일할 필요가 없으며, 일부는 그렇지 않습니다. 코드를 표준 C++로 유지하거나 일부 코드에 대해 클래식 Win32 컴파일 환경을 유지해야 할 수 있습니다. 적절한 아키텍처 선택으로 계속 수행할 수 있습니다. UWP UI 및 C#, Visual Basic 및 JavaScript 호출자에 노출되는 형식을 포함하는 모든 코드를 고려합니다. 이 코드는 Windows 앱 프로젝트 및 Windows 런타임 구성 요소 프로젝트에 있어야 합니다. C++에서만 호출하는 코드(C++/CX 포함)는 옵션 또는 표준 C++ 프로젝트로 /ZW 컴파일되는 프로젝트에 있을 수 있습니다. 허용되지 않는 API를 사용하지 않는 이진 전용 코드는 정적 라이브러리로 연결하여 사용할 수 있습니다. 또는 앱을 콘텐츠로 패키지하고 DLL에 로드할 수 있습니다.

데스크톱 프로그램을 UWP 환경에서 실행되게 하는 가장 쉬운 방법은 데스크톱 브리지 기술을 사용하는 것입니다. 여기에는 코드 변경 없이 기존 애플리케이션을 UWP 앱으로 패키지하는 데스크톱 앱 변환기가 포함됩니다. 자세한 내용은 데스크톱 브리지를 참조하세요.

이 문서의 나머지 부분은 C++ 라이브러리(DLL 및 정적 라이브러리)를 유니버설 Windows 플랫폼 포츠하는 방법에 대해 설명합니다. 코어 C++ 논리를 여러 UWP 앱과 함께 사용할 수 있도록 코드를 이식할 수 있습니다.

UWP 앱은 보호된 환경에서 실행됩니다. 따라서 플랫폼 보안을 손상시킬 수 있는 많은 Win32, COM 및 CRT API 호출은 허용되지 않습니다. /ZW 컴파일러 옵션은 이러한 호출을 감지하고 오류를 생성할 수 있습니다. 애플리케이션에서 앱 인증 키트를 사용하여 허용되지 않는 API를 호출하는 코드를 검색할 수 있습니다. 자세한 내용은 Windows 앱 인증 키트를 참조하세요.

라이브러리에 소스 코드를 사용할 수 있는 경우 허용되지 않는 API 호출을 제거하려고 할 수 있습니다. 허용되지 않는 API 목록은 유니버설 Windows 플랫폼 앱에서 지원되지 않는 UWP 앱 및 CRT 함수에 대한 Win32 및 COM API를 참조하세요. 일부 대안은 UWP 앱에서 Windows API의 대안에서 찾을 수 있습니다.

유니버설 Windows 프로젝트의 참조를 클래식 데스크톱 라이브러리에 추가하려고 하면 라이브러리가 호환되지 않는다는 오류 메시지가 표시됩니다. 정적 라이브러리인 경우 클래식 Win32 애플리케이션에서와 동일한 방식으로 라이브러리(.lib 파일)를 링커 입력에 추가하여 라이브러리에 연결할 수 있습니다. 이진 라이브러리만 사용할 수 있는 경우 유일한 옵션입니다. 정적 라이브러리는 앱의 실행 파일에 연결됩니다. 그러나 UWP 앱에서 사용하는 Win32 DLL은 프로젝트에 포함하고 콘텐츠로 표시하여 앱에 패키지되어야 합니다. UWP 앱에서 Win32 DLL을 로드하려면 대신 또는 LoadPackagedLibraryLoadLibraryLoadLibraryEx.

DLL 또는 정적 라이브러리에 대한 소스 코드가 있는 경우 컴파일러 옵션을 사용하여 UWP 프로젝트로 다시 컴파일할 /ZW 수 있습니다. 그런 다음 솔루션 탐색기 사용하여 참조를 추가하고 C++ UWP 앱에서 사용할 수 있습니다. 내보내기 라이브러리를 사용하여 DLL을 연결합니다.

다른 언어로 호출자에게 기능을 노출하기 위해 라이브러리를 Windows 런타임 구성 요소로 변환할 수 있습니다. Windows 런타임 구성 요소는 .NET 및 JavaScript 소비자가 요구하는 방식으로 콘텐츠를 설명하는 파일 형식의 .winmd 메타데이터를 포함한다는 점에서 일반 DLL과 다릅니다. API 요소를 다른 언어에 노출하려면 ref 클래스와 같은 C++/CX 구문을 추가하고 공용으로 만들 수 있습니다. Windows 10 이상에서는 C++/CX 대신 C++/WinRT 라이브러리를 사용하는 것이 좋습니다.

앞의 설명은 다르게 처리해야 하는 COM 구성 요소에는 적용되지 않습니다. EXE 또는 DLL에 COM 서버가 있는 경우 유니버설 Windows 프로젝트에서 사용할 수 있습니다. 등록이 없는 COM 구성 요소로 패키지하고, 프로젝트에 콘텐츠 파일로 추가하고, 를 사용하여 CoCreateInstanceFromApp인스턴스화합니다. 자세한 내용은 Windows 스토어 C++ 프로젝트에서 Free-COM DLL 사용을 참조하세요.

기존 COM 라이브러리를 UWP로 포팅하려는 경우 Windows 런타임 구성 요소로 변환할 수도 있습니다. 이러한 포트에는 C++/WinRT 라이브러리를 사용하는 것이 좋지만 WINDOWS 런타임 C++ 템플릿 라이브러리(WRL)를 사용할 수도 있습니다. WRL은 더 이상 사용되지 않으며 ATL 및 OLE의 모든 기능을 지원하지는 않습니다. 이러한 포트가 가능한지 여부는 구성 요소에 필요한 COM, ATL 및 OLE의 기능에 따라 달라집니다.

어떤 개발 시나리오를 선택하든 여러 매크로 정의를 알고 있어야 합니다. 코드에서 이러한 매크로를 사용하여 클래식 데스크톱 Win32 및 UWP에서 코드를 조건부로 컴파일할 수 있습니다.

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PC_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)

이러한 문은 각각 UWP 앱, Windows Phone 스토어 앱 중 하나 또는 둘 다에 적용되거나 적용되지 않습니다(클래식 Win32 데스크톱만 해당). 이러한 매크로는 Windows SDK 8.1 이상에서만 사용할 수 있습니다.

이 문서에는 다음 절차가 포함되어 있습니다.

UWP 앱에서 Win32 DLL 사용

보안 및 안정성을 높이기 위해 유니버설 Windows 앱은 제한된 런타임 환경에서 실행됩니다. 클래식 Windows 데스크톱 애플리케이션에서와 같은 방식으로 네이티브 DLL만 사용할 수는 없습니다. DLL의 소스 코드가 있는 경우 UWP에서 실행되도록 코드를 이식할 수 있습니다. 먼저 프로젝트를 UWP 프로젝트로 식별하기 위해 몇 가지 프로젝트 설정과 프로젝트 파일 메타데이터를 변경합니다. C++/CX를 사용하도록 설정하는 옵션을 사용하여 /ZW 라이브러리 코드를 다시 컴파일합니다. 특정 API 호출은 해당 환경과 연결된 엄격한 제어로 인해 UWP 앱에서 허용되지 않습니다. 자세한 내용은 UWP 앱용 Win32 및 COM API를 참조 하세요.

__declspec(dllexport)을 사용하여 함수를 내보내는 네이티브 DLL이 있는 경우 DLL을 UWP 프로젝트로 다시 컴파일하여 UWP 앱에서 해당 함수를 호출할 수 있습니다. 예를 들어 다음 헤더 파일과 같은 코드를 사용하여 몇 가지 클래스와 메서드를 내보내는 기린이라는 Win32 DLL 프로젝트가 있다고 가정해 보겠습니다.

// giraffe.h
// Define GIRAFFE_EXPORTS when building this DLL
#pragma once

#ifdef GIRAFFE_EXPORTS
#define GIRAFFE_API __declspec(dllexport)
#else
#define GIRAFFE_API
#endif

GIRAFFE_API int giraffeFunction();

class Giraffe
{
    int id;
        Giraffe(int id_in);
    friend class GiraffeFactory;

public:
    GIRAFFE_API int GetID();
};

class GiraffeFactory
{
    static int nextID;

public:
    GIRAFFE_API GiraffeFactory();
    GIRAFFE_API static int GetNextID();
    GIRAFFE_API static Giraffe* Create();
};

다음 코드 파일이 있다고 가정합니다.

// giraffe.cpp
#include "pch.h"
#include "giraffe.h"

Giraffe::Giraffe(int id_in) : id(id_in)
{
}

int Giraffe::GetID()
{
    return id;
}

int GiraffeFactory::nextID = 0;

GiraffeFactory::GiraffeFactory()
{
    nextID = 0;
}

int GiraffeFactory::GetNextID()
{
    return nextID;
}

Giraffe* GiraffeFactory::Create()
{
    return new Giraffe(nextID++);
}

int giraffeFunction();

프로젝트의 다른 모든 항목(pch.h, dllmain.cpp)은 표준 Win32 프로젝트 템플릿의 일부입니다. 이 코드는 정의된 시점 GIRAFFE_EXPORTS 으로 확인되는 매크로GIRAFFE_API__declspec(dllexport) 정의합니다. 즉, 프로젝트가 DLL로 빌드되는 경우 정의되지만 클라이언트에서 헤더를 사용하는 giraffe.h 경우는 정의되지 않습니다. 이 DLL은 소스 코드를 변경하지 않고 UWP 프로젝트에서 사용할 수 있습니다. 일부 프로젝트 설정 및 속성만 변경해야 합니다.

다음 절차는 을 사용하여 __declspec(dllexport)함수를 노출하는 네이티브 DLL이 있는 경우에 적용됩니다.

새 프로젝트를 만들지 않고 네이티브 DLL을 UWP로 이식하려면

  1. Visual Studio에서 DLL 프로젝트를 엽니다.

  2. DLL 프로젝트에 대한 프로젝트 속성을 열고 구성모든 구성으로 설정합니다.

  3. 프로젝트 속성C/C++>일반 탭에서 Windows 런타임 확장 사용예(/ZW)로 설정합니다. 이 속성은 구성 요소 확장(C++/CX)을 사용하도록 설정합니다.

  4. 솔루션 탐색기 프로젝트 노드를 선택하고 바로 가기 메뉴를 열고 프로젝트 언로드를 선택합니다. 그런 다음 언로드된 프로젝트 노드에서 바로 가기 메뉴를 열고 프로젝트 파일을 편집하도록 선택합니다. WindowsTargetPlatformVersion 요소를 찾아서 다음 요소로 바꿉니다.

    <AppContainerApplication>true</AppContainerApplication>
    <ApplicationType>Windows Store</ApplicationType>
    <WindowsTargetPlatformVersion>10.0.10156.0</WindowsTargetPlatformVersion>
    <WindowsTargetPlatformMinVersion>10.0.10156.0</WindowsTargetPlatformMinVersion>
    <ApplicationTypeRevision>10.0</ApplicationTypeRevision>
    

    파일을 닫고 .vcxproj 바로 가기 메뉴를 다시 열고 프로젝트 다시 로드를 선택합니다.

    이제 솔루션 탐색기는 프로젝트를 유니버설 Windows 프로젝트로 식별합니다.

  5. 미리 컴파일된 헤더 파일 이름이 올바른지 확인합니다. 미리 컴파일된 헤더 섹션에서 다음과 같은 오류가 표시되는 경우 미리 컴파일된 헤더 파일을pch.hstdafx.h 다른 방법으로 변경해야 할 수 있습니다.

    오류 C2857: 명령줄 옵션으로 /Ycpch.h 지정된 '#include' 문을 원본 파일에서 찾을 수 없습니다.

    문제는 이전 프로젝트 템플릿이 미리 컴파일된 헤더 파일에 대해 다른 명명 규칙을 사용한다는 것입니다. Visual Studio 2019 이상 프로젝트에서 사용합니다 pch.h.

  6. 프로젝트를 빌드합니다. 호환되지 않는 명령줄 옵션에 대한 몇 가지 오류가 발생할 수 있습니다. 예를 들어 현재 더 이상 사용되지 않지만 자주 사용되는 옵션인 최소 다시 빌드 가능(/Gm)은 기본적으로 많은 이전 C++ 프로젝트에서 설정되며 /ZW와 호환되지 않습니다.

    유니버설 Windows 플랫폼 컴파일할 때는 일부 함수를 사용할 수 없습니다. 모든 문제에 대한 컴파일러 오류가 표시됩니다. 클린 빌드할 때까지 이러한 오류를 해결합니다.

  7. 동일한 솔루션의 UWP 앱에서 DLL을 사용하려면 UWP 프로젝트 노드에 대한 바로 가기 메뉴를 열고 추가>참조를 선택합니다.

    프로젝트>솔루션 아래에서 DLL 프로젝트 옆의 확인란을 선택하고 확인 단추를 선택합니다.

  8. UWP 앱 pch.h 의 파일에 라이브러리의 헤더 파일을 포함합니다.

    #include "..\Giraffe\giraffe.h"
    
  9. 함수를 호출하고 DLL에서 형식을 만드는 코드를 UWP 프로젝트에서 일반적인 방식으로 추가합니다.

    MainPage::MainPage()
    {
        InitializeComponent();
        GiraffeFactory gf;
        Giraffe* g = gf.Create();
        int id = g->GetID();
    }
    

UWP 앱에서 네이티브 C++ 정적 라이브러리 사용

UWP 프로젝트에서 네이티브 C++ 정적 라이브러리를 사용할 수 있지만 알아두어야 할 몇 가지 제한 사항이 있습니다. C++/CX의 정적 라이브러리에 대한 내용을 읽고 시작합니다. UWP 앱에서 정적 라이브러리의 네이티브 코드에 액세스할 수 있지만 이러한 정적 라이브러리에서는 공용 ref 형식을 만들지 않는 것이 좋습니다. /ZW 옵션을 사용하여 정적 라이브러리를 컴파일하는 경우 라이브러리 관리자(실제로는 가장된 링커)는 다음과 같이 경고합니다.

LNK4264: /ZW로 컴파일된 개체 파일을 정적 라이브러리에 보관합니다. Windows 런타임 형식을 작성할 때는 Windows 런타임 메타데이터를 포함하는 정적 라이브러리와 연결하지 않는 것이 좋습니다.

그러나 을 사용하여 다시 컴파일하지 않고 UWP 앱에서 정적 라이브러리를 /ZW사용할 수 있습니다. 라이브러리는 참조 형식을 선언하거나 C++/CX 구문을 사용할 수 없습니다. 그러나 네이티브 코드 라이브러리를 사용하는 것이 목적인 경우 다음 단계를 수행하여 수행할 수 있습니다.

UWP 프로젝트에서 네이티브 C++ 정적 라이브러리를 사용하려면

  1. UWP 프로젝트의 프로젝트 속성에 있는 왼쪽 창에서 구성 속성>링커>입력을 선택합니다. 오른쪽 창에서 추가 종속성 속성의 라이브러리에 경로를 추가합니다. 예를 들어 프로젝트의 출력 <SolutionFolder>\Debug\MyNativeLibrary\MyNativeLibrary.lib을 배치하는 라이브러리의 경우 상대 경로를 Debug\MyNativeLibrary\MyNativeLibrary.lib추가합니다.

  2. 필요에 따라 파일(있는 경우) 또는 파일에 .cpp 헤더 파일을 참조하는 pch.h include 문을 추가하고 라이브러리를 사용하는 코드 추가를 시작합니다.

    #include "..\MyNativeLibrary\MyNativeLibrary.h"
    

    솔루션 탐색기 참조 노드에 참조추가하지 마세요. 해당 메커니즘은 Windows 런타임 구성 요소에만 적용됩니다.

Windows 런타임 구성 요소로 C++ 라이브러리 포팅

UWP 앱에서 정적 라이브러리의 네이티브 API를 사용하려는 경우를 가정해 보겠습니다. 네이티브 라이브러리에 대한 소스 코드가 있는 경우 코드를 Windows 런타임 구성 요소로 이식할 수 있습니다. 더 이상 정적 라이브러리가 아닙니다. C++ UWP 앱에서 사용할 수 있는 DLL로 전환합니다. 이 절차에서는 C++/CX 확장을 사용하는 새 Windows 런타임 구성 요소를 만드는 방법을 설명합니다. 대신 C++/WinRT를 사용하는 구성 요소를 만드는 방법에 대한 자세한 내용은 C++/WinRT를 사용하여 Windows 런타임 구성 요소를 참조하세요.

C++/CX를 사용하는 경우 모든 UWP 앱 코드의 클라이언트에서 사용할 수 있는 ref 형식 및 기타 C++/CX 구문을 추가할 수 있습니다. C#, Visual Basic 또는 JavaScript에서 이러한 형식에 액세스할 수 있습니다. 기본 절차는 다음과 같습니다.

  • Windows 런타임 구성 요소(유니버설 Windows) 프로젝트를 만듭니다.
  • 정적 라이브러리에 대한 코드를 복사하고
  • 는 옵션으로 인해 발생하는 컴파일러의 오류를 해결합니다 /ZW .

Windows 런타임 구성 요소로 C++ 라이브러리를 이식하려면

  1. Windows 런타임 구성 요소(유니버설 Windows) 프로젝트를 만듭니다.

  2. 프로젝트를 닫습니다.

  3. Windows 파일 탐색기 새 프로젝트를 찾습니다. 그런 다음 포트하려는 코드가 포함된 C++ 라이브러리 프로젝트를 찾습니다. C++ 라이브러리 프로젝트에서 원본 파일(헤더 파일, 코드 파일 및 하위 디렉터리에 포함된 기타 리소스)을 복사합니다. 새 프로젝트 폴더에 붙여넣어 동일한 폴더 구조를 유지합니다.

  4. Windows 런타임 구성 요소 프로젝트를 다시 엽니다. 솔루션 탐색기 프로젝트 노드의 바로 가기 메뉴를 열고 기존 항목 추가>를 선택합니다.

  5. 원래 프로젝트에서 추가할 모든 파일을 선택하고 확인을 선택합니다. 필요한 경우 하위 폴더를 대상으로 반복합니다.

  6. 이제 중복된 일부 코드가 있을 수도 있습니다. 미리 컴파일된 헤더(예: 둘 다 stdafx.hpch.h)가 두 개 이상 있는 경우 유지할 헤더를 선택합니다. 유지할 헤더에 include 문과 같은 필요한 코드를 복사합니다. 그런 다음 다른 헤더를 삭제하고 프로젝트 속성의 미리 컴파일된 헤더 아래에서 헤더 파일의 이름이 올바른지 확인합니다.

    미리 컴파일된 헤더로 사용할 파일을 변경한 경우 각 파일에 대한 미리 컴파일된 헤더 옵션이 올바른지 확인합니다. 각 .cpp 파일을 차례로 선택하고 속성 창을 열고 미리 컴파일된 헤더를 제외하고 모두 사용(/Yu)으로 설정되었는지 확인합니다. 이 헤더는 만들기(/Yc)로 설정해야 합니다.

  7. 프로젝트를 빌드하고 모든 오류를 해결합니다. 이러한 오류는 옵션을 사용하여 /ZW 발생하거나 새 버전의 Windows SDK로 인해 발생할 수 있습니다. 또는 라이브러리에 종속된 헤더 파일과 같은 종속성 또는 이전 프로젝트와 새 프로젝트 간의 프로젝트 설정 차이점을 반영할 수 있습니다.

  8. 프로젝트에 public ref 형식을 추가하거나 일반 형식을 ref 형식으로 변환합니다. 이러한 유형을 사용하여 UWP 앱에서 호출하려는 기능에 진입점을 노출합니다.

  9. UWP 앱 프로젝트에서 구성 요소에 대한 참조를 추가하여 구성 요소를 테스트하고 만든 공용 API를 호출하는 코드를 추가합니다.

참고 항목

유니버설 Windows 플랫폼으로 포팅