블로그 이미지
Every unexpected event is a path to learning for you. blueasa

카테고리

분류 전체보기 (2794)
Unity3D (852)
Programming (478)
Server (33)
Unreal (4)
Gamebryo (56)
Tip & Tech (185)
협업 (11)
3DS Max (3)
Game (12)
Utility (68)
Etc (98)
Link (32)
Portfolio (19)
Subject (90)
iOS,OSX (55)
Android (14)
Linux (5)
잉여 프로젝트 (2)
게임이야기 (3)
Memories (20)
Interest (38)
Thinking (38)
한글 (30)
PaperCraft (5)
Animation (408)
Wallpaper (2)
재테크 (18)
Exercise (3)
나만의 맛집 (3)
냥이 (10)
육아 (16)
Total
Today
Yesterday

내가 만든 라이브러리가 제대로 동작하는지, 그리고, 이 라이브러리는 사용하는데 있어서 문제가 없는지를 확인하기 위해서, 이를 사용한 테스트 클라이언트를 만들기로 했다. , 여기에 C#을 사용하고 싶었다. C#에서 간단히 처리할 수 있는 문제를 가지고 MFC와 씨름하면서 시간을 허비하기는 싫었기 때문에

몇 가지 방법 중에 내가 선택한 방법은 C++/CLIC++라이브러리를 감싼 다음 이를 C#에서 사용하는 것이다. 이 방법을 선택한 이유는 순전히, 시도해본 다른 방법이 모두 실패했기 때문이다. 방법이 없다 라기보다는 내가 잘 모르고 익숙하지 않아서 그렇다. 그렇다고 C++/CLI를 사용하는데 익숙한가 하면, 그것도 아니다. C++/CLI는 정말인지 필요 없다고 생각한다. 딱 한가지만 빼고. 바로 C++라이브러리를 감싸는 것. 하여튼, C++/CLI를 하나도 몰랐다. 지금도 잘 모르는 상태이기 때문에, 아래에 내가 설명하는 내용에는 다소의 오류가 있을 수도 있음을 알아주기 바란다

C++/CLI C++의 문법을 이해한다. 이 말은 C++/CLI에서 Unmanaged Code를 사용할 수 있다는 의미이다. 따라서 C# C++/CLI의 문법을 100% 이해할 수는 없다. 기본적으로 C# Managed Code이기 때문이다. 따라서 C++/CLI C++라이브러리를 잘만 감싸면, C#에서 아무런 수고 없이 이를 사용할 수 있다. 참고로 내가 사용한 Visual Studio의 버전은 2005이다

Visual C++ CLR타입 Class Library 프로젝트를 생성하고, C++로 만든 라이브러리를 포함시킨다. 사실, 이것은 Unmanaged C++을 사용할 때의 라이브러리 사용과정과 전혀 다르지 않다. 이제부터 할 일은 C++라이브러리 중에서 노출할 필요가 있는 인터페이스들을 Managed C++로 작성해주기만 하면 된다. 이 글의 주요 주제 되겠다

C++의 데이터타입은 C++/CLI에서 아래의 표와 같이 바꾼다.

 

Unmanaged Data Type

Unmanaged Data Type

Ref.

class

ref class

 

struct

value struct

 

enum

enum class

 

std::string

String^

PtrToStringAnsi()

std::map

Dictionary^

 

std::vector

List^

 

std::list

List^

 

function pointer

delegate

 

 

반드시 이와 같이 할 필요는 없다. std::vector Array로 바꾸어도 전혀 상관없다. 목표는 C++에서 데이터를 다루듯이 C#에서 이를 다룰 수 있도록 하는 것이다

C++/CLI struct C++과는 달리, value-type으로만 사용된다. reference-type으로 사용하기위해서는 class를 사용해야 한다

ref class로 선언되지 않은 클래스는 GC(Garbage Collection)의 관리를 받지 않으며, Unmanaged Code이다

C++/CLI에서의 ^ C++ *에 해당한다. 따라서 ^형으로 선언된 변수는 gcnew키워드로 생성해야 한다. gcnew로 할당된 메모리는 GC가 자동으로 해제하므로, 그에 대해 신경 쓸 필요 없다

Unmanaged String Managed String에 직접 대입될 수 없으므로, PtrToStringAnsi()함수로 사전에 변환되어야 한다. 다음은 Managed String Unmanaged String사이에 사용되는 매크로이다

 
#define MANAGEDSTR(unmanaged_string) System::Runtime::InteropServices::Marshal::PtrToStringAnsi(IntPtr::IntPtr((void*) unmanaged_string))
#define UNMANAGEDSTR(managed_string) (LPSTR)(LPCTSTR)(CString(managed_string))

C++라이브러리에서 사용되는 함수 포인터는 C++/CLI에서 적절한 델리게이트로 바뀌어야한다. GetFunctionPointerForDelegate()함수를 사용할 수도 있지만, 나의 경우는 좀 더 간단하게, Unmanaged Code로 작성한 콜백함수에서 Managed Code로 작성한 콜백함수(델리게이트)를 호출했다. 가장 까다롭게 생각했고, 실제로 시간도 많이 잡아먹은 부분이 콜백함수의 처리였지만, 의외로 싱겁게 끝나버렸다

이렇게 만들어진 라이브러리는 C#에서 바로 사용할 수 있다. 모든 인터페이스를 Managed Code로 재 작성 해야 한다는 번거로움이 있긴 하지만, 적어도 내 생각에는 이것이 가장 무난하고 또, 만만한 방법이라고 생각된다.


출처 : http://www.dogfootlife.com/archives/73

반응형
Posted by blueasa
, |