, , ,

 

*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. 저는 유니트형과 바이트형을 자주 안 쓰다 보니..... 두 개 사용법이 틀렸을 수도 있습니다 ㅡ.-;

 

  1. 질문이요 2012.05.30 11:55 신고  Address  Edit/Delete  Reply

    int 함수 ( char *argv )
    이런경우엔 c# 에서는 int (string )을 써야하나요?ㅠㅠ

  2. 질문이요2 2012.06.21 14:48 신고  Address  Edit/Delete  Reply

    void 함수 (RECT & rectTarget)
    이런경우엔 C# 에서 어케 써야 하나요? ㅠㅠ

    public struct RECT
    {
    public int top;
    public int left;
    public int bottom;
    public int right;
    }

    public static extern void 함수(ref RECT rectArea);

    이케 했드만 프로그램 실행시 에러 뜨네요. ㅠㅠ

  3. 이코스타 2013.01.26 13:24 신고  Address  Edit/Delete  Reply

    처음의
    #include <windwos.h>
    </windows.h>
    이 부분을 어디다 해야 하나요?

    걍 C++ 의 header에 하면 되는건가요?
    windows.h 가 소문자 w가 아니고 대문자 W 이고,
    </windows.h> 에서 에러가 납니다...
    이것 때문인가 배열 메모리로 인한 오류가 발생하는데... 자세히 좀 알려 주실 수 있으신지..

    • Favicon of http://blog.danggun.net BlogIcon 당근천국 2013.01.26 13:47 신고  Address  Edit/Delete

      </windows.h>이거는 제가 코드를 잘못붙여넣어서 그런것이니 빼면 됩니다.(수정했습니다 ^^;)

      인클루드는 헤더에 하시면 됩니다.
      배열오류는 모르겠네요.

      이 코드는 윈도우 xp 32비트 기준입니다,

댓글 작성

이름
패스워드
홈페이지
비밀글

티스토리 툴바