Windows 런타임 구성 요소로 멋진 Metro 스타일 앱 만들기

Windows 8 앱 개발자 블로그

Windows 8 엔지니어링 팀에서 제공하는 Windows 8용 Metro 스타일 앱 개발의 이해

Windows 런타임 구성 요소로 멋진 Metro 스타일 앱 만들기

  • Comments 0

Windows 8은 지금까지와는 전혀 다른 발상으로 접근한 플랫폼입니다. 따라서 개발자는 자신에게 익숙한 프로그래밍 언어와 기술을 선택하여 Windows 8 장치와 폼 팩터에 맞는 앱을 개발할 수 있습니다. 또한 Windows 런타임 덕분에 하나의 앱을 개발할 때도 여러 언어를 편리하게 사용할 수 있습니다. 그리고 C++를 이용해 자신만의 Windows 런타임 구성 요소를 만들어 Xbox 360 컨트롤러와 상호 작용하는 멋진 Metro 스타일 앱을 HTML과 JavaScript로 작성할 수 있습니다. 뿐만 아니라 C++와 C#으로 작성된 Metro 스타일 앱에서 바로 사용할 수 있는 Windows 런타임 구성 요소를 통해 노출된 재사용 가능 XAML 컨트롤러를 만들 수 있습니다. Windows 8 플랫폼은 기본적으로 개발자가 원하는 언어를 사용하여 앱을 개발할 수 있는 환경을 제공합니다.

이 글에서는 Windows 런타임 구성 요소를 구축하기 위해 알아야 할 내용을 설명하겠습니다.

기본 사항

Windows 런타임은 개발자가 원하는 언어를 선택할 수 있게 해주는 핵심 요소입니다. Windows 런타임이 노출되면 자연스럽고 친숙한 방식으로 JavaScript, C++, C#, Visual Basic에서 불러올 수 있습니다. 자신만의 API를 만들 때도 이와 동일한 기반을 사용하게 됩니다.

개발자의 앱에서 만들고 패키징한 Windows 런타임 구성 요소는 일반적으로 제3자 Windows 런타임 구성 요소라고 부릅니다. 이 구성 요소는 이미 Windows 8 플랫폼의 일부가 된 자사 구성 요소와는 차이가 있으며, 개발자는 C++, C#, Visual Basic으로 제3자 Windows 런타임 구성 요소를 작성할 수 있습니다. 그리고 앱에 패키징된 기타 Windows 런타임 구성 요소 등을 어디에서든 노출되는 곳에서 API로 불러올 수 있습니다. 또한 어떤 언어에서든 Windows 런타임 구성 요소를 통해 노출된 API로 불러올 수 있습니다.

Metro 스타일 앱 개발에 대한 지원이 계속되는 한 앱에 작성한 Windows 런타임 구성 요소에서 Windows 런타임 API, Win32, COM, .NET API, 제3자 라이브러리를 사용할 수 있습니다. 단, 개발자가 만든 Windows 런타임 구성 요소는 API를 노출시키는 C++ DLL이나 .NET 어셈블리 등 일반적으로 알려진 요소와는 다르다는 사실을 기억해 두시기 바랍니다. 다시 말해 .NET에서 클래스 라이브러리를 만들거나 C++에서 독립 실행형 DLL을 만드는 것은 Windows 런타임 구성 요소를 만드는 것과는 다릅니다. Windows 런타임 구성 요소는 Windows 런타임 API(예: JavaScript에 노출된 API를 위한 pascalCasedNames 지원)를 자연스럽게 사용하기 위해 Windows 런타임 메타데이터를 노출하는 .wnmd 파일로 선언되어 JavaScript와 같은 언어를 사용하게 됩니다. 또한 Windows 런타임 메타데이터를 통해 Visual Studio는 IntelliSense 지원과 같은 뛰어난 도구 기능을 제공할 수 있습니다.

나만의 Windows 런타임 구성 요소를 만들어야 하는 이유

