C/C++과 C# 사이의 메모리 할당/해제 방법
C#과 C/C++ 사이의 메모리 전달에 대해서는 예전에도 다뤘는데요.
구조체 포인터 인자에 대한 P/Invoke 정의
; https://www.sysnet.pe.kr/2/0/912
C++ 측에서 메모리를 new로 할당한 경우, 그럴 때는 C# 측에서 해제를 하는 방법이 없습니다. 따라서 어쩔 수 없이 다시 C/C++ 측의 코드를 불러서 delete로 해제하는 절차를 따르게 되는데... 이것도 예전에 설명드렸습니다.
Win32 Interop - 크기가 정해지지 않은 배열을 C++에서 C#으로 전달하는 경우
; https://www.sysnet.pe.kr/2/0/737
C#과 C/C++은 서로 메모리 할당/해제하는 방식이 다르기 때문에 어쩔 수 없지만, 이런 경우 2개의 환경 모두에서 공통 메모리 할당 방법을 사용하면 이런 제약으로부터 자유로울 수 있습니다. 바로 이럴 때 뜻하지 않게 COM이 등장합니다. COM의 메모리 할당/해제는 OS에 의해 제공되는 방식이므로 C#과 C/C++의 환경적인 영향을 받지 않고 사용할 수 있습니다.
일례로, C/C++에서 이렇게 CoTaskMemAlloc API를 사용해 메모리를 할당해서 반환했으면,
void AllocBuffer(wchar_t **pBuffer)
{
    wstring txt = L"fvjasdflkvsadjkfjavsdkfsadjvdksajfkavsdjflajvsdkfjalkvsjflkjewoqiur092uvoifjkladjfas";
    int bufSize = txt.size() + 1;
    *pBuffer = (wchar_t *)::CoTaskMemAlloc(4096);
    *pBuffer[0] = '\0';
    wcsncpy_s(*pBuffer, bufSize, txt.c_str(), bufSize - 1);
}
WIN32PROJECT1_API wchar_t *fnWin32Project1()
{
    wchar_t *pBuffer = nullptr;
    AllocBuffer(&pBuffer);
    return pBuffer;
}
C#에서는 해당 포인터 변수 그대로 가져다가 Marshal.FreeCoTaskMem 메서드를 이용해 해제할 수 있습니다.
using System;
using System.Runtime.InteropServices;
namespace ConsoleApplication1
{
    class Program
    {
        [DllImport("Win32Project1.dll")]
        public static extern IntPtr fnWin32Project1();
        static unsafe void Main(string[] args)
        {
            IntPtr ptr = fnWin32Project1();
            {
                string txt = Marshal.PtrToStringUni(ptr);
                txt = null;
                GC.Collect();
            }
            Marshal.FreeCoTaskMem(ptr);
        }
    }
}
(
첨부한 파일은 이 글의 예제 코드를 포함합니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]