2010. 12. 24. 21:20

관련글
c++ DLL을 C#에서 사용해보자 ( 함수 마샬링 )
c++ DLL을 C#에서 사용해보자 ( 클래스 마샬링 )

 

*Window XP 32bit 기준입니다.*


머......피치못할 사정으로 c++로 작성된 dll을 써야 된다면.....명복을 크크크크크크크

하지만 어차피 c++ dll은 여러모로 쓸모가 많다 보니 재판매(?)를 어느 정도 고려 할 겸, 역어셈에도 닷넷보다는 안전해 보여서 dll은 c++로 만들어 쓸 때가 있습니다.

근데 이렇게 딴 언어에서 만든 dll을 쓰기 위해서 마샬링이 필요합니다. ㅡ,.ㅡ;;;

 

일종의 컨버전이라고 생각하면 됩니다.
쉽게 생각하라고 컨버전이라고 한 거지 전혀 다릅니다.

컨버전은 프로그램 자체를 다른 언어에 맞게 변경시키는 것을 의미하고. 마샬링은 다른 언어에서도 읽을 수 있게 해주는 작업입니다.

마샬링은 dll자체는 변하지 않는다는 거~

마샬링하는 방법은 여러 가지가 있고 dll불러다 쓰는 방식도 여러 가지가 있으나 편의상 하나만 ㅎㅎㅎ
(절대 귀찮은 거 아니라능) 

일단 자주 쓰는 것들만 해봅시다.

 

1. C++ DLL

먼저 C++로 dll을 만들어 봅시다.

 

1-0. 인크루드

이거 안 해놓으면 고생 많이 합니다 ㅎㅎㅎ

 

#include <windows.h>

 

 

1-1. 구조체 (test.h)

 

typedef struct tTest
{
	char  strTest[128]; //문자열 128
	int   intTest;    //숫자형
	BYTE byteTest[64]; //바이트형 배열
	UINT  uintTest[4];  //유니트형 배열
} typeTest;

 

 

 

1-2. 함수(test.h)
//기본형
extern "C" __declspec(dllexport) void	OnTest1(void);
//입출력 숫자형
extern "C" __declspec(dllexport) int	intOnTest2(int intTemp);
//입출력 문자열형
extern "C" __declspec(dllexport) char*	strOnTest3(char *strTemp);
//입력 구조체(포인터 출력가능)
extern "C" __declspec(dllexport) void	OnTest4(typeTest *testTemp);
//입출력 배열(포인터 출력가능)
extern "C" __declspec(dllexport) void	OnTest5(int *intTemp);

 

 

 

1-3. 함수 내용(test.cpp)
#include "claTest.h"
 
void OnTest1(void)
{
	//기본형
}
 
int intOnTest2( int intA)
{
	//입출력 숫자형
 
	++intA; //입력받은 숫자에 +1
 
	return intA;
}
 
char* strOnTest3(char *strTemp)
{
	//입출력 문자열형
 
	static char strTemp2[128] = {0,};	//임시저장용 문자열
	sprintf_s( strTemp2, "%s strOnTest3 에서 리턴", strTemp);	//문자열 합치기
 
	return strTemp2;
}
 
void OnTest4( typeTest *testTemp )
{
	//입력 구조체형(포인터 출력가능)
 
	testTemp->byteTest[0] = 1;
	testTemp->intTest = testTemp->intTest + 2;
	sprintf_s( testTemp->strTest, "%s OnTest4에서 포인터", testTemp->strTest);
	testTemp->uintTest[0] = 1;
}
 
void OnTest5(int *intTemp)
{
	//입출력 배열형(포인터 출력 가능)
	for( int i = 0 ; i < 10 ; ++i )
 	{
		intTemp[i] = intTemp[i] + i;
	}
}

 

 

 

1-4. 빌드

빌드하고 dll의 위치를 알아서 정하시면 되겠습니다.

 

 

2. c# 응용프로그램

 

2-1. C#을 만들자

 

 

테스트하기 좋게 이렇게 만들었습니다.

