일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- MIX10
- 김춘배
- 윈도우폰
- 헤이맨
- 황광진
- 쉐어포인트코리아
- windows mobile 6.5
- 신동혁
- 윈모데브
- UX베이커리
- 서진호
- winmodev
- 훈스닷넷
- 스마트폰
- 주신영
- 윈도우폰7
- 소년포비
- 루나네스
- 옴니아2
- 소년포비소프트
- 거제도
- 마이크로소프트
- 데브피아
- 윈도데브
- 윈도우 모바일
- 신석현
- 안드로이드
- 윈도우모바일
- 지승욱
- 실버라이트 코리아
- Today
- Total
소년포비의 세계정복!!
[C#] C/C++ 구조체와 함수를 사용하기 본문
기존의 C/C++ 의 구조체와 함수들을 C# 의 클래스로 캡슐화하는 작업을 설명드립니다.
먼저, C/C++ 에서 DLL 프로젝트를 생성합니다. (프로젝트 이름을 'BND.Native' 라고 하면 출력물은 'BND.Native.dll' 이 됩니다.)
1단계: C/C++ 구조체 정의 (MD5.h)
typedef struct mD5Context
{
UINT state[4]; /* state (ABCD) */
UINT count[2]; /* number of bits, modulo 2^64 (lsb first) */
BYTE buffer[64]; /* input buffer */
}
MD5Context;
구조체 내부에 고정 크기의 배열이 정의되어 있습니다.
2단계: C/C++ 함수 정의 (MD5.cpp)
void MD5Init(MD5Context * context)
{
...
}
void MD5Update(MD5Context * context, BYTE * input, UINT input_size)
{
...
}
void MD5Final(MD5Context * context, BYTE * output_digest)
{
...
}
C/C++ 언어답게(?) 포인터를 마구 사용하고 있습니다.
3단계: C/C++ 함수 선언 (MD5.h)
extern "C" __declspec(dllexport) void MD5Init(MD5Context * context);
extern "C" __declspec(dllexport) void MD5Update(MD5Context * context, BYTE * input, UINT input_size);
extern "C" __declspec(dllexport) void MD5Final(MD5Context * context, BYTE * output_digest);
함수들을 DLL 외부로 노출합니다.
이를 위해서 #include <Windows.h> 라인을 추가해야 합니다.
이상의 3단계를 작업한 후 컴파일하여 C/C++ DLL 을 생성합니다.
다음으로 C# 프로젝트를 생성합니다.
C# 프로그램에서 C/C++ DLL 을 참조하기 위해 [C# 프로젝트의 속성] - [빌드 이벤트] - [빌드 후 이벤트 명령줄] 에 다음을 추가합니다.
COPY /Y "$(SolutionDir)BND.Native$(ConfigurationName)BND.Native.dll" "$(TargetDir)BND.Native.dll"
C/C++ DLL 파일을 C# 프로젝트의 출력 디렉토리로 복사해 오는 것입니다.
이를 위해서 프로젝트 '종속성'에 'BND.Native' 프로젝트를 추가해야 합니다.
4단계: 구조체 캡슐화
public class MD5Calculator
{
// C/C++ 의 구조체와 동일한 형태가 되도록 정의합니다.
public struct MD5Context
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] public UInt32[] state;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] public UInt32[] count;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] public byte[] buffer;
}
// 클래스 내부에 구조체 인스턴스를 캡슐화합니다.
private MD5Context mContext = new MD5Context();
// 구조체를 초기화하는 코드를 생성자 내부에 작성합니다.
public MD5Calculator()
{
/* 따로 new 하지 않아도 이미 공간이 확보되어 있음.
mContext.state = new UInt32[4];
mContext.count = new UInt32[2];
mContext.buffer = new byte[64];
*/
}
C/C++ 에서 정의한 구조체와 동일한 구조체를 정의하고, 그 인스턴스를 정의하고, 초기화 코드를 작성하였습니다.
이 작업들을 편의상 하나의 클래스(MD5Calculator) 내에 캡슐화하였습니다.
5단계: 함수 참조 선언
// C언어 함수들
[DllImport("BND.Native.dll")] extern public static void MD5Init(ref MD5Context ctx);
[DllImport("BND.Native.dll")] extern public static void MD5Update(ref MD5Context ctx, byte[] input, int input_size);
[DllImport("BND.Native.dll")] extern public static void MD5Final(ref MD5Context ctx, byte[] output_digest);
각종 포인터 파라미터가 위와 같이 매핑됩니다.
6단계: 함수 캡슐화
public void Initial()
{
MD5Init(ref mContext);
}
public void Update(byte[] input, int input_size)
{
MD5Update(ref mContext, input, input_size);
}
public byte[] Final()
{
byte[] output_digest = new byte[16];
MD5Final(ref mContext, output_digest);
return output_digest;
}
구조체를 캡슐화 했듯이, 함수들도 캡슐화해 줍니다