SlideShare a Scribd company logo
유영천 / 메이크어스 모바일
프로그래밍 언어의 F1머신 C++을
타고 Windows 10 UWP앱 개발의
세계로~
강연 목표
• UWP이 뭔지 알았다.
• UWP을 개발하고 싶다.
• UWP앱을 C++로 개발하고 싶다!
Hello UWP App!
• Windows UWP app
• C++
Minecraft
UWP(Universal Windows Platform)
• Windows Platform의 새로운 API
• 모바일과 터치,웹 억세스에 특화
• 모든 Windows Device API의 대통합
• X86/x64/ARM 지원
• Windows 8/8.1 – Metro App / Windows Store App
• Windows 10 – UWP App
UWP(Universal Windows Platform)
UWP Apps
Desktop Applications
Why UWP App?
• 배포가 쉽다.
• 별도의 디지털 서명이 필요없다.
• Windows Store에 올릴 수 있다.
• Sandbox형태로 깔끔한 설치/깔끔한 제거
• UI만들기 쉽다.
• Mobile 친화적이다.(전력관리/터치입력 등)
• Web과의 연동이 쉽다.
• 모든 Windows 10 device에서 다 돌아간다.
Why not UWP App? ( 불편한 진실)
• 기존 코드를 얼마나 재사용할 수 있을까? ( 0% – 90%)
• 이놈의 App은 되는게 없네.
• Sandbox 시스템 하에서의 권한 문제
• API규모가 실제로 작음.
• 아직 불안한 면도 있음.
• 디바이스의 모든 기능을 사용할 수 없다.
• 사실 모든 Windows 10 device간 완벽 호환도 아니다.
• Windows 10 Mobile / Windows 10간에 UWP는 거의 완벽 호환
• Windows IoT와는 부분적으로 호환.
• XBOX ONE 은 거의 100%일걸로 예상.
• Hololense는 아직 모름.
Desktop App vs UWP App
• 개발하기 쉽다
• UWP App > Desktop App or Desktop App > UWP App ????
• 배포하기 쉽다(팔아먹기 쉽다)
• UWP App >>> Desktop App
• 기능(할 수 있는 것)
• Desktop App >>>> UWP App
• 타겟 디바이스 수
• UWP App >> Desktop App
UWP의 기술적 특징
• Sandbox – (MS/Google/Apple중 MS가 가장 엄격함.)
• 앱의 명시적 종료가 따로 없음(iOS와 비슷)
• GDI사용할 수 없음. (WPF가 아니라면 UI는 새로 작성합니다.)
• UI는 XAML로 작성
• C++ / Java Script(HTML) , C#으로 개발가능
• C++로 개발할때
• Win32일부 사용 가능.
• Direct X 사용 가능.
• 표준 C/C++ 라이브러리 어느 정도 사용 가능.
UWP의 기술적 특징
Windows 10 App vs Windows 8.x App
• 공식적으로는 둘다 Windows App으로 칭함.
• UWP :
Windows Runtime API for Windows 10
• Windows 8.x App :
Windows Runtime API for Windows 8/8.1
• Windows Runtime -> 줄여서 WinRT
• 저주받은 그 이름 Windows RT (Surface RT에 탑재된 Windows 8 on ARM)
• WinRT는 Windows RT를 연상시켜서 금기시되고 있다.
• 따라서 앞으론 UWP라고 부르기로 합니다.
UWP App과 Windows 8.x App의 차이
• 사실상 Windows 10 과 Windows 8.x에서의 WinRT API의 차이
• Universal App 호환성
• Windows 8.1에선 Phone,PC 각각 XAML코드를 따로 작성해야됨.
• Windows 10의 UWP에선 따로 작성할 필요없음.
• 다양한 사이즈의 디스플레이를 위한 Adaptive UI지원.
UWP App과 Windows 8.x App의 차이
• 추가적인 Win32 API/CRT추가지원.(Winsock, process관련 CRT
등)
• 창모드 지원
• 드래그앤 드롭 지원.
• 여러개의 인스턴스 가능.(계산기,Edge브라우저 등)
이제 Windows Store에서도 데스크탑에서 쓸만한 앱
을 다운로드 할 수 있게 될 것이다.
megayuchi
UWP앱 개발
Why C++?
• 빠르다.(빠르게 짜거나 느리게 짤 수 있다.)
• 메모리 관리를 내 맘대로
• 메모리 사용량을 줄일 수 있다.
• GC기반 언어와 성능차이를 만들어내는 가장 큰 이유
• 기존 코드 재사용 가능 (게임/영상처리 등)
• 영상 처리나 그래픽스 코드들의 상당수가 C++로 작성되어 있다.
• 기존 PC/콘솔 게임들의 100%. 모바일 게임도 상당수가 C/C++로 작성
되어 있다.
• 크로스플랫폼 지원 – 모든 플랫폼이 공통적으로 지원하는 언어
는 C/C++ 뿐.
Cross-Platform 을 위한 C++사용 사례
Building Cross-Platform Mobile Apps in C++ with Visual Studio 2015
https://channel9.msdn.com/Events/Build/2015/3-714
C++로 UWP앱 개발
• C++만을 사용하면 좋겠지만 C++/CX를 조금은 사용해야함.
• API는 호출하는 방법만 약간 다르고 C#,C++,JS 기본적으로 동일.
• 예제가 없어요ㅠㅠ -> C#을 키워드에 넣어서 검색합니다.
• UI는 XAML을 사용한다. (C#,JS와 동일)
• C/C++ Runtime Library 사용 -> Universal CRT(ucrtbase.dll)
• 8/8.1 세대의 CRT지원에 비해 제약이 상당히 줄어들었다.
C/C++로 개발할때의 중요한 변화
• _beginthread(), _endthread()등 process.h에 선언된 스레드관련
함수들 사용 가능
• SetCurrentDirectory(),GetCurrentDirectory() 사용 가능. 이전엔
모든 path는 절대 경로로 접근해야 했음.
• ARM/x86에 상관없이 HLSL Shader를 run-time에 컴파일 가능.
8.x에선 미리 빌드한 바이너리만 사용 가능했다.
Hello World~
• 간단 라이브 코딩
XAML UI
• XAML - MS의 UI 개발용 마크업 언어
• 어떤 언어를 사용하든 UWP앱 개발을 위해서 XAML은 무조건
사용해야함.
• Visual Studio에 기본 내장된 XAML Designer로 작성 가능.
• Visual Studio 패키지에 포함된 Blend로 작성 가능.
XAML Designer
App Lifecycle
App Lifecycle – 이것만 알아둡시다.
• void App::OnLaunched()
• App이 실행됨. 최초 실행되었거나, 죽었다가 실행되었거나…
• Suspend-> Killed -> Resume -> OnLanunched
• 최초 설치됨 -> OnLaunched
• Void App::OnSuspending()
• 더 이상 스케쥴링되지 않음.
• Phone이나 태블릿모드에서 back버튼, Windows버튼 눌렀을때.
• 전화왔을때.
• Desktop에서 창을 최소화시켰을때.
• void App::OnResuming()
• Susened상태에서 다행히(?) 죽지 않고 App으로 복귀한 경우.
• OS는 메모리가 부족할 때 suspend 상태의 앱부터 죽인다.
C++/CX
• UWP API(Windows Runtime API)를 호출하기 위한 MS의 C++
확장
• UWP의 모든 API는 객체지향. C++/CX의 ref class로 구현되어있
다.
• 레퍼런스 카운팅 기반 C++
• 컴파일러가 분석해서 알아서 AddRef()와 Release()를 호출하는
게 아니고…ref class가 스마트 포인터를 내장하고 있다.
C++/CX
• C++에 C++/CLI 문법을 차용했다. -> C# 비슷한 느낌이 있다.
• ref class는 내부적으로 IInspectable COM 객체
• ref class의 핸들로 포인터 연산자 *대신 ^을 사용한다.
• Lambda 표현을 많이 사용함.
• ppl task를 많이 사용한다.
ref class CSimpleObject sealed
{
String^_Name;
~CSimpleObject();
public: // 외부에 메타데이타를 노출함. 심지어 다른 언어에서도 이 클래스의 public 멤버 호출 가능
property Platform::String^ Name // get(),set() 직접 코딩
{
Platform::String^ get()
{
return _Name;
}
void set(Platform::String^ name)
{
_Name = name;
}
}
property int Value; // get(),set()자동 생성
CSimpleObject();
CSimpleObject(String^ name,int value)
{
_Name = name;
Value = value;
}
internal: // 이 모듈(빌드되는 바이너리) 내에서만 public.
CSimpleObject^ operator+(CSimpleObject^ obj);
};
ref class 선언
#include "pch.h"
#include "SimpleObject.h"
CSimpleObject::CSimpleObject()
{
}
CSimpleObject^ CSimpleObject::operator+(CSimpleObject^ obj)
{
CSimpleObject^result = ref new CSimpleObject();
result->Value = Value + obj->Value;
result->Name = _Name + L" + " + obj->Name;
return result;
}
CSimpleObject::~CSimpleObject()
{
String^Message = _Name + L" destroyedn";
OutputDebugString(Message->Data());
}
ref class 구현
void MainPage::TestRefClass()
{
CSimpleObject^ Obj0 = ref new CSimpleObject(L"Object 0",0);
CSimpleObject^ Obj1 = ref new CSimpleObject(L"Object 1",1);
CSimpleObject^ Obj2 = Obj0 + Obj1; // 새로운 객체 Obj2 생성
CSimpleObject^ Obj3 = Obj2; // Obj3이 Obj2를 참조. ref count 1 증가
Obj0 = nullptr; // ref count가 0이 되어 해제
Obj1 = nullptr; // ref count가 0이 되어 해제
Obj2 = nullptr; // ref count가 1 남아있으므로 해제되지 않음.
Obj3 = nullptr; // ref count가 0이 되어 해제
}
<Output>
Object 0 destroyed
Object 1 destroyed
Object 0 + Object 1 destroyed
ref class 사용
C++/CX - Lambda
• 비동기 API호출을 위해 create_task(), then()을 많이 쓰다보니
Lambda식을 자연스럽게 많이 사용하게 됨.
• 이벤트 핸들러(Win32에서 콜백함수)의 상당수를 Lambda식으
로 전달
• 그냥 쓰다 보면 익숙해짐. 나름 편함.
• Lambda에 대한 자세한 설명은 생략. 링크를 참조
https://msdn.microsoft.com/ko-kr/library/dd293608.aspx
void MainPage::MessageDialogOkCancel(Platform::String^ Message)
{
MessageDialog^ msg = ref new MessageDialog(Message);
// OK버튼을 눌렀을때의 이벤트 핸들러를 Lambda식으로 전달
UICommand^ cmdOK = ref new UICommand("OK",ref new UICommandInvokedHandler([this](IUICommand^
)
{
// On Pressed OK
}));
// Cancel버튼을 눌렀을때의 이벤트 핸들러를 Lambda식으로 전달
UICommand^ cmdCanccel = ref new UICommand("Cancel",ref new UICommandInvokedHandler([this](IU
ICommand^)
{
// On Pressed Cancel
}));
msg->Commands->Append(cmdOK);
msg->Commands->Append(cmdCanccel);
msg->DefaultCommandIndex = 0;
msg->CancelCommandIndex = 1;
msg->ShowAsync();
}
Lambda식 사용
Async API
• Windows Runtime의 설계자들은 생각했다.
• UI가 잠깐이라도 먹통 되는 것은 참을 수 없다!!!!
• I/O작업은 미친듯이 느리다.
• 그래서 그들은 이렇게 결정했다.
• 어떤 작업도 UI스레드를 block시켜서는 안된다.
• 모든 I/O작업은 비동기로 처리한다.
• 가능하면 UI 스레드는 다른 스레드에 작업을 넘길 뿐 직접 처리하지 않
는다.
Async API
• I/O 관련 API는 모조리 Async
• Async API는 ppl task의 create_task()와 같이 사용한다.
• create_task().then().then().then()….
• create_task()는 Windows ThreadPool 사용하므로 task 생성 비용이
높지는 않다.
• 추후 C++에서도 await가 지원될 예정.
• 사실 이 문서를 작성하는 시점에서 전혀 불편함을 못 느끼고 있음.
void FileOpenUWP::MainPage::PickButton_ClickSingle(Platform::Object^ sender, Windows::UI::Xaml:
:RoutedEventArgs^ e)
{
FileOpenPicker^ openPicker = ref new FileOpenPicker();
openPicker->ViewMode = PickerViewMode::Thumbnail;
openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary;
openPicker->FileTypeFilter->Append(".txt");
//auto ctx = task_continuation_context::use_arbitrary();
auto ctx = task_continuation_context::use_default();
create_task(openPicker->PickSingleFileAsync()).then([this](Windows::Storage::StorageFile^ fi
le)
{
if (file)
{
ReadTextFromFile(file);
}
},ctx);
}
Async call – File Open
UI스레드가 task::get()을 사용해서 Asyc 태스크의 완료를 wait할 수 있다.
Then()문이 필요 없다.
then().then().then()이 너무 정신 없다!!!
Windows::Storage::CreationCollisionOption opt = CreationCollisionOption::ReplaceExisting;
auto task_file = create_task(folder->CreateFileAsync(FileName,opt));
StorageFile^ file = nullptr;
try
{
file = task_file.get();
}
catch (Platform::Exception^ e)
{
String^ err = e->Message;
String^ errMsg = L"Failed to CreateFileAsyc - " + err + L"n";
WriteDebugStringW(errMsg->Data());
}
파일 오픈 예제(Desktop Application)
파일오픈 예제 (UWP)
감을 잡으셨나요?
• 추가적으로 학습해야 할 내용
• XAML
• C++/CX
• Async API + ppl task
그때그때 검색해서 사용하다 보면 금방 익숙해집니다.
만들어 봅시다.
UWP앱, 무엇을 만들까?
• smi자막과 다양한 코덱을 지원하는 동영상 플레이어
• 강제 resize없고 exif 표시되는 이미지 뷰어
• Winamp같은 뮤직 플레이어
• 그림판보단 좀 그럴싸한 이미지 에디터-아이콘 에디터라든가
• Mp3 tag
• 가벼운 3D 모델링 툴. Sket**up같은거?
• 네트워크 툴 – ftp등
• 게임
• 소비성이 아닌 생산성 앱이면서 무겁지 않은 앱이 적합하다.
• PC/콘솔 게임과 동등한 스케일, 혹은 그에 준하는 스케일의 게
임
• 이런 앱이 모바일에서도 똑같이 작동한다면 매력적이지 않은가?
UWP앱, 무엇을 만들까?
이런걸 만들어 봤습니다.
• D3DPlayer - ffmpeg 동영상 플레이어
• 최초 발단은 Windows Phone에서 돌아가는 스트리밍 게임 클라이언트
를 만들 생각이었다.
• ffmpeg , Direct X(Direct 3D, Direct 2D) , C++
• ffmepg interop 참고 (https://github.com/Microsoft/FFmpegInterop)
• ffmpeg는 따로 빌드해야함.
• FileTransfer - TCP기반 파일 전송 앱
• 내 Windos Phone으로 파일을 전송하고 싶은데 케이블이 없네.
• 원격지의 친구에게 빠르게(peer to peer) 파일을 전송하고 싶다.
• Winsock , C++
D3DVideoPlayer
D3DPlayer – 목표 기능
• ffmepg를 이용한 동영상 재생
• Shader를 이용한 간단한 후처리
• 비디오 출력은 D3D를 이용해서 직접 출력함.
• D2D를 이용한 텍스트 출력
• Windows Phone/Tablet/Desktop 동일 작동.
D3DVideoPlayer – 앱 구조
EXE
Rendering Loop
UI Thread
YUV Frame Queue
File or Network
Decoding Thread
Reader &
Audio Decoder
DLL
Media Element
D3D
Display
Video
Audio
D3DVideoPlayer 데모
D3DPlayer – 디코딩
• MediaElement사용
• 타이머 겸 오디오 스트림 출력
• XAML에서 <MediaElement x:Name="mediaElement"></MediaElement>
한 줄로 끝.
• 오디오 스트림을 가지고 MediaStreamSource 세팅.
• 오디오 샘플 요청이 들어오면 큐를 채움.
• 비디오 샘플의 경우 디코딩 스레드가 백그라운드로 디코딩.
• 디코딩해서 얻은 YUV 프레임을 큐에 쌓아둠.
void CDecoder::DecodePacket(AVPacket avPacket)
{
BOOLbGotPicture = FALSE;
if (avcodec_decode_video2(m_pVCtx, m_pVFrame, &bGotPicture, &avPacket) >= 0)
{
if (bGotPicture)
{
DWORDstride = m_pVFrame->linesize[0];
DWORDwidth = m_pVCtx->width;
DWORDheight = m_pVCtx->height;
if (avPacket.pts == AV_NOPTS_VALUE && avPacket.dts != AV_NOPTS_VALUE)
avPacket.pts = avPacket.dts;
Windows::Foundation::TimeSpan pts = { LONGLONG(av_q2d(m_pFmtCtx->streams[m_nVSI]->ti
me_base) * 10000000 * avPacket.pts) };
Windows::Foundation::TimeSpan dur = { LONGLONG(av_q2d(m_pFmtCtx->streams[m_nVSI]->ti
me_base) * 10000000 * avPacket.duration) };
PushYUVFrame(&bDestroyed, width, height, m_pVFrame->data[0], m_pVFrame->data[1], m_p
VFrame->data[2], stride, (__int64)pts.Duration);
}
}
} AVPacket으로부터 비디오 프레임 디코딩
Direct3D/Direct2D 생성 및 초기화
• Desktop앱과 UWP앱의 DirectX 사용법은 95% 같다.
• Desktop앱에선 D3D 생성에 HWND가 필요하다.
• UWP앱 D3D생성에는 XALM로 페이지에 배치한 SwapChainPan
el 객체가 필요하다.
<SwapChainPanel x:Name="swapChainPanel"/>
Direct3D/Direct2D 생성 및 초기화
• UWP/Desktop 모두 IDirect3DDevice로부터 ID2DDevice 인터페
이스를 얻는다.
• 단 Desktop API는 HWND로부터 Direct2D 객체를 직접 생성할
수 있다.
• DirectX를 사용함에 있어 UWP앱과 Desktop앱의 가장 큰 차이
점은 SwapChain을 설정하는 방법이다.
GDI Windows Handle - HWND SwapChainPlanel
<SwapChainPanel x:Name="swapChainPanel"/>
in XAML
Desktop Application – win32 UWP App
ID3D11Device*pD3DDevice = NULL;
// create D3DDevice...blabla
IDXGIDevice1*pdxgiDevice = NULL;
pD3DDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**) &pdxgiDevice);
IDXGIAdapter*pdxgiAdapter = NULL;
pdxgiDevice->GetAdapter(&pdxgiAdapter);
IDXGIFactory2*pdxgiFactory = NULL;
pdxgiAdapter->GetParent(__uuidof(IDXGIFactory2), (void**) &pdxgiFactory);
IDXGISwapChain1*pSwapChain = NULL;
DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 };
// Fill swapChainDesc…blabla
pdxgiFactory->CreateSwapChainForComposition(pD3DDevice, &swapChainDesc, nullptr, &pSwapChain);
ISwapChainPanelNative*pSwapChainPanelNative = nullptr;
reinterpret_cast<IUnknown*>(swapChainPanel)->QueryInterface(__uuidof(ISwapChainPanelNative), (v
oid**) &pSwapChainPanelNative);
pSwapChainPanelNative->SetSwapChain(m_pSwapChain);
XAML에서 페이지에 배치한 <SwapChainPanel>객
체를 D3D에서 생성한 IDXGISwapChain1 객체와 연
결시킨다.
UWP앱에서의 SwapChain생성
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC swapChainDesc = {0};
// Fill swapChainDesc…blabla
swapChainDesc.OutputWindow = hWnd;
IDXGISwapChain*pSwapChain = NULL;
ID3D11Device*pD3DDevice = NULL;
ID3D11DeviceContext*pImmediateContext = NULL;
HRESULT hr = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDevic
eFlags, featureLevels, numFeatureLevels,D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pD3DDe
vice, &m_FeatureLevel, &pImmediateContext );
Desktop앱에서의 SwapChain생성
HWND를 받아서 DXGI_SWAP_CHAIN_DESC 구조체에 넣는다.
이 구조체로 SwapChain,D3DDevice,D3DDeviceContext를
한번에 생성한다.
D3DPlayer – 렌더링
• 게임루프 처리하듯이 60프레임으로 폴링
• 클라우드 게이밍용 클라이언트가 목적이므로
• 큐에서 현재 타임 스탬프와 일치하는 YUV프레임을 얻어옴.
• YUV포맷의 이미지를 직접 텍스쳐에 써넣는다.
• YUV포맷의 텍스쳐를 쉐이더 안에서 RGB로 변환
• 필터 모드에 따라 쉐이더를 다르게 선택
• 텍스트는 Direct2D를 이용해서 출력
void MainPage::Init()
{
EventHandler<Object^>^ ev = ref new EventHandler<Object^>(this, &MainPage::OnUpdate);
Windows::Foundation::EventRegistrationToken RenderingEventToken = CompositionTarget::Renderi
ng::add(ev);
}
void MainPage::OnUpdate(_In_ Object^ sender ,_In_ Object^ args)
{
if (g_pVideoPlayer)
{
g_pVideoPlayer->OnRender();
}
}
유휴시간을 모두 사용하는
(게임용) 렌더링 루프
YUV프레임으로부터 텍스쳐
업데이트 - Lock
void CD3DRenderer::UpdateYUVTexture(DWORD dwWidth,DWORD dwHeight,BYTE* pYBuffer,BYTE* pUBuffer,
BYTE* pVBuffer,DWORD Stride)
{
D3D11_MAPPED_SUBRESOURCE mappedResource = {0}
pDeviceContext->Map(m_pYUVTexture,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource);
DWORDStrideHalf = Stride / 2;
for (DWORD y=0; y<dwHeight; y++)
{
BYTE* y_buffer_entry = pYBuffer + (Stride*y);
BYTE* u_buffer_entry = pUBuffer + (StrideHalf*(y>>1));
BYTE* v_buffer_entry = pVBuffer + (StrideHalf*(y>>1));
BYTE*pDestEntry = (BYTE*)mappedResource.pData + (mappedResource.RowPitch*y);
for (DWORD x=0; x<dwWidth; x++)
{
pDestEntry[0] = *y_buffer_entry;
pDestEntry[1] = *u_buffer_entry;
pDestEntry[2] = *v_buffer_entry;
pDestEntry[3] = 0xff;
y_buffer_entry++;
DWORDuv_inc = x & 0x00000001;
u_buffer_entry += uv_inc;
v_buffer_entry += uv_inc;
pDestEntry += 4;
}
}
YUV프레임으로부터 텍스쳐
업데이트 - Wirte
pDeviceContext->Unmap(m_pYUVTexture,0);
}
YUV프레임으로부터 텍스쳐
업데이트 - Unlock
FileTransfer
FileTransfer - 목표기능
• Windows 10 디바이스간 파일 전송
• 여러 개의 파일 전송 가능
• 동시에 여러 개의 peer와 파일 전송 가능
• 저장할 폴더 선택 가능
• Windows Phone/Tablet/Desktop 동일 작동.
• 대부분의 코드를 공유하여 Win32 CUI버전도 개발
FileTransfer – 앱구조
Peer Finder
Listen & Accept
Receiver
Sender
Peer Finder
Listen & Accept
Receiver
Sender
File Stream
Connect
AppApp
FileTransfer - 데모
FileTransfer – peer간 접속
• UDP로 브로드캐스팅
• UDP패킷을 수신하면 TCP 포트를 열어서 listen
• 파일 전송 허가를 기다림
FileTransfer – 파일 송신/수신
• block모드 socke함수 send(),recv()사용.
• 전송 이벤트 하나당 스레드 하나씩
• Win32의 경우 소켓 에러 -1만 처리하면 됨.
• 파일 송수신 코드는 UWP/Desktop 99% 동일
• UWP의 경우 소켓 에러 상황에서 리턴값 외에 execption 처리
가 필요할 수 있음. (1%의 차이)
BOOL RecvPacket(SOCKET s,char* pBuffer,int size,int* piOutSocketError)
{
*piOutSocketError = 0;
BOOLbResult = TRUE;
while (size > 0)
{
BOOLbException = FALSE;
intiErrCodeOnException = 0;
intrecv_result = -1;
__try
{
recv_result = recv(s,pBuffer,size,0);
}
__except(GetExceptionCode() == EXCEPTION_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EX
CEPTION_CONTINUE_SEARCH)
{
iErrCodeOnException = 10038;
bException = TRUE;
WriteDebugStringW(L"Exception was occured in recv().n");
}
패킷 수신
UWP에선 소켓에러 상황에서 SOCKET_ERROR를 리턴하는것 외
에 추가적으로 익셉션을 발생시킨다.
StreamSocket이 내부적으로 winsock을 사용하기
StreamSocket을 위해 이렇게 작동하는 것으로 보인다.
StreamSocket은 소켓 에러 상황을 익셉션으로 처리함.
if (0 == recv_result)
{
*piOutSocketError = 0;
bResult = FALSE;
break;
}
if (SOCKET_ERROR == recv_result)
{
if (bException)
{
*piOutSocketError = iErrCodeOnException;
}
else
{
*piOutSocketError = WSAGetLastError();
}
bResult = FALSE;
break;
}
pBuffer += recv_result;
size -= recv_result;
}
return bResult;
}
패킷 수신
FileTransfer – 파일 읽기/쓰기
• UWP
• Windows::Storage::StorageFile로부터 IRandomAccessStream^ fileStre
am을 얻는다.
• FIleStream으로 DataWriter / DataReader를 생성,
• 파일에 쓰기 - DataWriter::WriteBytes() , DataWriter::StoreAsync()
• 파일로부터 읽기 - DataReader::LoadAsync() , DataReader::ReadBytes()
• Desktop – win32
• CreateFile()로 파일 생성 및 오픈
• 파일에 쓰기 – WriteFile()
• 파일로부터 읽기 ReadFile()
BOOL CFileReceiver::CreateFileAndRecv(Windows::Storage::StorageFolder^ folder , String^ FileName , ….
{
Windows::Storage::CreationCollisionOption opt = CreationCollisionOption::ReplaceExisting;
auto task_file = create_task(folder->CreateFileAsync(FileName,opt));
StorageFile^ file = nullptr;
try
{
file = task_file.get();
}
catch (Platform::Exception^ e)
{
String^ err = e->Message;
String^ errMsg = L"Failed to CreateFileAsyc - " + err + L"n";
WriteDebugStringW(errMsg->Data());
}
폴더로부터 파일 생성
UWP앱은 완전한 Sandbox시스템이므로 아무 폴더나 임의로 억세스 할수
없다.
명시적인 방법으로 Windows::Storage::StorageFolder 객체를 얻어와야 한다.
auto task_open = create_task(file->OpenAsync(FileAccessMode::ReadWrite));
IRandomAccessStream^ fileStream = task_open.get();
UINT64 CurPos = fileStream->Position;
fileStream->Seek(ui64StartPos);
CurPos = fileStream->Position;
DataWriter^ dataWriter = ref new DataWriter(fileStream);
파일 오픈
UI Thread가 아니므로 task::get()으로 wait가능
파일/네트워크 스트림에 써넣기 위해서는
Windows::Storage::Stream::DataWriter를 사용한다.
while (ui64FileSize > 0)
{
int recv_size = (int)MAX_RECV_SIZE_PER_ONCE;
if ((UINT64)(DWORD)recv_size > ui64FileSize)
{
recv_size = (int)(DWORD)ui64FileSize;
}
if (!RecvPacket(sock,m_pRecvBuffer,recv_size,piOutSocketError))
{
break;
}
dataWriter->WriteBytes(Platform::ArrayReference<BYTE>((BYTE*)m_pRecvBuffer, (unsigned int)re
cv_size));
auto task_write = create_task(dataWriter->StoreAsync());
size_t WrittenBytes = task_write.get();
ui64FileSize -= recv_size;
}
파일에 수신한 스트림 저장
실제 write작업은 StoreAsync()호출 후에 비동기로 이루어진
다.
WriteBytes()에서 Write작업이 바로 이루어지지는 않는다.
잠깐! C#으론 못만들어요?
• 물론 됩니다.
• D3D , D2D , ffmepg , winsock을 사용하는 부분만 C++로 작성
하고 C#에서 호출할 수 있도록 ref class로 포장하면 됩니다.
• 저라면 이렇게 복잡하게 하느니 차라리 전체를 C++로 작성하
겠습니다.
결론
• 같은 성능이라면 사용자는 간편하고 깔끔한 설치/제거를 원한다.
• UWP앱으로 Desktop 앱의 영역을 어느 정도 대체 가능하다.
• C++을 사용해서 UWP앱을 개발하면 효율적으로 Desktop앱의 코드
를 UWP앱으로 옮겨갈 수 있다.
• C++은 크로스 플랫폼 개발에 가장 효율적인 언어이다.
• 몇 가지 내용만 학습하면 기존 C++ 프로그래머들이 어렵지 않게
UWP앱을 개발할 수 있다.
Q / A
Classic Win32 개발자들이 자주 하는 질문
• MessageBox를 띄우고 싶어요.
• 작업 중간에 MessageBox를 띄우고 응답이 올때까지 작업을 대기시
키고 싶어요.
• WriteFile() ,ReadFile() ,fread() ,fwrite()를 사용하고 싶은데 문제가 있
나요?
• 임의로 아무 폴더의 파일을 open할수 있는가?
• 폴더(디렉토리)간 이동을 하려면?
• DLL은 사용 가능한가요?
• Memory Leak을 확인하려면?
• create_task().then()이 짜증나요.
• Lambda 쓰기 싫어요.
Reference
• C++/CX의 ref class객체들을 STL컨테이너와 함께 사용할 경우
ref count관리는 어떻게 이루어지는가 (http://wp.me/p6sbBj-aZ)
• Windows 10 UWP에서 D3D객체들이 완전히 해제되었는지 확
인하기 (http://wp.me/p6sbBj-6P)
• C++로 WIndows 10 UWP앱 개발할때 드래그 앤 드롭 처리하기
(http://wp.me/p6sbBj-7i)
감사합니다.
• MSDN Forum http://aka.ms/msdnforum
• TechNet Forum http://aka.ms/technetforum
http://aka.ms/td2015_again
TechDays Korea 2015에서 놓치신 세션은
Microsoft 기술 동영상 커뮤니티 Channel 9에서
추후에 다시 보실 수 있습니다.

More Related Content

PDF
Ndc17 - 차세대 게임이펙트를 위해 알야아할 기법들
PPTX
리플렉션과 가비지 컬렉션
PDF
멀티스레드 렌더링 (Multithreaded rendering)
PDF
NoSQL 위에서 MMORPG 개발하기
PDF
06_게임엔진구성
PDF
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
PDF
Deep Dive async/await in Unity with UniTask(EN)
PDF
UE4 Garbage Collection
Ndc17 - 차세대 게임이펙트를 위해 알야아할 기법들
리플렉션과 가비지 컬렉션
멀티스레드 렌더링 (Multithreaded rendering)
NoSQL 위에서 MMORPG 개발하기
06_게임엔진구성
Ndc2010 전형규 마비노기2 캐릭터 렌더링 기술
Deep Dive async/await in Unity with UniTask(EN)
UE4 Garbage Collection

What's hot (20)

PDF
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
PDF
[Ndc12] 누구나 알기쉬운 hdr과 톤맵핑 박민근
PDF
NDC12_Lockless게임서버설계와구현
PDF
언리얼 서밋 2016 프로젝트 A1의 구형 월드 라이팅 기술
PDF
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
PDF
배정섭, 쉽고 빠르게 매력적인 모션 제작하기 tip, NDC2010
PPT
게임 프레임워크의 아키텍쳐와 디자인 패턴
PDF
Unityネイティブプラグインの勧め 〜UnityでiOS, AndroidのAPIを利用する方法〜
PDF
간단한 게임을 쉽고 저렴하게 서비스해보자! ::: AWS Game Master 온라인 시리즈 #1
PDF
나만의 엔진 개발하기
PPTX
DDDモデリング勉強会 #6
PPTX
Tips and experience of DX12 Engine development .
PDF
NDC2019 - 게임플레이 프로그래머의 역할
PPTX
게임프로젝트에 적용하는 GPGPU
PDF
FANTASIANの明日使えない特殊テクニック教えます
PDF
Igc2016 Technical Artist가 뭐하는 사람이에요?
PDF
[2012 대학특강] 아티스트 + 프로그래머
PDF
C++20 Coroutine
PDF
[221] 딥러닝을 이용한 지역 컨텍스트 검색 김진호
PPTX
画像認識ベースのUI自動化フレームワークを用いた取り組み
〈야생의 땅: 듀랑고〉 서버 아키텍처 Vol. 3
[Ndc12] 누구나 알기쉬운 hdr과 톤맵핑 박민근
NDC12_Lockless게임서버설계와구현
언리얼 서밋 2016 프로젝트 A1의 구형 월드 라이팅 기술
Unityによるリアルタイム通信とMagicOnionによるC#大統一理論の実現
배정섭, 쉽고 빠르게 매력적인 모션 제작하기 tip, NDC2010
게임 프레임워크의 아키텍쳐와 디자인 패턴
Unityネイティブプラグインの勧め 〜UnityでiOS, AndroidのAPIを利用する方法〜
간단한 게임을 쉽고 저렴하게 서비스해보자! ::: AWS Game Master 온라인 시리즈 #1
나만의 엔진 개발하기
DDDモデリング勉強会 #6
Tips and experience of DX12 Engine development .
NDC2019 - 게임플레이 프로그래머의 역할
게임프로젝트에 적용하는 GPGPU
FANTASIANの明日使えない特殊テクニック教えます
Igc2016 Technical Artist가 뭐하는 사람이에요?
[2012 대학특강] 아티스트 + 프로그래머
C++20 Coroutine
[221] 딥러닝을 이용한 지역 컨텍스트 검색 김진호
画像認識ベースのUI自動化フレームワークを用いた取り組み
Ad

Viewers also liked (20)

PPTX
Implements Cascaded Shadow Maps with using Texture Array
PDF
[0602 박민근] Direct2D
PDF
RAD Studio 10 시애틀: 출시 세미나 발표자료
PPTX
Porting direct x 11 desktop game to uwp app
PPTX
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
PPTX
DirectX + C++을 이용한 WindowsStore App과 Windows Phone용 게임 개발
PPTX
[0122 구경원]게임에서의 충돌처리
PPTX
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계
PPTX
UWP 응용 프로그램 작성시 올바른 networking APIs 사용하기
PDF
20150912 windows 10 앱 tips tricks
PDF
20150728 100분만에 배우는 windows 10 앱 개발
PDF
[Td 2015]프로그래밍 언어의 f1머신 c++을 타고 windows 10 uwp 앱 개발의 세계로~(유영천)
PPTX
Build 2016 - P426 - Using the Right Networking API for your UWP App
PDF
[데브기어 온라인세미나] 20160504 새로 강화된 기능들 RAD Studio, Delphi, C++Builder
PPTX
Hierachical z Map Occlusion Culling
PDF
[스마트스터디] 재택근무 잘 하고 있어요
PDF
[C++ Korea 2nd Seminar] C++17 Key Features Summary
PPT
Presentation On Bandra Worli Sealink
PDF
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
PDF
스타트업에서 기술책임자로 살아가기
Implements Cascaded Shadow Maps with using Texture Array
[0602 박민근] Direct2D
RAD Studio 10 시애틀: 출시 세미나 발표자료
Porting direct x 11 desktop game to uwp app
GPGPU(CUDA)를 이용한 MMOG 캐릭터 충돌처리
DirectX + C++을 이용한 WindowsStore App과 Windows Phone용 게임 개발
[0122 구경원]게임에서의 충돌처리
[KGC2014] 두 마리 토끼를 잡기 위한 C++ - C# 혼합 멀티플랫폼 게임 아키텍처 설계
UWP 응용 프로그램 작성시 올바른 networking APIs 사용하기
20150912 windows 10 앱 tips tricks
20150728 100분만에 배우는 windows 10 앱 개발
[Td 2015]프로그래밍 언어의 f1머신 c++을 타고 windows 10 uwp 앱 개발의 세계로~(유영천)
Build 2016 - P426 - Using the Right Networking API for your UWP App
[데브기어 온라인세미나] 20160504 새로 강화된 기능들 RAD Studio, Delphi, C++Builder
Hierachical z Map Occlusion Culling
[스마트스터디] 재택근무 잘 하고 있어요
[C++ Korea 2nd Seminar] C++17 Key Features Summary
Presentation On Bandra Worli Sealink
[NDC12] 게임 물리 엔진의 내부 동작 원리 이해
스타트업에서 기술책임자로 살아가기
Ad

Similar to 프로그래밍 언어의 F1머신 C++을 타고 Windows 10 UWP 앱 개발의 세계로~ (20)

PDF
[Td 2015]알아두면 핵 이득! vc++로 안드로이드 개발하기(김성엽)
PDF
XDK없이 XBOX게임 개발하기(UWP on XBOX)
PDF
[Td 2015]70분에 보여준다. 웹표준을 지원하는 edge 브라우저부터 웹 앱 개발까지(김영욱)
PPTX
C# 뉴비를 위한 맛보기 2
PPTX
C#기초에서 윈도우, 스마트폰 앱개발 과정(c#.net, ado.net, win form, wpf, 자마린)_자마린학원_씨샵교육_WPF학원...
PDF
델파이 @22
PPTX
About Visual C++ 10
PPTX
안드로이드 오픈소스 어플리케이션 블록
PDF
M5 6 1
PPTX
Windows Phone Apps Story Book #1
PPTX
The Future of C# and .NET Framework
DOCX
C#강좌
PDF
게임프로그래머에게 배우는 C#1권(버전1)
PPTX
Tech Update - The Future of .NET Framework (김명신 부장)
PDF
나만의 C++애플리케이션 완성하기 with C++빌더
PDF
S#03 김용현:VS2010으로 마이그레이션
PDF
HD 애플리케이션 만들기(파이어몽키 활용)
PDF
모바일환경에서의 크로스 플랫폼_3D_렌더링엔진_제작과정
PPTX
C# 뉴비를 위한 맛보기
PDF
나의 첫 윈도우/맥 애플리케이션 개발하기
[Td 2015]알아두면 핵 이득! vc++로 안드로이드 개발하기(김성엽)
XDK없이 XBOX게임 개발하기(UWP on XBOX)
[Td 2015]70분에 보여준다. 웹표준을 지원하는 edge 브라우저부터 웹 앱 개발까지(김영욱)
C# 뉴비를 위한 맛보기 2
C#기초에서 윈도우, 스마트폰 앱개발 과정(c#.net, ado.net, win form, wpf, 자마린)_자마린학원_씨샵교육_WPF학원...
델파이 @22
About Visual C++ 10
안드로이드 오픈소스 어플리케이션 블록
M5 6 1
Windows Phone Apps Story Book #1
The Future of C# and .NET Framework
C#강좌
게임프로그래머에게 배우는 C#1권(버전1)
Tech Update - The Future of .NET Framework (김명신 부장)
나만의 C++애플리케이션 완성하기 with C++빌더
S#03 김용현:VS2010으로 마이그레이션
HD 애플리케이션 만들기(파이어몽키 활용)
모바일환경에서의 크로스 플랫폼_3D_렌더링엔진_제작과정
C# 뉴비를 위한 맛보기
나의 첫 윈도우/맥 애플리케이션 개발하기

More from YEONG-CHEON YOU (19)

PDF
DirectStroage프로그래밍소개
PDF
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
PDF
Visual Studio를 이용한 어셈블리어 학습 part 2
PDF
Visual Studio를 이용한 어셈블리어 학습 part 1
PDF
Introduction to DirectX 12 Programming , Ver 1.5
PDF
MMOG Server-Side 충돌 및 이동처리 설계와 구현
PDF
빠른 렌더링을 위한 오브젝트 제외 기술
PDF
실시간 게임 서버 최적화 전략
PDF
Voxelizaition with GPU
PDF
Voxel based game_optimazation_relelase
PDF
Sw occlusion culling
PPTX
CUDA를 게임 프로젝트에 적용하기
PPTX
서버와 클라이언트 같은 엔진 사용하기
PPT
프레임레이트 향상을 위한 공간분할 및 오브젝트 컬링 기법
PPTX
win32 app에서 UWP API호출하기
PPTX
Azure로 MMO게임 서비스하기
PPTX
Development AR App with C++ and Windows Holographic API
PDF
빌드관리 및 디버깅 (2010년 자료)
PPTX
Tips and experience_of_dx12_engine_development._ver_1.2
DirectStroage프로그래밍소개
CUDA Raytracing을 이용한 Voxel오브젝트 가시성 테스트
Visual Studio를 이용한 어셈블리어 학습 part 2
Visual Studio를 이용한 어셈블리어 학습 part 1
Introduction to DirectX 12 Programming , Ver 1.5
MMOG Server-Side 충돌 및 이동처리 설계와 구현
빠른 렌더링을 위한 오브젝트 제외 기술
실시간 게임 서버 최적화 전략
Voxelizaition with GPU
Voxel based game_optimazation_relelase
Sw occlusion culling
CUDA를 게임 프로젝트에 적용하기
서버와 클라이언트 같은 엔진 사용하기
프레임레이트 향상을 위한 공간분할 및 오브젝트 컬링 기법
win32 app에서 UWP API호출하기
Azure로 MMO게임 서비스하기
Development AR App with C++ and Windows Holographic API
빌드관리 및 디버깅 (2010년 자료)
Tips and experience_of_dx12_engine_development._ver_1.2

프로그래밍 언어의 F1머신 C++을 타고 Windows 10 UWP 앱 개발의 세계로~

  • 1. 유영천 / 메이크어스 모바일 프로그래밍 언어의 F1머신 C++을 타고 Windows 10 UWP앱 개발의 세계로~
  • 2. 강연 목표 • UWP이 뭔지 알았다. • UWP을 개발하고 싶다. • UWP앱을 C++로 개발하고 싶다!
  • 3. Hello UWP App! • Windows UWP app • C++ Minecraft
  • 4. UWP(Universal Windows Platform) • Windows Platform의 새로운 API • 모바일과 터치,웹 억세스에 특화 • 모든 Windows Device API의 대통합 • X86/x64/ARM 지원 • Windows 8/8.1 – Metro App / Windows Store App • Windows 10 – UWP App
  • 8. Why UWP App? • 배포가 쉽다. • 별도의 디지털 서명이 필요없다. • Windows Store에 올릴 수 있다. • Sandbox형태로 깔끔한 설치/깔끔한 제거 • UI만들기 쉽다. • Mobile 친화적이다.(전력관리/터치입력 등) • Web과의 연동이 쉽다. • 모든 Windows 10 device에서 다 돌아간다.
  • 9. Why not UWP App? ( 불편한 진실) • 기존 코드를 얼마나 재사용할 수 있을까? ( 0% – 90%) • 이놈의 App은 되는게 없네. • Sandbox 시스템 하에서의 권한 문제 • API규모가 실제로 작음. • 아직 불안한 면도 있음. • 디바이스의 모든 기능을 사용할 수 없다. • 사실 모든 Windows 10 device간 완벽 호환도 아니다. • Windows 10 Mobile / Windows 10간에 UWP는 거의 완벽 호환 • Windows IoT와는 부분적으로 호환. • XBOX ONE 은 거의 100%일걸로 예상. • Hololense는 아직 모름.
  • 10. Desktop App vs UWP App • 개발하기 쉽다 • UWP App > Desktop App or Desktop App > UWP App ???? • 배포하기 쉽다(팔아먹기 쉽다) • UWP App >>> Desktop App • 기능(할 수 있는 것) • Desktop App >>>> UWP App • 타겟 디바이스 수 • UWP App >> Desktop App
  • 11. UWP의 기술적 특징 • Sandbox – (MS/Google/Apple중 MS가 가장 엄격함.) • 앱의 명시적 종료가 따로 없음(iOS와 비슷) • GDI사용할 수 없음. (WPF가 아니라면 UI는 새로 작성합니다.) • UI는 XAML로 작성 • C++ / Java Script(HTML) , C#으로 개발가능 • C++로 개발할때 • Win32일부 사용 가능. • Direct X 사용 가능. • 표준 C/C++ 라이브러리 어느 정도 사용 가능.
  • 13. Windows 10 App vs Windows 8.x App • 공식적으로는 둘다 Windows App으로 칭함. • UWP : Windows Runtime API for Windows 10 • Windows 8.x App : Windows Runtime API for Windows 8/8.1 • Windows Runtime -> 줄여서 WinRT • 저주받은 그 이름 Windows RT (Surface RT에 탑재된 Windows 8 on ARM) • WinRT는 Windows RT를 연상시켜서 금기시되고 있다. • 따라서 앞으론 UWP라고 부르기로 합니다.
  • 14. UWP App과 Windows 8.x App의 차이 • 사실상 Windows 10 과 Windows 8.x에서의 WinRT API의 차이 • Universal App 호환성 • Windows 8.1에선 Phone,PC 각각 XAML코드를 따로 작성해야됨. • Windows 10의 UWP에선 따로 작성할 필요없음. • 다양한 사이즈의 디스플레이를 위한 Adaptive UI지원.
  • 15. UWP App과 Windows 8.x App의 차이 • 추가적인 Win32 API/CRT추가지원.(Winsock, process관련 CRT 등) • 창모드 지원 • 드래그앤 드롭 지원. • 여러개의 인스턴스 가능.(계산기,Edge브라우저 등)
  • 16. 이제 Windows Store에서도 데스크탑에서 쓸만한 앱 을 다운로드 할 수 있게 될 것이다. megayuchi
  • 18. Why C++? • 빠르다.(빠르게 짜거나 느리게 짤 수 있다.) • 메모리 관리를 내 맘대로 • 메모리 사용량을 줄일 수 있다. • GC기반 언어와 성능차이를 만들어내는 가장 큰 이유 • 기존 코드 재사용 가능 (게임/영상처리 등) • 영상 처리나 그래픽스 코드들의 상당수가 C++로 작성되어 있다. • 기존 PC/콘솔 게임들의 100%. 모바일 게임도 상당수가 C/C++로 작성 되어 있다. • 크로스플랫폼 지원 – 모든 플랫폼이 공통적으로 지원하는 언어 는 C/C++ 뿐.
  • 19. Cross-Platform 을 위한 C++사용 사례 Building Cross-Platform Mobile Apps in C++ with Visual Studio 2015 https://channel9.msdn.com/Events/Build/2015/3-714
  • 20. C++로 UWP앱 개발 • C++만을 사용하면 좋겠지만 C++/CX를 조금은 사용해야함. • API는 호출하는 방법만 약간 다르고 C#,C++,JS 기본적으로 동일. • 예제가 없어요ㅠㅠ -> C#을 키워드에 넣어서 검색합니다. • UI는 XAML을 사용한다. (C#,JS와 동일) • C/C++ Runtime Library 사용 -> Universal CRT(ucrtbase.dll) • 8/8.1 세대의 CRT지원에 비해 제약이 상당히 줄어들었다.
  • 21. C/C++로 개발할때의 중요한 변화 • _beginthread(), _endthread()등 process.h에 선언된 스레드관련 함수들 사용 가능 • SetCurrentDirectory(),GetCurrentDirectory() 사용 가능. 이전엔 모든 path는 절대 경로로 접근해야 했음. • ARM/x86에 상관없이 HLSL Shader를 run-time에 컴파일 가능. 8.x에선 미리 빌드한 바이너리만 사용 가능했다.
  • 22. Hello World~ • 간단 라이브 코딩
  • 23. XAML UI • XAML - MS의 UI 개발용 마크업 언어 • 어떤 언어를 사용하든 UWP앱 개발을 위해서 XAML은 무조건 사용해야함. • Visual Studio에 기본 내장된 XAML Designer로 작성 가능. • Visual Studio 패키지에 포함된 Blend로 작성 가능.
  • 26. App Lifecycle – 이것만 알아둡시다. • void App::OnLaunched() • App이 실행됨. 최초 실행되었거나, 죽었다가 실행되었거나… • Suspend-> Killed -> Resume -> OnLanunched • 최초 설치됨 -> OnLaunched • Void App::OnSuspending() • 더 이상 스케쥴링되지 않음. • Phone이나 태블릿모드에서 back버튼, Windows버튼 눌렀을때. • 전화왔을때. • Desktop에서 창을 최소화시켰을때. • void App::OnResuming() • Susened상태에서 다행히(?) 죽지 않고 App으로 복귀한 경우. • OS는 메모리가 부족할 때 suspend 상태의 앱부터 죽인다.
  • 27. C++/CX • UWP API(Windows Runtime API)를 호출하기 위한 MS의 C++ 확장 • UWP의 모든 API는 객체지향. C++/CX의 ref class로 구현되어있 다. • 레퍼런스 카운팅 기반 C++ • 컴파일러가 분석해서 알아서 AddRef()와 Release()를 호출하는 게 아니고…ref class가 스마트 포인터를 내장하고 있다.
  • 28. C++/CX • C++에 C++/CLI 문법을 차용했다. -> C# 비슷한 느낌이 있다. • ref class는 내부적으로 IInspectable COM 객체 • ref class의 핸들로 포인터 연산자 *대신 ^을 사용한다. • Lambda 표현을 많이 사용함. • ppl task를 많이 사용한다.
  • 29. ref class CSimpleObject sealed { String^_Name; ~CSimpleObject(); public: // 외부에 메타데이타를 노출함. 심지어 다른 언어에서도 이 클래스의 public 멤버 호출 가능 property Platform::String^ Name // get(),set() 직접 코딩 { Platform::String^ get() { return _Name; } void set(Platform::String^ name) { _Name = name; } } property int Value; // get(),set()자동 생성 CSimpleObject(); CSimpleObject(String^ name,int value) { _Name = name; Value = value; } internal: // 이 모듈(빌드되는 바이너리) 내에서만 public. CSimpleObject^ operator+(CSimpleObject^ obj); }; ref class 선언
  • 30. #include "pch.h" #include "SimpleObject.h" CSimpleObject::CSimpleObject() { } CSimpleObject^ CSimpleObject::operator+(CSimpleObject^ obj) { CSimpleObject^result = ref new CSimpleObject(); result->Value = Value + obj->Value; result->Name = _Name + L" + " + obj->Name; return result; } CSimpleObject::~CSimpleObject() { String^Message = _Name + L" destroyedn"; OutputDebugString(Message->Data()); } ref class 구현
  • 31. void MainPage::TestRefClass() { CSimpleObject^ Obj0 = ref new CSimpleObject(L"Object 0",0); CSimpleObject^ Obj1 = ref new CSimpleObject(L"Object 1",1); CSimpleObject^ Obj2 = Obj0 + Obj1; // 새로운 객체 Obj2 생성 CSimpleObject^ Obj3 = Obj2; // Obj3이 Obj2를 참조. ref count 1 증가 Obj0 = nullptr; // ref count가 0이 되어 해제 Obj1 = nullptr; // ref count가 0이 되어 해제 Obj2 = nullptr; // ref count가 1 남아있으므로 해제되지 않음. Obj3 = nullptr; // ref count가 0이 되어 해제 } <Output> Object 0 destroyed Object 1 destroyed Object 0 + Object 1 destroyed ref class 사용
  • 32. C++/CX - Lambda • 비동기 API호출을 위해 create_task(), then()을 많이 쓰다보니 Lambda식을 자연스럽게 많이 사용하게 됨. • 이벤트 핸들러(Win32에서 콜백함수)의 상당수를 Lambda식으 로 전달 • 그냥 쓰다 보면 익숙해짐. 나름 편함. • Lambda에 대한 자세한 설명은 생략. 링크를 참조 https://msdn.microsoft.com/ko-kr/library/dd293608.aspx
  • 33. void MainPage::MessageDialogOkCancel(Platform::String^ Message) { MessageDialog^ msg = ref new MessageDialog(Message); // OK버튼을 눌렀을때의 이벤트 핸들러를 Lambda식으로 전달 UICommand^ cmdOK = ref new UICommand("OK",ref new UICommandInvokedHandler([this](IUICommand^ ) { // On Pressed OK })); // Cancel버튼을 눌렀을때의 이벤트 핸들러를 Lambda식으로 전달 UICommand^ cmdCanccel = ref new UICommand("Cancel",ref new UICommandInvokedHandler([this](IU ICommand^) { // On Pressed Cancel })); msg->Commands->Append(cmdOK); msg->Commands->Append(cmdCanccel); msg->DefaultCommandIndex = 0; msg->CancelCommandIndex = 1; msg->ShowAsync(); } Lambda식 사용
  • 34. Async API • Windows Runtime의 설계자들은 생각했다. • UI가 잠깐이라도 먹통 되는 것은 참을 수 없다!!!! • I/O작업은 미친듯이 느리다. • 그래서 그들은 이렇게 결정했다. • 어떤 작업도 UI스레드를 block시켜서는 안된다. • 모든 I/O작업은 비동기로 처리한다. • 가능하면 UI 스레드는 다른 스레드에 작업을 넘길 뿐 직접 처리하지 않 는다.
  • 35. Async API • I/O 관련 API는 모조리 Async • Async API는 ppl task의 create_task()와 같이 사용한다. • create_task().then().then().then()…. • create_task()는 Windows ThreadPool 사용하므로 task 생성 비용이 높지는 않다. • 추후 C++에서도 await가 지원될 예정. • 사실 이 문서를 작성하는 시점에서 전혀 불편함을 못 느끼고 있음.
  • 36. void FileOpenUWP::MainPage::PickButton_ClickSingle(Platform::Object^ sender, Windows::UI::Xaml: :RoutedEventArgs^ e) { FileOpenPicker^ openPicker = ref new FileOpenPicker(); openPicker->ViewMode = PickerViewMode::Thumbnail; openPicker->SuggestedStartLocation = PickerLocationId::PicturesLibrary; openPicker->FileTypeFilter->Append(".txt"); //auto ctx = task_continuation_context::use_arbitrary(); auto ctx = task_continuation_context::use_default(); create_task(openPicker->PickSingleFileAsync()).then([this](Windows::Storage::StorageFile^ fi le) { if (file) { ReadTextFromFile(file); } },ctx); } Async call – File Open
  • 37. UI스레드가 task::get()을 사용해서 Asyc 태스크의 완료를 wait할 수 있다. Then()문이 필요 없다. then().then().then()이 너무 정신 없다!!! Windows::Storage::CreationCollisionOption opt = CreationCollisionOption::ReplaceExisting; auto task_file = create_task(folder->CreateFileAsync(FileName,opt)); StorageFile^ file = nullptr; try { file = task_file.get(); } catch (Platform::Exception^ e) { String^ err = e->Message; String^ errMsg = L"Failed to CreateFileAsyc - " + err + L"n"; WriteDebugStringW(errMsg->Data()); }
  • 40. 감을 잡으셨나요? • 추가적으로 학습해야 할 내용 • XAML • C++/CX • Async API + ppl task 그때그때 검색해서 사용하다 보면 금방 익숙해집니다.
  • 42. UWP앱, 무엇을 만들까? • smi자막과 다양한 코덱을 지원하는 동영상 플레이어 • 강제 resize없고 exif 표시되는 이미지 뷰어 • Winamp같은 뮤직 플레이어 • 그림판보단 좀 그럴싸한 이미지 에디터-아이콘 에디터라든가 • Mp3 tag • 가벼운 3D 모델링 툴. Sket**up같은거? • 네트워크 툴 – ftp등 • 게임
  • 43. • 소비성이 아닌 생산성 앱이면서 무겁지 않은 앱이 적합하다. • PC/콘솔 게임과 동등한 스케일, 혹은 그에 준하는 스케일의 게 임 • 이런 앱이 모바일에서도 똑같이 작동한다면 매력적이지 않은가? UWP앱, 무엇을 만들까?
  • 44. 이런걸 만들어 봤습니다. • D3DPlayer - ffmpeg 동영상 플레이어 • 최초 발단은 Windows Phone에서 돌아가는 스트리밍 게임 클라이언트 를 만들 생각이었다. • ffmpeg , Direct X(Direct 3D, Direct 2D) , C++ • ffmepg interop 참고 (https://github.com/Microsoft/FFmpegInterop) • ffmpeg는 따로 빌드해야함. • FileTransfer - TCP기반 파일 전송 앱 • 내 Windos Phone으로 파일을 전송하고 싶은데 케이블이 없네. • 원격지의 친구에게 빠르게(peer to peer) 파일을 전송하고 싶다. • Winsock , C++
  • 46. D3DPlayer – 목표 기능 • ffmepg를 이용한 동영상 재생 • Shader를 이용한 간단한 후처리 • 비디오 출력은 D3D를 이용해서 직접 출력함. • D2D를 이용한 텍스트 출력 • Windows Phone/Tablet/Desktop 동일 작동.
  • 47. D3DVideoPlayer – 앱 구조 EXE Rendering Loop UI Thread YUV Frame Queue File or Network Decoding Thread Reader & Audio Decoder DLL Media Element D3D Display Video Audio
  • 49. D3DPlayer – 디코딩 • MediaElement사용 • 타이머 겸 오디오 스트림 출력 • XAML에서 <MediaElement x:Name="mediaElement"></MediaElement> 한 줄로 끝. • 오디오 스트림을 가지고 MediaStreamSource 세팅. • 오디오 샘플 요청이 들어오면 큐를 채움. • 비디오 샘플의 경우 디코딩 스레드가 백그라운드로 디코딩. • 디코딩해서 얻은 YUV 프레임을 큐에 쌓아둠.
  • 50. void CDecoder::DecodePacket(AVPacket avPacket) { BOOLbGotPicture = FALSE; if (avcodec_decode_video2(m_pVCtx, m_pVFrame, &bGotPicture, &avPacket) >= 0) { if (bGotPicture) { DWORDstride = m_pVFrame->linesize[0]; DWORDwidth = m_pVCtx->width; DWORDheight = m_pVCtx->height; if (avPacket.pts == AV_NOPTS_VALUE && avPacket.dts != AV_NOPTS_VALUE) avPacket.pts = avPacket.dts; Windows::Foundation::TimeSpan pts = { LONGLONG(av_q2d(m_pFmtCtx->streams[m_nVSI]->ti me_base) * 10000000 * avPacket.pts) }; Windows::Foundation::TimeSpan dur = { LONGLONG(av_q2d(m_pFmtCtx->streams[m_nVSI]->ti me_base) * 10000000 * avPacket.duration) }; PushYUVFrame(&bDestroyed, width, height, m_pVFrame->data[0], m_pVFrame->data[1], m_p VFrame->data[2], stride, (__int64)pts.Duration); } } } AVPacket으로부터 비디오 프레임 디코딩
  • 51. Direct3D/Direct2D 생성 및 초기화 • Desktop앱과 UWP앱의 DirectX 사용법은 95% 같다. • Desktop앱에선 D3D 생성에 HWND가 필요하다. • UWP앱 D3D생성에는 XALM로 페이지에 배치한 SwapChainPan el 객체가 필요하다. <SwapChainPanel x:Name="swapChainPanel"/>
  • 52. Direct3D/Direct2D 생성 및 초기화 • UWP/Desktop 모두 IDirect3DDevice로부터 ID2DDevice 인터페 이스를 얻는다. • 단 Desktop API는 HWND로부터 Direct2D 객체를 직접 생성할 수 있다. • DirectX를 사용함에 있어 UWP앱과 Desktop앱의 가장 큰 차이 점은 SwapChain을 설정하는 방법이다.
  • 53. GDI Windows Handle - HWND SwapChainPlanel <SwapChainPanel x:Name="swapChainPanel"/> in XAML Desktop Application – win32 UWP App
  • 54. ID3D11Device*pD3DDevice = NULL; // create D3DDevice...blabla IDXGIDevice1*pdxgiDevice = NULL; pD3DDevice->QueryInterface(__uuidof(IDXGIDevice1), (void**) &pdxgiDevice); IDXGIAdapter*pdxgiAdapter = NULL; pdxgiDevice->GetAdapter(&pdxgiAdapter); IDXGIFactory2*pdxgiFactory = NULL; pdxgiAdapter->GetParent(__uuidof(IDXGIFactory2), (void**) &pdxgiFactory); IDXGISwapChain1*pSwapChain = NULL; DXGI_SWAP_CHAIN_DESC1 swapChainDesc = { 0 }; // Fill swapChainDesc…blabla pdxgiFactory->CreateSwapChainForComposition(pD3DDevice, &swapChainDesc, nullptr, &pSwapChain); ISwapChainPanelNative*pSwapChainPanelNative = nullptr; reinterpret_cast<IUnknown*>(swapChainPanel)->QueryInterface(__uuidof(ISwapChainPanelNative), (v oid**) &pSwapChainPanelNative); pSwapChainPanelNative->SetSwapChain(m_pSwapChain); XAML에서 페이지에 배치한 <SwapChainPanel>객 체를 D3D에서 생성한 IDXGISwapChain1 객체와 연 결시킨다. UWP앱에서의 SwapChain생성
  • 55. D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_0 }; UINT numFeatureLevels = ARRAYSIZE( featureLevels ); DXGI_SWAP_CHAIN_DESC swapChainDesc = {0}; // Fill swapChainDesc…blabla swapChainDesc.OutputWindow = hWnd; IDXGISwapChain*pSwapChain = NULL; ID3D11Device*pD3DDevice = NULL; ID3D11DeviceContext*pImmediateContext = NULL; HRESULT hr = D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, createDevic eFlags, featureLevels, numFeatureLevels,D3D11_SDK_VERSION, &swapChainDesc, &pSwapChain, &pD3DDe vice, &m_FeatureLevel, &pImmediateContext ); Desktop앱에서의 SwapChain생성 HWND를 받아서 DXGI_SWAP_CHAIN_DESC 구조체에 넣는다. 이 구조체로 SwapChain,D3DDevice,D3DDeviceContext를 한번에 생성한다.
  • 56. D3DPlayer – 렌더링 • 게임루프 처리하듯이 60프레임으로 폴링 • 클라우드 게이밍용 클라이언트가 목적이므로 • 큐에서 현재 타임 스탬프와 일치하는 YUV프레임을 얻어옴. • YUV포맷의 이미지를 직접 텍스쳐에 써넣는다. • YUV포맷의 텍스쳐를 쉐이더 안에서 RGB로 변환 • 필터 모드에 따라 쉐이더를 다르게 선택 • 텍스트는 Direct2D를 이용해서 출력
  • 57. void MainPage::Init() { EventHandler<Object^>^ ev = ref new EventHandler<Object^>(this, &MainPage::OnUpdate); Windows::Foundation::EventRegistrationToken RenderingEventToken = CompositionTarget::Renderi ng::add(ev); } void MainPage::OnUpdate(_In_ Object^ sender ,_In_ Object^ args) { if (g_pVideoPlayer) { g_pVideoPlayer->OnRender(); } } 유휴시간을 모두 사용하는 (게임용) 렌더링 루프
  • 58. YUV프레임으로부터 텍스쳐 업데이트 - Lock void CD3DRenderer::UpdateYUVTexture(DWORD dwWidth,DWORD dwHeight,BYTE* pYBuffer,BYTE* pUBuffer, BYTE* pVBuffer,DWORD Stride) { D3D11_MAPPED_SUBRESOURCE mappedResource = {0} pDeviceContext->Map(m_pYUVTexture,0,D3D11_MAP_WRITE_DISCARD,0,&mappedResource); DWORDStrideHalf = Stride / 2;
  • 59. for (DWORD y=0; y<dwHeight; y++) { BYTE* y_buffer_entry = pYBuffer + (Stride*y); BYTE* u_buffer_entry = pUBuffer + (StrideHalf*(y>>1)); BYTE* v_buffer_entry = pVBuffer + (StrideHalf*(y>>1)); BYTE*pDestEntry = (BYTE*)mappedResource.pData + (mappedResource.RowPitch*y); for (DWORD x=0; x<dwWidth; x++) { pDestEntry[0] = *y_buffer_entry; pDestEntry[1] = *u_buffer_entry; pDestEntry[2] = *v_buffer_entry; pDestEntry[3] = 0xff; y_buffer_entry++; DWORDuv_inc = x & 0x00000001; u_buffer_entry += uv_inc; v_buffer_entry += uv_inc; pDestEntry += 4; } } YUV프레임으로부터 텍스쳐 업데이트 - Wirte
  • 62. FileTransfer - 목표기능 • Windows 10 디바이스간 파일 전송 • 여러 개의 파일 전송 가능 • 동시에 여러 개의 peer와 파일 전송 가능 • 저장할 폴더 선택 가능 • Windows Phone/Tablet/Desktop 동일 작동. • 대부분의 코드를 공유하여 Win32 CUI버전도 개발
  • 63. FileTransfer – 앱구조 Peer Finder Listen & Accept Receiver Sender Peer Finder Listen & Accept Receiver Sender File Stream Connect AppApp
  • 65. FileTransfer – peer간 접속 • UDP로 브로드캐스팅 • UDP패킷을 수신하면 TCP 포트를 열어서 listen • 파일 전송 허가를 기다림
  • 66. FileTransfer – 파일 송신/수신 • block모드 socke함수 send(),recv()사용. • 전송 이벤트 하나당 스레드 하나씩 • Win32의 경우 소켓 에러 -1만 처리하면 됨. • 파일 송수신 코드는 UWP/Desktop 99% 동일 • UWP의 경우 소켓 에러 상황에서 리턴값 외에 execption 처리 가 필요할 수 있음. (1%의 차이)
  • 67. BOOL RecvPacket(SOCKET s,char* pBuffer,int size,int* piOutSocketError) { *piOutSocketError = 0; BOOLbResult = TRUE; while (size > 0) { BOOLbException = FALSE; intiErrCodeOnException = 0; intrecv_result = -1; __try { recv_result = recv(s,pBuffer,size,0); } __except(GetExceptionCode() == EXCEPTION_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EX CEPTION_CONTINUE_SEARCH) { iErrCodeOnException = 10038; bException = TRUE; WriteDebugStringW(L"Exception was occured in recv().n"); } 패킷 수신 UWP에선 소켓에러 상황에서 SOCKET_ERROR를 리턴하는것 외 에 추가적으로 익셉션을 발생시킨다. StreamSocket이 내부적으로 winsock을 사용하기 StreamSocket을 위해 이렇게 작동하는 것으로 보인다. StreamSocket은 소켓 에러 상황을 익셉션으로 처리함.
  • 68. if (0 == recv_result) { *piOutSocketError = 0; bResult = FALSE; break; } if (SOCKET_ERROR == recv_result) { if (bException) { *piOutSocketError = iErrCodeOnException; } else { *piOutSocketError = WSAGetLastError(); } bResult = FALSE; break; } pBuffer += recv_result; size -= recv_result; } return bResult; } 패킷 수신
  • 69. FileTransfer – 파일 읽기/쓰기 • UWP • Windows::Storage::StorageFile로부터 IRandomAccessStream^ fileStre am을 얻는다. • FIleStream으로 DataWriter / DataReader를 생성, • 파일에 쓰기 - DataWriter::WriteBytes() , DataWriter::StoreAsync() • 파일로부터 읽기 - DataReader::LoadAsync() , DataReader::ReadBytes() • Desktop – win32 • CreateFile()로 파일 생성 및 오픈 • 파일에 쓰기 – WriteFile() • 파일로부터 읽기 ReadFile()
  • 70. BOOL CFileReceiver::CreateFileAndRecv(Windows::Storage::StorageFolder^ folder , String^ FileName , …. { Windows::Storage::CreationCollisionOption opt = CreationCollisionOption::ReplaceExisting; auto task_file = create_task(folder->CreateFileAsync(FileName,opt)); StorageFile^ file = nullptr; try { file = task_file.get(); } catch (Platform::Exception^ e) { String^ err = e->Message; String^ errMsg = L"Failed to CreateFileAsyc - " + err + L"n"; WriteDebugStringW(errMsg->Data()); } 폴더로부터 파일 생성 UWP앱은 완전한 Sandbox시스템이므로 아무 폴더나 임의로 억세스 할수 없다. 명시적인 방법으로 Windows::Storage::StorageFolder 객체를 얻어와야 한다.
  • 71. auto task_open = create_task(file->OpenAsync(FileAccessMode::ReadWrite)); IRandomAccessStream^ fileStream = task_open.get(); UINT64 CurPos = fileStream->Position; fileStream->Seek(ui64StartPos); CurPos = fileStream->Position; DataWriter^ dataWriter = ref new DataWriter(fileStream); 파일 오픈 UI Thread가 아니므로 task::get()으로 wait가능 파일/네트워크 스트림에 써넣기 위해서는 Windows::Storage::Stream::DataWriter를 사용한다.
  • 72. while (ui64FileSize > 0) { int recv_size = (int)MAX_RECV_SIZE_PER_ONCE; if ((UINT64)(DWORD)recv_size > ui64FileSize) { recv_size = (int)(DWORD)ui64FileSize; } if (!RecvPacket(sock,m_pRecvBuffer,recv_size,piOutSocketError)) { break; } dataWriter->WriteBytes(Platform::ArrayReference<BYTE>((BYTE*)m_pRecvBuffer, (unsigned int)re cv_size)); auto task_write = create_task(dataWriter->StoreAsync()); size_t WrittenBytes = task_write.get(); ui64FileSize -= recv_size; } 파일에 수신한 스트림 저장 실제 write작업은 StoreAsync()호출 후에 비동기로 이루어진 다. WriteBytes()에서 Write작업이 바로 이루어지지는 않는다.
  • 73. 잠깐! C#으론 못만들어요? • 물론 됩니다. • D3D , D2D , ffmepg , winsock을 사용하는 부분만 C++로 작성 하고 C#에서 호출할 수 있도록 ref class로 포장하면 됩니다. • 저라면 이렇게 복잡하게 하느니 차라리 전체를 C++로 작성하 겠습니다.
  • 74. 결론 • 같은 성능이라면 사용자는 간편하고 깔끔한 설치/제거를 원한다. • UWP앱으로 Desktop 앱의 영역을 어느 정도 대체 가능하다. • C++을 사용해서 UWP앱을 개발하면 효율적으로 Desktop앱의 코드 를 UWP앱으로 옮겨갈 수 있다. • C++은 크로스 플랫폼 개발에 가장 효율적인 언어이다. • 몇 가지 내용만 학습하면 기존 C++ 프로그래머들이 어렵지 않게 UWP앱을 개발할 수 있다.
  • 75. Q / A
  • 76. Classic Win32 개발자들이 자주 하는 질문 • MessageBox를 띄우고 싶어요. • 작업 중간에 MessageBox를 띄우고 응답이 올때까지 작업을 대기시 키고 싶어요. • WriteFile() ,ReadFile() ,fread() ,fwrite()를 사용하고 싶은데 문제가 있 나요? • 임의로 아무 폴더의 파일을 open할수 있는가? • 폴더(디렉토리)간 이동을 하려면? • DLL은 사용 가능한가요? • Memory Leak을 확인하려면? • create_task().then()이 짜증나요. • Lambda 쓰기 싫어요.
  • 77. Reference • C++/CX의 ref class객체들을 STL컨테이너와 함께 사용할 경우 ref count관리는 어떻게 이루어지는가 (http://wp.me/p6sbBj-aZ) • Windows 10 UWP에서 D3D객체들이 완전히 해제되었는지 확 인하기 (http://wp.me/p6sbBj-6P) • C++로 WIndows 10 UWP앱 개발할때 드래그 앤 드롭 처리하기 (http://wp.me/p6sbBj-7i)
  • 78. 감사합니다. • MSDN Forum http://aka.ms/msdnforum • TechNet Forum http://aka.ms/technetforum
  • 79. http://aka.ms/td2015_again TechDays Korea 2015에서 놓치신 세션은 Microsoft 기술 동영상 커뮤니티 Channel 9에서 추후에 다시 보실 수 있습니다.