Windows 런타임 구성 요소를 생성하는 것은 재사용 가능성과 언어 상호 운용성을 구축하는 데 도움이 됩니다. 이제 몇 가지 앱 시나리오를 살펴보면서 제3자 Windows 런타임 구성 요소를 사용하여 더 나은 경험을 구현하는 방법을 알아보겠습니다.

Windows용 Xbox 360 컨트롤러를 Metro 스타일 앱에 통합할 수 있습니다.
그림 1: Xbox 360 컨트롤러

Metro 스타일 앱에서 Win32와 COM API 사용하기

Internet Explorer 10에서 제공하는 플랫폼을 통해 HTML, CSS, JavaScript를 사용하여 Metro 스타일 앱 경험을 구현할 수 있습니다. 그렇지만 HTML5 캔버스를 사용하여 게임을 만들고 Windows용 Xbox 360 컨트롤러와 통합하고 싶다면 어떻게 해야 할까요? 앱이 컨트롤러에서 입력을 받을 수 있게 해주는 XInput API는 JavaScript에 직접 사용할 수 없는 Win32 API를 노출합니다.

이는 Windows 런타임 구성 요소를 만들어 이 문제를 해결하고 Metro 스타일 앱 기반의 HTML에서 XInput API를 사용할 수 있다는 것을 보여주는 좋은 예입니다. 이러한 XInput과 JavaScript 컨트롤러 스케치 샘플을 통해 이를 정확히 확인할 수 있습니다. 이 샘플 앱에는 XInput API에서 노출된 기능을 래핑하는 C++로 작성된 게임 컨트롤러 Windows 런타임 구성 요소가 있습니다. HTML 기반의 컨트롤러 스케치 앱은 Xbox 360 컨트롤러와의 상호 작용을 가능하게 하기 위해 게임 컨트롤러 C++ Windows 런타임 구성 요소를 사용합니다.

이 시나리오는 HTML과 JavaScript만을 사용하여 구현하는 것이 불가능하며, 제3자 Windows 런타임 구성 요소를 만들면 다른 방법으로는 불가능한 복잡한 시나리오를 구현할 수 있다는 것을 보여주는 완벽한 예입니다.

고도의 계산이 필요한 작업

과학, 기술 및 지도/지리와 같은 분야의 앱은 흔히 고도의 계산이 필요한 작업입니다. 이러한 고도의 작업은 강력한 병렬 처리가 요구되고 최적의 성과를 얻으려면 C++가 안성맞춤입니다. JavaScript와 C++로 Metro 스타일 앱인 Bing Maps Trip Optimizer 개발에서는 C++에서 Windows 런타임 구성 요소를 생성하여 앱에서 최적의 사용 환경을 구축할 수 있는 또 다른 시나리오를 확인할 수 있습니다.

Bing 서버의 클라우드에서 이처럼 고도의 계산이 필요한 작업을 실행할 수 있다면 왜 로컬 데이터로 여행 경로를 전부 계산해야 하는지 의문이 생길 수 있습니다. Bing Maps에서는 이를 위해 JavaScript API를 노출하지만 경우에 따라 앱을 오프라인에서 실행해야 할 때도 있습니다. 아울러 우리는 사용자가 터치하여 실시간으로 경로를 끌어다 변경할 수 있기를 바랍니다. 이러한 고도의 작업을 로컬에서 실행할 수 있다면 보다 향상된 경험을 구현할 수 있습니다.

병렬 작업 라이브러리를 사용하여 C++에서 고도의 계산이 필요한 작업을 작성함으로써 클라이언트의 성능을 활용하여 사용자를 위한 멋진 경험을 구현할 수 있습니다. Windows 런타임은 이 시나리오에 가장 이상적입니다. 즉, 병렬화로 순식간에 계산하는 C++ 코드를 사용하는 고도의 경로 작업 전체를 실행하는 동안 Bing Maps AJAX 컨트롤을 사용하여 HTML과 JavaScript에서 풍부한 클라이언트 UI를 생성할 수 있습니다.

라이브러리

