블로그 이미지
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
System.String → char * (marshal_context)






■ System.String → char *

 예전 C++/CLI 에서는 System.String 문자열을 char * 형으로 변환하기 위해선
메모리를 할당하고, 할당된 메모리에 문자열을 복사하기 위해 Marshal::StringToHGlobalAuto 메소드를 호출했다.
그런 후, HGlobal 포인터를 char * 에 캐스팅 해주었다.

const char* unmanagedString = NULL;
try
{
    String^ managedString = gcnew String("managed string");
    // Note the double cast.
    unmanagedString = (char*)(void*)Marshal::StringToHGlobalAnsi(managedString);
}
finally
{
    // Don't forget to release. Note the ugly casts again. 
    Marshal::FreeHGlobal((IntPtr)(void*)unmanagedString);
}

 

 Visual Studio 2008 에서는 새로운 Marshalling Library 를 통하여 문자열을 복사하는 새로운 방법이 추가 되었다.
이 라이브러리는 Managed Code 의 System.String 과 Native Code 에서 문자열을 나타내는데 자주 쓰이는 타입
(char *, wchar_t *, BSTR, CStringT<wchar_t>, ...) 간의 변환을 쉽게 할 수 있게 해준다.

 Marshalling Library 에서는 marshal_context 라고 하는 새로운 클래스를 포함한다. 이 클래스는 문자열 변환 시
기본의 명시적으로 메모리를 해제 시켜 줘야 하는 작업을 대신 해준다. 따라서 문자열 변환 작업 시의 메모리 해제 및 누수에
대한 걱정을 덜어준다. marshal_context 클래스를 사용하는 예제는 다음과 같다.

marshal_context^ context = gcnew marshal_context();
String^ managedString = gcnew String("managed string");
const char* unmanagedString = context->marshal_as( managedString );



 기본 방법에 비해 코드가 상당히 줄어들었다. 또한 형변환을 위한 캐스팅 연산도 직접 작성하지 않아도 된다.
무엇보다도 제일 중요한 점은 char * 의 메모리 해제 시켜주는 작업을 작성하지 않아도 된다.
marshal_context 클래스는 모든 string 에 대한 참조를 유지한다. 유효 범위(scope) 를 벗어 날 때 소멸자가
그것들을 메모리 해제 시켜준다.






■ Native String → System:String




반대로 변환 하는 방법 역시 비슷하다.



System::String^ 타입을 const char *, const wchar_t *, BSTR 으로 변환하기 위해 marshal_as 를 직접 사용할 수는 없다. 왜냐하면 이러한 변환들은 사용 후에 메모리 해제를 위한 비 관리(Unmanaged) resource 를 필요로 한다. 아래와 같이 context 객체를 사용해야 한다. (즉, marshal_context 클래스의 객체 context 를 사용함으로써 marshal_context 의 소멸자가 메모리 해제를 해준다.)



context 객체는 동적 생성된 객체를 유지하다가 소멸자에서 그 메모리를 해제 시킨다. 내부적으로 할당된 객체들은 Linked-List 로 유지된다. 위의 코드에서 Console::WriteLine(context._clean_up_list.Count); 는 3을 출력 한다.




■ Extend the Marshaling Library 사용

String 타입을 변환할 때 다음과 같은 에러 메시지를 발생할 수 도 있다.

오류 1 error C4996: 'msclr::interop::error_reporting_helper<_To_Type,_From_Type>::marshal_as': This conversion is not supported by the library or the header file needed for this conversion is not included.  Please refer to the documentation on 'How to: Extend the Marshaling Library' for adding your own marshaling method.

CString 타입을 사용하려 하니까 나타난 에러 메시지 인데, MFC 사용할 때 CString 이 ATL data type 이라는 것을 얼 추 추측하긴 했지만 위와 같은 에러 메시지로 확신하게 되었다.

에러 메시지 내용대로 MSDN 의 How to:Extend the Marshaling Library 문서를 확인해 보니 ATL data type 을 위해선 marshal_atl.h 헤더 파일을 include 시켜줘야 한다.








■ 참조

1. More Tales from the Unmanaged Side - System.String -> char* : marshal_context 사용 전의 문자열 변환 방법
2. Tales from the Unmanaged Side – System.String –> char* (pt. 2)  : marshal_context 이용한 방법
3. Using marshal_as for mixed-mode string conversions : 여러 string type 의 conversion
4. Overview of Marshaling in C++
5. How to:Extend the Marshaling Library 


반응형
Posted by blueasa
, |