1이라고 적혀있는 텍스트박스가 textBox2, 그 아래가 textBox1 입니다.

버튼은 위에서부터 button1, button2, button3, button4 입니다.

 

 

2-2. 구조체 마샬링( Form1.cs )

 클래스 안에 넣어야 합니다,

구조체는 dll에 넣고 뺄 때만 사용하기 때문에 그때만 양쪽의 형식이 맞으면 되니 알아서들 잘 쓰시고 여기 나와 있는 건 규격이라고 생각하면 됩니다.

 

public struct typeTest
{
	//문자열 124
	[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
	public String strTest;
 
	//숫자형
	public int intTest;
 
	//바이트 배열
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)]
	public byte[] byteTest;
 
	//유니트형 배열
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
	public UInt32[] uintTest;
}

 

 

2-3. 함수 마샬링

당연한 이야기지만 [DllImport("dll경로 및 이름")] 입니다.

여기서는 함수의 입출력 타입이 정확해야 합니다.

[DllImport("test1.dll")]
extern public static void OnTest1();
 
[DllImport("test1.dll")]
extern public static int intOnTest2(int intTemp);
 
[DllImport("test1.dll")]
extern public static string strOnTest3(string strTemp);
 
[DllImport("test1.dll")]
extern public static void OnTest4(ref typeTest testTemp);
 
[DllImport("test1.dll")]
extern public static void OnTest5(int[] intTemp);

 

 

2-4. 그럼 사용은?

이렇게 하면 됩니다.

 

private void button1_Click(object sender, EventArgs e)
{
	OnTest1();
}
 
private void button2_Click(object sender, EventArgs e)
{
	MessageBox.Show(intOnTest2(int.Parse(textBox2.Text)) + " = intOnTest2(" + textBox2.Text + ")");
}
 
private void button3_Click(object sender, EventArgs e)
{
	MessageBox.Show(strOnTest3(textBox1.Text) + " = strOnTest3(" + textBox1.Text + ")");
}
 
private void button4_Click(object sender, EventArgs e)
{
	typeTest testTemp = new typeTest();
 
	testTemp.byteTest = new byte[64];
	testTemp.uintTest = new uint[4];
 
	testTemp.strTest = textBox1.Text;
	testTemp.intTest = int.Parse(textBox2.Text);
	testTemp.byteTest[0] = byte.Parse(textBox2.Text);
	testTemp.uintTest[0] = uint.Parse(textBox2.Text);
 
 
	OnTest4(ref testTemp);
 
	MessageBox.Show(textBox1.Text + " => " + testTemp.strTest + "\r\n"
			+ textBox2.Text + " => " + testTemp.intTest + "\r\n"
			+ textBox2.Text + " => " + testTemp.byteTest[0] + "\r\n"
			+ textBox2.Text + " => " + testTemp.uintTest[0] + "\r\n"
			);
}
 
private void button5_Click(object sender, EventArgs e)
{
	int[] intTemp = new int[5];
 
	intOnTest5(intTemp);
 
	MessageBox.Show( intTemp[0] + "\r\n"
			+ intTemp[1] + "\r\n"
			+ intTemp[2] + "\r\n"
			+ intTemp[3] + "\r\n"
			+ intTemp[4] + "\r\n"
			);
}

 

 

2-5. 눌러보자

이제 버튼을 눌러 봅시다~

 

잘 돌아 가네요.

 

 

마무리

마샬링은 여러 가지로 힘든 작업입니다.-_-;;;

귀찮기도하고...

아마도 처음에 기획만 제대로 해도 쓸 일이 많지 않을 겁니다. ㅋㅋㅋㅋ

 

마샬링에 관한 변수 타입에 대하 설명이다. 참고하도록 합니다!

참고 : http://msdn.microsoft.com/en-us/library/ac7ay120.aspx

 

 

p.s. 저는 유니트형과 바이트형을 자주 안 쓰다 보니..... 두 개 사용법이 틀렸을 수도 있습니다 ㅡ.-;