이 커뮤니티에는 누구나 사용할 수 있도록 개발자들이 제공한 멋진 라이브러리들로 가득합니다. 과거에는 앱이 구현된 프로그래밍 언어와 일치하지 않는 경우 라이브러리를 재사용하기가 어려웠습니다. 예를 들어, 아무리 좋은 .NET 앱을 만들어도 PInvoke와 같은 인터롭 후프를 사용해야만 C++에서 작성한 라이브러리를 사용할 수 있었습니다.

하지만 Windows 런타임 덕분에 Windows 8에서는 이러한 언어 간의 장벽이 허물어졌습니다. 그에 따라, 구성 요소의 언어나 앱의 주요 프로그래밍 언어가 무엇인지에 관계없이 단일 코드 기준의 단일 Windows 런타임 구성 요소 라이브러리를 수많은 개발자들이 사용할 수 있게 되었습니다.

이제 C++와 C# 앱 개발자 모두가 사용할 수 있는 사용자 지정 컨트롤의 단일 Windows 런타임 노출 XAML 라이브러리를 만드는 것이 가능합니다. 또한 XAML이나 HTML 기반의 Metro 스타일 앱에서 개발자들이 공유한 다양한 데이터 저장소 Windows 런타임 라이브러리를 사용할 수 있습니다. 인터롭 코드를 작성할 필요 없이 이 모든 시나리오가 가능합니다.

Windows 런타임은 개발자가 Metro 스타일 앱 개발자 커뮤니티에서 만들고 널리 공유하는 라이브러리에 유용하게 사용될 것입니다. 이제 C++/CX와 C#에서 제3자 Windows 런타임 구성 요소를 만드는 기본적인 방법을 두 가지 예를 들어 살펴보겠습니다.

시나리오 1: 네이티브 오디오로 앱 향상시키기

C#으로 작성한 앱 로직을 기반으로 하는 XAML을 사용하여 소프트웨어 신시사이저 앱을 만든다고 가정해 보겠습니다. 음악 앱에 필터 지원을 추가하려면 오디오 버퍼를 직접 컨트롤하기 위해XAudio를 사용해야 할 것입니다.

솔루션에 Windows 런타임 구성 요소 추가하기

Visual Studio를 사용하여 기존의 솔루션에 새로운 C++ Windows 런타임 구성 요소 프로젝트를 추가합니다. 이 Windows 런타임 구성 요소는 다음과 같이 음악 프로세싱 기능을 래핑합니다.

새로운 C++ Windows 런타임 구성 요소 추가하기
그림 2: 새로운 C++ Windows 런타임 구성 요소 추가하기

Visual Studio에서 생성되어 C++ 구현 작업을 DLL로 패키지하고 Windows 런타임 메타데이터�� winmd 파일로 패키지할 수 있도록 API를 노출할 수 있습니다. 두 가지 모두 C# 프로젝트에서 사용할 수 있습니다.

XAML C# 프로젝트에 노출된 클래스 정의하기

우리는 C# 프로젝트에 노출시킬 API를 만들기 위해 C++/CX를 사용하지만 여러분은 Windows 런타임 C++ 템플릿 라이브러리(WRL)를 사용할 수도 있습니다. XAudio 기능을 캡슐화할 수 있는 아주 기본적인 클래스를 정의하는 것으로 시작합니다.

XAudioWrapper.h

#pragma once

#include "mmreg.h"
#include <vector>
#include <memory>

namespace XAudioWrapper
{
public ref class XAudio2SoundPlayer sealed
{
public:
XAudio2SoundPlayer(uint32 sampleRate);
virtual ~XAudio2SoundPlayer();

void Initialize();

bool PlaySound(size_t index);
bool StopSound(size_t index);
bool IsSoundPlaying(size_t index);
size_t GetSoundCount();

void Suspend();
void Resume();

private:
interface IXAudio2* m_audioEngine;
interface IXAudio2MasteringVoice* m_masteringVoice;
std::vector<std::shared_ptr<ImplData>> m_soundList;
};
}

여러분은 먼저 클래스 선언에서 공용, ref, 봉인 키워드가 사용된다는 사실을 발견하게 될 것입니다. Metro 스타일 앱에서 JavaScript나 C#과 같은 다른 언어로부터 인스턴스화되어야 하는 클래스는 봉인된 공용 ref 클래스로 선언해야 합니다.

