우리는 어떨때 Unsafe Code를 사용해야 할까 고민을 한다.
아래 그림과 같이 우린 Unsafe Code를 위해 아래와 같이 Setting을 해주면 된다.
그러나 그것만으로 끝나지 않는다.
여기서부터가 가장 큰 의문에 휩싸인다.
"왜~ 그리고 언제~" Unsafe Code를 사용하는 것인가?
필자가 사용한 경우를 토대로 설명을 하는게 좀 명쾌할 것 같다.
public unsafe static class DllClass
{
[DllImport("test.dll", SetLastError = true)]
public static extern ReturnValue* TestDllFunc(string strInput, ref int refTotal);
}
[StructLayout(LayoutKind.Sequential, Pack = Compile.PackSize), CLSCompliant(false)]
public unsafe struct ReturnValue
{
public fixed byte btTest[20];
public UInt16 iTest;
}
public class ReturnValue2
{
public string strTest = "";
public short iTest = 0;
}
일단 먼저 test.dll이 있어야 겠다. void형 pointer로 반환하는 것도 괜찮고, 구조체 pointer로 반환하는 것도 괜찮다. 암튼 그 내부를 구현하는건 마음이니 일단 저런식으로 한다고 치자.
저기서 중요한건 반환값이 ReturnValue 구조체 pointer형이라는 것이다.
dll 만들고, DllImport 만들어주고, 반환될 값 unsafe struct로 잘 만들어 준다.
물론, 반환되는 값의 struct 변수들은 동일해야 함은 당근이겄지만...
아래 코드들은 unsafe class내에서 이루어 져야 한다. 안그럼 저런 "*" 따윈 쓰지도 못한다.
ReturnValue* returnValues = NULL;
int nTotal = 0;
returnValues = DllClass.TestDllFunc("test string", ref nTotal);
여기서부터 중요한건 저 ReturnValue의 Array(?)를 어떻게 가공하냐는 것이다. 아래 코드를 보면
그 해답이 있다.
List<ReturnValue2> returnNodes = new List<ReturnValue2>();
ASCIIEncoding encodeASCII = new ASCIIEncoding();
for (int i = 0; i < nTotal; i++)
{
byte[] btTest = null;
ReturnValue2 rt = new ReturnValue2 ();
rt.iTest = (short)returnValues ->iTest ;
PtrToBuffer(returnValues->btTest, ref btTest );
rt.strTest = encodeASCII.GetString(btTest);
returnNodes.Add(rt);
}
/// <summary>
/// 포인터 스트링에서 byte Buffer로 변환
/// </summary>
[CLSCompliant(false)]
private int PtrToBuffer(byte* ptr, ref byte[] buffer)
{
int size = ByteStrLen(ptr);
if (size > (buffer == null ? 0 : buffer.Length))
Array.Resize<byte>(ref buffer, size);
if (ptr != null)
Marshal.Copy((IntPtr)ptr, buffer, 0, size);
return size;
}
/// <summary>
/// 길이 계산해서 Byte String으로 변환
/// </summary>
[CLSCompliant(false)]
private static int ByteStrLen(byte* str)
{
byte* tmp = str;
int len = 0;
if (tmp != null)
{
while (*tmp != 0) tmp++;
len = (int)(tmp - str);
}
return len;
}
위와 같은 아름다운 코드로 인해 닷넷에서 struct 포인터 반환형을 사용할 수 있는 것이다.
여러 짱나는 마샬링을 통해 처리하는 것보다 때로는 위와 같이 처리하는 것이 보다 더 깔끔하지 않을까 한다.
[출처] 닷넷 Unsafe Code의 묘미 with DllImport|작성자 다이아
'닷넷' 카테고리의 다른 글
[닷넷] Visual studio 파일선택하면 솔루션탐색기 파일 위치로 이동하게 설정 (0) | 2023.07.26 |
---|---|
c# 가상메소드, 추상메소드 (0) | 2012.03.27 |
c# String 과 string의 차이 (0) | 2012.03.27 |