다양한 방법으로 C++ DLL String 사용하기
C#에서 C++로 문자열을 전달을 해줄때 자동으로 데이터를 맞춰주지만 C++에서 C#으로 문자열을 전달 할때는 수동으로 데이터를 맞춰야 합니다.
지금부터 다양한 방법으로 C++문자열을 C#에서 사용하는 방법을알아봅시다.
방법 1. PtrToStringAnsi 함수를 사용하여 Marshalling 하기
C++
const char* stringTest()
{
string testStr = "Ruru Test C++ String !!!";
return testStr.c_str();
}
C#
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("StringTest.dll", CallingConvention = CallingConvention.Cdecl)]
static private extern IntPtr stringTest();
static void Main(string[] args)
{
IntPtr stringPtr = stringTest();
string testStr = Marshal.PtrToStringAnsi(stringPtr);
Console.WriteLine(testStr);
Console.ReadKey();
//초기화
Marshal.FreeHGlobal(stringPtr);
}
}
C++의 const char*를 IntPtr 형태로 받아 PtrToStringAnsi 함수를 사용하여 string으로 변환하는 방법입니다.
Marshal 클래스를 사용하기 위해서는 System.Runtime.InteropServices를 추가해야 사용할 수 있습니다.
메모리 누수 방지를 위해 문자열 사용이 끝났으면 꼭 FreeHGlobal 함수를 사용하여 초기화 해주어야합니다.
방법 2. PtrToStringUni 함수를 사용하여 Marshalling 하기
C++
const wchar_t* stringTest()
{
string testStr = "Ruru Test C++ String !!!";
wstring testUni(testStr.begin(), testStr.end());
return testUni.c_str();
}
C#
using System;
using System.Runtime.InteropServices;
class Program
{
[DllImport("StringTest.dll", CallingConvention = CallingConvention.Cdecl)]
static private extern IntPtr stringTest();
static void Main(string[] args)
{
IntPtr stringPtr = stringTest();
string testStr = Marshal.PtrToStringUni(stringPtr);
Console.WriteLine(testStr);
//초기화
Marshal.FreeHGlobal(stringPtr);
}
}
C++의 const wchar_t*를 IntPtr 형태로 받아 PtrToStringUni 함수를 사용하여 string으로 변환하는 방법입니다.
Marshal 클래스를 사용하기 위해서는 System.Runtime.InteropServices를 추가해야 사용할 수 있습니다.
메모리 누수 방지를 위해 문자열 사용이 끝났으면 꼭 FreeHGlobal 함수를 사용하여 초기화 해주어야합니다.
방법 3. ICustomMarshaler를 사용하여 커스텀 Marshalling하기
C++
const char* stringTest()
{
string testStr = "Ruru Test C++ String !!!";
return testStr.c_str();
}
C#
using System;
using System.Runtime.InteropServices;
internal class StringCustom : ICustomMarshaler
{
#region ICustomMarshaler Members
public void CleanUpManagedData(object ManagedObj) { }
public void CleanUpNativeData(IntPtr pNativeData) { }
public int GetNativeDataSize()
=> -1;
public IntPtr MarshalManagedToNative(object ManagedObj)
{
throw new NotSupportedException();
}
public object MarshalNativeToManaged(IntPtr pNativeData)
=> Marshal.PtrToStringAnsi(pNativeData);
#endregion
public static ICustomMarshaler GetInstance(string cookie)
{
if (cookie == null)
{
throw new ArgumentNullException(nameof(cookie));
}
var result = new StringCustom();
return result;
}
}
class Program
{
[DllImport("StringTest.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(StringCustom))]
static private extern string stringTest();
static void Main(string[] args)
{
string testStr = stringTest();
Console.WriteLine(testStr);
Console.ReadKey();
}
}
사용자 커스텀 클래스인 ICustomMarshaler 를 사용하여 string으로 리턴받는 방법입니다.
속도가 느려 퍼포먼스가 필요한 코드라면 비추천하는 방법입니다.
방법 4. StringBuilder 함수를 사용하여 C++에서 직접 복사 하기
C++
int stringTest(char* buffer)
{
string testStr = "Ruru Test C++ String !!!";
strcpy(buffer, testStr.c_str());
return testStr.size();
}
C#
using System;
using System.Text;
class Program
{
[DllImport("StringTest.dll", CallingConvention = CallingConvention.Cdecl)]
static private extern int stringTest(StringBuilder buffer);
static void Main(string[] args)
{
StringBuilder testBuffer = new StringBuilder(100);
stringTest(testBuffer);
Console.WriteLine(testBuffer.ToString());
Console.ReadKey();
}
}
StringBuilder를 이용하여 C++에 buffer를 전달하고 C++에서 문자열을 복사하여 사용하는 방법입니다.
StringBuilder를 사용하기 위해서는 System.Text 를 추가하여야 사용할 수 있습니다.
마무리
지금까지 다양한 방법으로 C++문자열을 C#에서 사용하는 방법을 알아보았습니다.
잘못된 점이 있거나 궁금한 점이 있다면 언제든지 문의해주시기 바랍니다!
'프로그래밍 > C#' 카테고리의 다른 글
[C#] 클래스 구조의 C++ DLL 사용하기 (0) | 2024.04.25 |
---|