클래스의 공용 기능(메서드, 속성 등)은 C++ 기본 제공 형식이나 Windows 런타임 형식으로 제한됩니다. Windows 런타임 구성 요소에서 언어의 경계를 넘나들 수 있는 형식은 이러한 것들뿐입니다. 따라서 이 코드 조각에 나타난 대로 클래스의 전용 데이터 멤버에는 일반적인 C++ 라이브러리를 사용할 수 있습니다(예: 표준 템플릿 라이브러리 컬렉션). 이러한 전용 데이터 멤버에서는 언어의 경계를 넘어서는 규칙을 따를 필요가 없습니다. 지원되지 않는 구문을 사용할 경우 Visual Studio 컴파일러에서 오류 메시지를 표시하고 지침을 제공합니다.

Windows 런타임 구성 요소에 노출된 클래스 구현하기

클래스에 대해 기본 인터페이스를 정의했으므로 이제 몇 가지 구현 방법을 살펴보도록 하겠습니다.

XAudioWrapper.cpp

XAudio2SoundPlayer::XAudio2SoundPlayer(uint32 sampleRate) :
m_soundList()
{
// Create the XAudio2 engine
UINT32 flags = 0;

XAudio2Create(&m_audioEngine, flags);

// Create the mastering voice
m_audioEngine->CreateMasteringVoice(
&m_masteringVoice,
XAUDIO2_DEFAULT_CHANNELS,
sampleRate
);
}

void XAudio2SoundPlayer::Resume()
{
m_audioEngine->StartEngine();
}

bool XAudio2SoundPlayer::PlaySound(size_t index)
{
//
// Setup buffer
//
XAUDIO2_BUFFER playBuffer = { 0 };
std::shared_ptr<ImplData> soundData = m_soundList[index];
playBuffer.AudioBytes = soundData->playData->Length;
playBuffer.pAudioData = soundData->playData->Data;
playBuffer.Flags = XAUDIO2_END_OF_STREAM;

HRESULT hr = soundData->sourceVoice->Stop();
if (SUCCEEDED(hr))
{
hr = soundData->sourceVoice->FlushSourceBuffers();
}

//
// Submit the sound buffer and (re)start (ignore any 'stop' failures)
//
hr = soundData->sourceVoice->SubmitSourceBuffer(&playBuffer);
if (SUCCEEDED(hr))
{
hr = soundData->sourceVoice->Start(0, XAUDIO2_COMMIT_NOW);
}

return SUCCEEDED(hr);
}

이 코드 조각에서는 Metro 스타일 앱 개발에 사용할 수 있는 XAudio2 COM API만을 사용하여 오디오 엔진으로 연결하고 사운드를 재생하며 엔진을 다시 시작합니다. 더불어 단순한 Windows 런타임 형식을 뛰어넘은 C++ 구문과 형식을 사용하여 필요한 기능을 구현하는 것이 가능합니다.

Windows 런타임 구성 요소 추가 및 사용하기

기본 클래스를 정의하고 구현한 다음 Visual Studio를 사용하여 XAudioWrapper Windows 런타임 구성 요소를 C# 프로젝트에서 C++ 프로젝트로 추가합니다.

Visual Studio 사용하여 음악 앱에 있는 XAudioWrapper Windows 런타임 구성 요소에 참조 추가하기

그림 3: 음악 앱에 XAudioWrapper Windows 런타임 구성 요소 추가하기

그 결과, C++ 프로젝트로부터 노출한 클래스를 C # 프로젝트에서 사용할 수 있게 됩니다.

MainPage.cs

using XAudioWrapper;

namespace BasicSoundApp
{
public sealed partial class MainPage : Page
{
XAudio2SoundPlayer _audioPlayer = new XAudio2SoundPlayer(48000);
public MainPage()
{
this.InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
_audioPlayer.Initialize();
}

private void Button_Click_1(object sender, RoutedEventArgs e)
{
_audioPlayer.PlaySound(0);
}
}
}

