[wp_ad_camp_1]
1. 개요
WPF기반에 Bluetooth Low Energy 관련하여 프로젝트를 하게 되었다.
응용프로그램에 Bluetooth 통신을 하려면 관련 Library의 집합체인 Bluetooth Stack 이라는 것을 활용해야 했다.
현재 사용할 수 있는 Bluetooth Stack은 아주 제한적이며 몇개 되지도 않았다. 그나마 범용적으로 사용할 수 있는게 Microsoft Bluetooth Stack.
하지만 이 녀석은 Windows 10 의 UWP 에서만 제공이 되었다.
그리하여 UWP가 아닌 C# 프로젝트에서 UWP를 사용할 수 있는 방법을 찾게 되어 정리한다.
2. 방법
크게 2가지 방법이 있다. 하나는 Project의 정보를 수정하여 UWP API를 사용하는 방법. 하나는 winmd 파일을 참조하는 방법. 일단 UWP 플랫폼이 아닌(물론 Xamarin도 아닌) 프로젝트를 하나 생성한다. 난 WPF로 하겠다.
2.1. *.csproj 파일 수정
프로젝트의 여러 정보가 담긴 파일인 *.csproj 파일편집을 위하여 별도의 메모장이나 텍스트에디트 프로그램으로 *.csproj 파일을 열어서 수정해도 되지만, Visual Studio에서 바로 수정도 가능하다.
솔루션탐색기에서 수정하고자 하는 프로젝트에 마우스 오른쪽 클릭하여 나타난 Context Menu 중에 ‘프로젝트 언로드(L)’를 클릭한다.
그러면 열려 있었던 프로젝트가 닫히면서 솔루션 탐색기에 ‘프로젝트명(사용할 수 없음)’ 으로 표시된다.
이 상태에서 다시 Context Menu를 열어 ‘편집 프로젝트명.csproj’ 메뉴를 선택한다.
프로젝트의 정보가 담긴 xml 파일을 편집할 수 있다.
이것 저것 많은 정보가 있지만 넘어가고, Project Element의 하위에 아래 정보를 추가한다.
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <TargetPlatformVersion>10.0</TargetPlatformVersion> </PropertyGroup> <Import Project> .....
저장 후, xml 편집기를 닫고, 솔루션 탐색기에서 프로젝트의 Context Menu를 열어 ‘프로젝트 다시 로드’ 메뉴를 선택한다.
일단, 정상적으로 빌드가 되는지 확인한다. xml 내용이 올바르지 않거나 수정이 잘못되었다면, 프로젝트가 로드되지않거나 빌드되지 않으니 주의하도록 한다.
빌드가 잘 되는지 확인하였다면, 솔루션 탐색기의 프로젝트의 참조 노드에서 Context Menu를 열어 ‘참조 추가’를 선택한다.
자주 보던 참조관리자가 열린다. 하지만, 처음보는 메뉴가 생겼다. ‘Universal Windows’!
‘핵심’ 노드를 선택하여 Windows를 체크하고, ‘확인’ 버튼을 눌러 참조를 추가한다.
아직 끝난게 아니다. UWP의 다양한 API들은 async / await 를 통하여 비동기 방식을 사용한다. UWP의 async / await와 None-UWP (WPF)의 async / await가 어떠한 차이가 있는지 알수는 없지만, UWP의 async / await 문법을 사용하려면 System.Runtime.WindowsRuntime.dll을 추가하여야 한다. 전체경로는
‘c:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5\System.Runtime.WindowsRuntime.dll’이다.
이로써 UWP API 사용을 위한 준비가 끝났다.
UWP API 가 정상동작 하는지 ‘Windows.Devices.Enumeration.DeviceWatcher’ 클래스를 사용하여 현재 시스템에 설치된 Device를 가져오는 코드를 샘플로 작성하였다.
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { Windows.Devices.Enumeration.DeviceWatcher watcher = Windows.Devices.Enumeration.DeviceInformation.CreateWatcher(); watcher.Added += Watcher_Added; watcher.Start(); } private async void Watcher_Added(Windows.Devices.Enumeration.DeviceWatcher sender, Windows.Devices.Enumeration.DeviceInformation args) { var deviceThumbnail = await args.GetThumbnailAsync(); using (deviceThumbnail) { Console.WriteLine($"Watcher_Added. [{args.Name}] Thumbnail Size={deviceThumbnail.Size}"); } } }
빌드 후 실행하여 출력창을 확인하면 정상적으로 동작하는 것을 확인할 수 있다.
[wp_ad_camp_1]
2.2. *.winmd 파일 참조 추가
보다 더 간단하게 UWP API를 사용하는 방법이 있다. 바로 Windows.winmd 파일을 프로젝트에 참조로 추가하는 방법이다.
전체 경로는
‘C:\Program Files (x86)\Windows Kits\10\UnionMetadata\Windows.winmd’ 이다.
*.winmd 라는 확장자를 가진 파일을 참조추가 할 수 있다는 걸 이번에 처음 알았다.
위에서 했던 두번째 작업인 ‘System.Runtime.Windows.Runtime.dll’ 파일을 역시 참조에 추가한다.
끝! (응? 정말 간단하지 않은가?)
위에서 샘플로 작성한 코드를 복사하여 빌드, 실행 해보자. 정상 동작하는 것을 확인할 수 있다.
3.정리
두가지 방법중 첫번째 방법으로 프로젝트에 적용하여 사용중이었지만, dll 충돌이 일어난다던가 하는 자잘한 문제로 고생이 많았다. Windows.winmd 파일을 참조하여 사용하길 권한다.
전 회사에서 OCR 관련 라이브러리가 필요하였었는데, UWP API에 있는 OCR API를 사용했어도 좋았을 것 같다. Tesseract 라는 Open source를 사용하였으나, UWP의 OCR API 보다는 성능이 낮았다.
이제 UWP에서만 가능하던 모든 기능을 스토어 앱이 아닌 일반 앱에서 사용가능해 졌으니, 개인프로젝트의 플랫폼 선택에서 조금 더 자유로워 진 것 같다.
[wp_ad_camp_1]
안녕하세요. 당사의 기존에 있던 프로젝트에서 기능 추가개발을 하게 되었습니다.
그러나 당사의 기존 프로젝트는 C# Winform 기반입니다. Winform에도 UWP API와 async / await 문법을 사용할 수 있나요?
.NET Framework 4.5 이상이면 사용할 수 있습니다~ Console 어플리케이션도 UWP API를 사용할수 있는걸요. ㅎ
자세한 사항은 아래 링크 참조하세요~
https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/async/