.NET 5 응용 프로그램에서 WinRT API 호출
이번 글은 다음의 내용에 대한 실습입니다.
Calling Windows APIs in .NET5
; https://blogs.windows.com/windowsdeveloper/2020/09/03/calling-windows-apis-in-net5/
예전에도 이에 대한 소개를 몇 번 했는데요,
일반 닷넷 프로젝트에서 WinRT API를 호출하는 방법
; https://www.sysnet.pe.kr/2/0/1508
윈도우 데스크톱 응용 프로그램(예: Console)에서 알림 메시지(Toast notifications) 띄우기
; https://www.sysnet.pe.kr/2/0/11073
데스크톱 윈도우 응용 프로그램에서 UWP 라이브러리를 이용한 비디오 장치 열람하는 방법
; https://www.sysnet.pe.kr/2/0/11284
.NET 5의 경우 Preview 8부터 새로운 TFM(Target Framework Monikers)을 추가해 별도의 NuGet 라이브러리 참조 없이 연동하게 만들었다고 합니다.
간단하게 실습을 해보면, .NET 5 대상의 Windows Forms 프로젝트를 만든 후, TargetFramework에 다음과 같이 "net5.0-windows10..." TFM을 지정하면 됩니다.
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows10.0.17763.0</TargetFramework>
<UseWindowsForms>true</UseWindowsForms>
</PropertyGroup>
</Project>
TFM에 지정 가능한 버전은 (
Windows 10의 최신 버전이 19041이므로) 3가지입니다.
- 10.0.17763.0
- 10.0.18362.0
- 10.0.19041.0
이렇게 TFM을 바꾸면 프로젝트의 의존성에 "
Microsoft.Windows.SDK.NET.Ref"가 자동으로 추가됩니다. 이후 일반적인 WinRT 응용 프로그램처럼 Windows 10 API를 가져다 쓸 수 있습니다.
일례로 "
윈도우 데스크톱 응용 프로그램(예: Console)에서 알림 메시지(Toast notifications) 띄우기" 글에서 소개한 Toast 알림을 다룬 그 소스 코드 그대로 다음과 같이 복사해 쓸 수 있습니다.
using System;
using System.Windows.Forms;
using Windows.Data.Xml.Dom;
using Windows.UI.Notifications;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ShowToast($"{nameof(WindowsFormsApp1)}", DateTime.Now.ToLongTimeString(), "Test Message", null);
}
static void ShowToast(string appId, string title, string message, string image)
{
XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(
string.IsNullOrEmpty(image) ? ToastTemplateType.ToastText02 :
ToastTemplateType.ToastImageAndText02);
XmlNodeList stringElements = toastXml.GetElementsByTagName("text");
stringElements[0].AppendChild(toastXml.CreateTextNode(title));
stringElements[1].AppendChild(toastXml.CreateTextNode(message));
if (string.IsNullOrEmpty(image) == false)
{
// Specify the absolute path to an image
String imagePath = "file:///" + image;
XmlNodeList imageElements = toastXml.GetElementsByTagName("image");
imageElements[0].Attributes.GetNamedItem("src").NodeValue = imagePath;
}
ToastNotification toast = new ToastNotification(toastXml);
toast.Activated += Toast_Activated;
toast.Dismissed += Toast_Dismissed;
toast.Failed += Toast_Failed;
ToastNotificationManager.CreateToastNotifier(appId).Show(toast);
}
private static void Toast_Failed(ToastNotification sender, ToastFailedEventArgs args)
{
}
private static void Toast_Dismissed(ToastNotification sender, ToastDismissedEventArgs args)
{
}
private static void Toast_Activated(ToastNotification sender, object args)
{
}
}
}
물론, 원문 글(
Calling Windows APIs in .NET5")에서처럼
GPS 장치를 접근하는 것도 가능하고,
private async void button2_Click(object sender, EventArgs e)
{
var locator = new Windows.Devices.Geolocation.Geolocator();
var location = await locator.GetGeopositionAsync();
var position = location.Coordinate.Point.Position;
var latlong = string.Format("lat:{0}, long:{1}",
position.Latitude, position.Longitude);
MessageBox.Show(latlong);
}
(원문에서는 WPF 프로젝트였지만) 카메라 접근으로 사진 찍는 기능도 다음과 같이 쉽게 구현할 수 있습니다.
private async void button3_Click(object sender, EventArgs e)
{
// Initialize the webcam
MediaCapture captureManager = new MediaCapture();
await captureManager.InitializeAsync();
ImageEncodingProperties imgFormat = ImageEncodingProperties.CreateJpeg();
// create storage file in local app storage
StorageFile file =
await KnownFolders.CameraRoll.CreateFileAsync("TestPhoto.jpg",
CreationCollisionOption.GenerateUniqueName);
// take photo
await captureManager.CapturePhotoToStorageFileAsync(imgFormat, file);
Bitmap bitmap = new Bitmap(file.Path);
pictureBox1.Image = bitmap;
}
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
암튼, 간단해져서 좋습니다. ^^ 기존에는 System.Runtime.WindowsRuntime.dll이나 Windows.winmd 파일 등을 신경써야 했는데 이제는 단순히 적절한 TFM만 지정하는 것으로 모든 준비 작업이 끝납니다.
참고로, 하나의 프로젝트 파일로 .NET Core 3.1과 .NET 5 지원을 모두 추가할 수 있습니다. 이를 위해 프로젝트 파일만 다음과 같이 살짝 바꾸면 됩니다.
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFrameworks>netcoreapp3.1;net5.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>
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]