코드 조각에 나타난 것과 같이 일반적인 .NET 구성 요소와 마찬가지로 C#의 XAudio 래퍼와 상호 작용할 수 있습니다. 네임스페이스를 참조하여 구성 요소를 인스턴스화하고 여기에서 노출되는 다양한 메서드를 호출하기 시작합니다. 이 모든 작업이 네이티브 코드를 호출하는 어떤 DllImport 없이도 가능합니다!

시나리오 2: 앱의 압축 파일을 열기 위해 기본 제공 API 사용하기

HTML을 사용하여 파일 뷰어 앱을 만드는 동시에 해당 앱의 사용자가 압축 파일을 선택할 수 있는 기능을 추가한다고 가정해 보겠습니다. 우리는 이미 Windows에 빌드되고 압축 파일 처리을 위해 .NET 플랫폼에 노출된 API를 사용할 것입니다.

솔루션에 Windows 런타임 구성 요소 추가하기

음악 앱과 관련하여 설명한 것과 동일한 단계이지만 이번에는 Windows 런타임 구성 요소를 선택하여 압축 파일 처리 기능을 래핑합니다.

Visual Studio를 사용하여 파일 뷰어 앱에 새로운 C# Windows 런타임 구성 요소 추가하기
그림 4: 새로운 C# Windows 런타임 구성 요소 추가하기 

Visual Studio에서 C# 프로젝트가 생성되어 구현 메타데이터와 Windows 런타임 메타데이터가 모두 .winmd 파일로 패키지되도록 API를 노출하고 웹 프로젝트에서 사용할 수 있습니다.

Windows 런타임 구성 요소에 노출된 클래스 구현하기

웹 프로젝트에 노출할 API를 노출하기 위해 우리는 C#을 사용하지만 여러분은 Visual Basic을 사용할 수도 있습니다. 압축 기능을 캡슐화할 수 있는 단순한 C#을 정의하는 것에서 시작합니다.

ZipWrapper.cs

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.Storage;

public sealed class ZipWrapper
{
public static IAsyncOperationWithProgress<IList<string>, double> EnumerateZipFileAsync(StorageFile file)
{
return AsyncInfo.Run(async delegate(
System.Threading.CancellationToken cancellationToken, IProgress<double> progress)
{
IList<string> fileList = new List<string>();
progress.Report(0);

using (var stream = await file.OpenStreamForReadAsync())
{
using (var archive = new ZipArchive(stream))
{
for (int i = 0; i < archive.Entries.Count; i++)
{
// add code for processing/analysis on the file
// content here

// add to our list and report progress
fileList.Add(archive.Entries[i].FullName);
double progressUpdate = ((i + 1) / ((double)archive.Entries.Count)) * 100; // percentage
progress.Report(progressUpdate);
}
}
}

progress.Report(100.0);
return fileList;
});
}
}

이 클래스는 공용이며 봉인되어 있습니다. 이는 C++ Windows 런타임 구성 요소를 작성할 때와 마찬가지로 다른 언어에서 클래스를 인스턴스화하기 위해 필요합니다. 클래스에 노출된 정적 메서드는 혼합된 Windows 런타임 형식(StorageFile 등)과 메서드 시그니처의 .NET 형식(IList 등)을 사용합니다. 경험상, 다른 언어로 노출할 공용 필드, 매개 변수, 반환 형식을 정의하려면 Windows 런타임을 사용하는 것이 좋습니다. 따라서 특정 .NET 기본 형식을 사용하는 것이 가능합니다(예: DateTimeOffset and Uri). 또한 기본 형식을 그대로 사용할 수도 있습니다(예: IList).

여러분은 위의 메서드가 Windows 런타임 구성 요소를 정의할 때 사용할 수 있는(사용해야 하는) 비동기 지원 및 진행 지원을 위한 Windows 런타임 인프라를 활용한다는 사실도 발견하게 될 것입니다. Windows 런타임 구성 요소를 위한 구현이나 클래스의 모든 전용 기능에 대해서 만큼은 Windows 런타임 형식과 API만 사용하도록 제한되지 않습니다. 코드 조각 ZipArchive API에 나타난 것처럼 Metro 앱 개발을 위해 노출된 .NET API 화면 중 어느 것을 사용해도 무방합니다.

