using System.Runtime.InteropServices;
namespace Test
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct TestSet
{
[MarshalAs(UnmanagedType.I4)]
public int EntType;
[MarshalAs(UnmanagedType.I4)]
public int EntityID_1;
[MarshalAs(UnmanagedType.R8)]
public double EntityID_2;
[MarshalAs(UnmanagedType.I4)]
public int EntityID_3;
[MarshalAs(UnmanagedType.R8)]
public double EntityID_4;
[MarshalAs(UnmanagedType.R8)]
public double EntityID_5;
[MarshalAs(UnmanagedType.I4)]
public int EntityID_6;
}
}
문자열 마샬링은
를 참조하길 바란다. (뭐 유니코드쓸꺼냐, 다른 형식 쓸꺼냐 차이인듯)
이제 이를 Byte[] 배열로 변환해야 하는데, 다음과 같은 코드를 이용한다.
private byte[] getMashalData()
{
int bufferSize = Marshal.SizeOf(STRUCTOR);
IntPtr buffer = Marshal.AllocHGlobal(bufferSize);
Marshal.StructureToPtr(STRUCTOR, buffer, false);
byte[] data = new byte[bufferSize];
Marshal.Copy(buffer, data, 0, bufferSize);
Marshal.FreeHGlobal(buffer);
return data;
}
STRUCTOR 란에는 본인이 선언한 Structor 가 들어가면 된다.
한줄씩 해석해 보면,
1) int bufferSize = Marshal.SizeOf(STRUCTOR);
int bufferSize 에 마샬링에 필요한만큼의 개체 크기를 반환함.
2) IntPtr buffer = Marshal.AllocHGlobl(bufferSize);
IntPtr 에 bufferSize 만큼의 Unmanaged 메모리를 할당한다.
어려우면 그냥 C++ 에 Vector 초기화처럼 초기화한다고 생각하면 쉽다.
(Vector 도 동적할당, Delete 를 하지 않아도 되므로 비슷한 예시인듯.)
3) Marshal.StructureToPtr(STRUCTOR, buffer, false);
STRUCTOR 는 '마샬링 될 데이터가 있는 managed 개체이다. 해당 개체는 구조체, or instance 여야 한다.
buffer 는 unManaged 개체며, 당연하게도 해당 StructureToPtr() 이 호출되기 전에 '할당' 이 끝마쳐진 상태여야 한다.
4) byte[] data = new byte[bufferSize];
Return 할 byte[] 를 선언한다.
5) Marshal.Copy(Buffer, data, 0, bufferSize)
IntPtr 포인터에 저장되어 있는 주소의 위치를 참조, 이를 BufferSize 만큼 복사하여 byte[] 데이터에 삽입한디ㅏ.
6) Marshal.FreeHGlobal(buffer);
할당한 IntPtr Unmanaged 메모리를 해제한다.
7) return data
데이터 리턴.
참조
'Programming > C#' 카테고리의 다른 글
[C#] Task .Wait() vs await 차이점 (0) | 2021.05.04 |
---|---|
[C#] StructLayoutAttribute.Pack 필드 설명 (0) | 2021.04.28 |
[C#] C# 에서 대괄호가 가지는 의미, (사전 정의된 속성, 특성) (0) | 2021.04.03 |
[C#] async & await 을 lamdba 에서 사용시 오류 (0) | 2021.03.19 |
[C#] 델리게이트와 이벤트의 차이점 (0) | 2021.03.04 |