WinRT (Windows 런타임) 라이브러리를 만들어내면 WinMD (Windows 메타데이터)를 출력으로 내보내며 이것으로 다양한 프로그래밍 언어에서 언어 프로젝션을 사용, 이를 이용 할 수 있습니다. 허나 C++ Windows Runtime Component를 만들고 C# 프로젝트에서 그냥 참조해서 써보려고 하면 오류가 발생합니다. 이에 대해 찾아본 결과 .NET 6 이상부터는 WinMD 파일의 사용을 지원하지 않는다고 합니다.
바로 C++ Windows Runtime Component를 쓸 수는 없고, C# 프로젝션을 만들어내고 이를 이용해야 합니다. 이 과정을 한번 추후 다시 찾는 일이 없게 하기 위해 예제를 만들어 보고 실습하는 과정을 겪어보겠습니다. 이 글은 Visual Studio 2022, WinUI 3 기준으로 작업되었습니다. (Windows App SDK 설치하여 WinUI 3를 사용할 수 있는 환경은 이미 갖추었다고 보고 기술하겠습니다.)
1. 메인이 될 C# 프로젝트 만들기
New Project로 가셔서 Blank App, Packaged (WinUI 3 in Desktop) C# 을 선택합니다.
편하게 TestApp이라고 이름 짓겠습니다.
윈도우 App (UWP) 개발을 하고자 하는 것이 아니니 따로 패키지화를 하지 않고 Desktop App 으로 동작할수 있게 하단과 같이 프로젝트에서 마우스 오른쪽을 눌려 Edit Project File한 후 PropertyGroup에 다음의 내용을 추가하고 시작하였습니다. 필요없다면 Skip 해도 됩니다.
패키지되지 않은 앱으로 만듭니다.
<WindowsPackageType>None</WindowsPackageType>
Windows App SDK는 FrameWork 종속적인데 이를 빌드시 포함시킵니다.
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
빌드 설정은 Debug / x64 / TestApp (unpackaged)로 지정했습니다.
2. C++ Windows Runtime Component 만들기
New Project로 가셔서 C++ 용 Windows Runtime Component (WinUI 3)를 선택합니다. 이름은 TestLibrary라고 지었습니다. 그럼 플랫폼 최소버전 설정이 나오고 일단 기본으로 세팅합니다.
Windows Runtime Component (WinUI 3)로 선택하면 기본적으로 옵션이 활성화 되어 있지만, 그냥 WinUI 3를 사용하지 않는 Windows Runtime Component으로 만들었을 경우 다음의 옵션이 꺼져 있습니다. 프로젝트 속성에 다음 옵션을 켜서 Windows Desktop 호환이 가능하게 합니다.
기본적으로 Class.cpp, Class.h, Class.idl이 생성됩니다. 동작확인이 목적이므로 기본적으로 만들어지는 Class.cpp의 함수 MyProperty의 리턴값만 1234로 바꾸어 보겠습니다. 나중에 C#에서 해당 함수 호출 후 이 값이 제대로 들어오는지 확인 할 것입니다.
3. C# 프로젝션용 라이브러리 만들기
2번에서 만든 C++ 라이브러리는 C#에서 그대로 사용할 수 없습니다. 한번 언어 프로젝션 과정을 거쳐야 합니다. New Project로 가셔서 C# 용 Class Library (WinUI 3 in Desktop)을 선택후 TestLibraryProjection이라는 이름으로 만들겠습니다. 해당 프로젝트는 프로젝션 이외의 목적은 사용할 마음이 없기 때문에 기본 생성되는 Class1.cs는 그냥 지워줍니다. 그리고 Add Project Reference를 통해 TestLibrary의 참조를 추가합니다.
그다음 Manage NuGet Packages를 통해 Microsoft.Windows.CsWinRT를 설치합니다. 이것은 C#에서 WinRT를 사용하게 해줍니다.
또한 C#은 Build 환경이 기본적으로 Any CPU로 되어 있는데 C++은 그렇지 않으므로 TestLibrary에 맞춰서 x64 plaform으로 빌드하게 해당 프로젝트를 변경해 줍니다.
이제 Edit Project File을 통해 Project파일에 새로운 PropertyGroup을 다음과 같이 추가합니다.
<PropertyGroup>
<CsWinRTIncludes>TestLibrary</CsWinRTIncludes>
<CsWinRTGenereatedFilesDir>$(OutDir)</CsWinRTGenereatedFilesDir>
</PropertyGroup>
해당 내용은 TestLibrary namespace을 프로젝션 시켜주는 역활을 합니다.
4. TestApp C# 메인 프로그램에서 라이브러리 사용
일단 TestApp의 참조에 다음과 같이 TestLibraryProjection을 추가합니다.
또한 C# 프로젝션 프로젝트와 마찬가지로 NuGet를 통해 Microsoft.Windows.CsWinRT 를 설치합니다.
처음 빈 C# 프로젝트를 만들면 myButton 이라는 버튼이 추가되고, 해당 함수가 생기는데 그 함수를 다음과 같이 수정하여 Library 동작을 확인합니다. (MainWindow.xaml.cs 파일 수정)
private void myButton_Click(object sender, RoutedEventArgs e)
{
var obj = new TestLibrary.Class();
myButton.Content = "Valus is " + obj.MyProperty.ToString();
//myButton.Content = "Clicked";
}
이제 빌드 후 실행, 그 다음 Click Me버튼을 눌러보면 다음과 같이 Library에서 MyProperty 함수를 호출하여 그 값을 읽어서 우리가 원하는 1234가 나오는 것을 볼 수 있습니다.
만약 C++ 코드내에서 Break Point를 잡고 싶다면, TestApp의 Debug Type을 변경해 주어야 합니다. Visual Studio 2022의 경우에는 다음과 같이 TestApp 프로젝트 선택후 메뉴에 Debug->TestApp Debug Properties을 선택하시면 됩니다. 이후 나오는 Launch Profiles 창에서 Enable native cod debugging 옵션을 켜시면 됩니다.
이제 C++ 코드에서 Break Point 잡고 실행해 보시면 다음과 같이 정상적으로 Break Point가 동작함을 확인할 수 있습니다.
'C#' 카테고리의 다른 글
[C# / WinUI3] User Control에서 Property 및 Event 추가 (0) | 2023.08.28 |
---|---|
win32 API로 디스플레이 확장/복제 설정하기 (0) | 2023.04.17 |
[C#.NET] Laptop Battery 정보 얻기 (Power Status) (0) | 2022.09.26 |
[C# .NET] COM 통신 (4) | 2022.09.21 |