[c#] 클래쓰 인스턴쓰를 IntPtr로 변환하기
c# 프로그래밍만 할 때에는 이럴 일이 없는데 c++이나 델파이로 만든 dll을 이용한다면 클래쓰나 구조체를 포인터로 넘겨줘야 하는 경우들이 많다.
포인터는 메모리의 주소를 나타내는 결국 정수다. 특정 객체가 위치해 있는 메모리상의 위치와 그 크기만 안다면 어디에서부터 어디까지 그대로 넘겨서 데이터를 전송할 수 있다. 정수 두 개만 제어하면 되니까 아마도 대부분의 경우 정수 두 개보다는 훨씬 크기가 클 해당 객체의 실제 값(예를 들면 책 한 권 분량의 문자열)은 신경 쓰지 않아도 된다.
dll이 포인터를 요구하는 경우 .네트는 이걸 IntPtr로 처리하는데 이게 이름만 봐서는 정수형 포인터같지만 사실은 구조체다. 그런데 구조체의 구조는 각 언어마다 달라서 주소와 크기만으로는 제대로 주고 받을 수 없다. 그래서 .네트에서는 마셜링이란 작업을 한다. marshal이란 집결시킨다는 뜻으로 컴퓨터에서는 메모리에 있는 데이터를 전송을 위한 형태로 정리하는 작업을 의미한다.
우선 AllocHGlobal로 IntPtr의 메모리상의 주소와 크기를 특정하여 선언한 뒤 StructureToPtr로 IntPtr에 마셜링하여 넣는다. StructureToPtr는 이름과 달리 구조체에 국한되지 않고 클래쓰를 포함한 매니지드 객체에 이용된다. 프로그래밍은 이렇게 구체화된 명칭과 추상적 개념의 끊임 없는 충돌이다. 구체화된 실체에 얽매이지 않는 자유로운 추상적 사고가 필요하다.
IntPtr은 언매니지드 스트럭트이므로 이용을 다 한 뒤에는 직접 메모리에서 없애야 메모리 낭비를 막는다.
class TestClass
{
...
}
void ClassToIntPtr()
{
TestClass testClass = new TestClass();
IntPtr intPtr = Marshal.AllocHGlobal(Marshal.SizeOf(testClass));
Marshal.StructureToPtr(testClass, intPtr, false);
Marshal.FreeHGlobal(intPtr);
}