Windows 런타임 구성 요소 추가 및 사용하기

압축 도구 래퍼를 구현했으므로 이제 Visual Studio를 사용하여 JavaScript 프로젝트에서 C# 프로젝트로 참조를 추가합니다.

Visual Studio 사용하여 파일 뷰어 앱에 있는 ZipUtil Windows 런타임 구성 요소에 참조 추가하기
그림 5: 파일 뷰어 앱에 ZipUtil Windows 런타임 구성 요소 추가하기

그 결과, C# 프로젝트로부터 노출된 클래스를 웹 프로젝트에서 사용할 수 있게 됩니다.

program.js

function pickSinglePhoto() {

// Create the picker object for picking zip files
var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.viewMode = Windows.Storage.Pickers.PickerViewMode.thumbnail;
openPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary;
openPicker.fileTypeFilter.replaceAll([".zip"]);

// Open the picker for the user to pick a file
openPicker.pickSingleFileAsync().then(function (file) {
if (file) {
ZipUtil.ZipWrapper.enumerateZipFileAsync(file).then(
function (fileList) {
for (var i = 0; i < fileList.length; i++)
document.getElementById('output').innerHTML += " " + fileList[i];
},
function (prog) {
document.getElementById('zipProgress').value = prog;
}
);
} else {
document.getElementById('output').innerHTML = "an error occurred";
}
});
};

보시다시피, 일반적인 JavaScript 개체와 마찬가지로 JavaScript의 압축 도구와 상호 작용할 수 있습니다. Windows 런타임 구성 요소에 노출된 정적 메서드를 호출할 수 있으며 .then()처럼 JavaScript의 비동기 언어 구문을 사용하여 동일한 작업을 수행할 수도 있습니다.

일반 지침

Metro 스타일 앱을 위해 작성하는 모든 API가 제3자 Windows 런타임 구성 요소로 노출되어서는 안 됩니다. 대개의 경우에는 프로그래밍 언어 간의 통신을 할 때 Windows 런타임 형식을 사용하고 Windows 런타임 구성 요소를 통해 공개적으로 노출되지 않은 기능에 사용한 언어로 작성된 형식과 구문을 사용합니다. 또한 Windows 런타임 구성 요소를 작성할 때 고려해야 하는 언어의 경계를 넘나드는 다양한 언어 관련 기능과 규칙이 존재합니다. 여기에는 대리자와 이벤트, 비동기 작업, 메서드 오버로드, 컬렉션과 같은 특정 데이터 형식 처리, 처리 해제와 디버깅 팁 등이 포함됩니다. 개발 언어와 관련하여 Windows 런타임 구성 요소 생성하기의 섹션을 방문하면 해당 주제에 대해 보다 자세한 정보를 얻을 수 있습니다.

결론

이제 Windows 런타임 구성 요소를 사용하면 프로그래밍 언어와 API 기술들을 조합하여 개발자가 원하는 앱을 만들 수 있습니다. Windows 8은 개발자를 위한 완벽한 환경을 제공합니다. 어떤 장점도 포기하지 않는 완벽한 개발 환경을 제공하기 때문에 개발자의 시나리오에 가장 적합한 프로그래밍 언어를 조합하고 적용하는 것이 가능합니다. 이로써 개발자는 혁신적인 아이디어를 떠올리는 데 더 집중할 수 있으며, 새로운 프로그래밍 언어를 완전히 익히는 데 걸리는 시간을 크게 줄일 수 있습니다.

멋진 앱을 구축해 보시기 바랍니다!

- Windows 프로그램 관리자, Ines Khelifi

참조

이번 글은 Windows 런타임 구성 요소를 만들면 무엇이 가능한지를 간략하게 살펴보았습니다. 다음에는 앱을 개발하는 데 도움이 되는 내용을 보다 자세히 알아보겠습니다.

  • Loading...
Leave a Comment
  • Please add 5 and 5 and type the answer here:
  • Post