*Window XP 32bit 기준입니다.*
머......피치못할 사정으로 c++로 작성된 dll을 써야 된다면.....명복을 크크크크크크크
하지만 어차피 c++ dll은 여러모로 쓸모가 많다 보니 재판매(?)를 어느 정도 고려 할 겸, 역어셈에도 닷넷보다는 안전해 보여서 dll은 c++로 만들어 쓸 때가 있습니다.
근데 이렇게 딴 언어에서 만든 dll을 쓰기 위해서 마샬링이 필요합니다. ㅡ,.ㅡ;;;
일종의 컨버전이라고 생각하면 됩니다.
쉽게 생각하라고 컨버전이라고 한 거지 전혀 다릅니다.
컨버전은 프로그램 자체를 다른 언어에 맞게 변경시키는 것을 의미하고. 마샬링은 다른 언어에서도 읽을 수 있게 해주는 작업입니다.
마샬링은 dll자체는 변하지 않는다는 거~
마샬링하는 방법은 여러 가지가 있고 dll불러다 쓰는 방식도 여러 가지가 있으나 편의상 하나만 ㅎㅎㅎ
(절대 귀찮은 거 아니라능)
일단 자주 쓰는 것들만 해봅시다.
먼저 C++로 dll을 만들어 봅시다.
이거 안 해놓으면 고생 많이 합니다 ㅎㅎㅎ
#include <windows.h>
typedef struct tTest
{
char strTest[128]; //문자열 128
int intTest; //숫자형
BYTE byteTest[64]; //바이트형 배열
UINT uintTest[4]; //유니트형 배열
} typeTest;
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); //입출력 배열(포인터 출력가능)
>#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;
}
}
빌드하고 dll의 위치를 알아서 정하시면 되겠습니다.
테스트하기 좋게 이렇게 만들었습니다.
1이라고 적혀있는 텍스트박스가 textBox2, 그 아래가 textBox1 입니다.
버튼은 위에서부터 button1, button2, button3, button4 입니다.
클래스 안에 넣어야 합니다,
구조체는 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;
}
당연한 이야기지만 [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);
이렇게 하면 됩니다.
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"
);
}
이제 버튼을 눌러 봅시다~
잘 돌아 가네요.
마샬링은 여러 가지로 힘든 작업입니다.-_-;;;
귀찮기도하고...
아마도 처음에 기획만 제대로 해도 쓸 일이 많지 않을 겁니다. ㅋㅋㅋㅋ
마샬링에 관한 변수 타입에 대하 설명이다. 참고하도록 합니다!
참고 : http://msdn.microsoft.com/en-us/library/ac7ay120.aspx
p.s. 저는 유니트형과 바이트형을 자주 안 쓰다 보니..... 두 개 사용법이 틀렸을 수도 있습니다 ㅡ.-;
[.Net] 숫자형을 각종 문자열 포맷으로 변환하기 (0) | 2011.04.20 |
---|---|
[.Net]C#코드를 웹에서 동작확인을 시켜주다 (0) | 2011.04.19 |
[C#] 각종 날짜구하는 식 - 웹에서 바로확인 (12) | 2011.04.19 |
[.Net] 오류 - 이 행은 이미 다른 테이블에 속해 있습니다. (0) | 2011.02.04 |
[C#] c++ DLL을 C#에서 사용해보자 ( 함수 마샬링 ) (6) | 2010.12.24 |
int 함수 ( char *argv )
이런경우엔 c# 에서는 int (string )을 써야하나요?ㅠㅠ
extern "C" __declspec(dllexport) char* strOnTest3(char *strTemp); //입출력 문자열형
이것과 동일 합니다.
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);
이케 했드만 프로그램 실행시 에러 뜨네요. ㅠㅠ
구조체를 이용한 방법으로 하시면 될것 같네요.
아니면 클래스마샬링을 하셔도 됩니다,
처음의
#include <windwos.h>
</windows.h>
이 부분을 어디다 해야 하나요?
걍 C++ 의 header에 하면 되는건가요?
windows.h 가 소문자 w가 아니고 대문자 W 이고,
</windows.h> 에서 에러가 납니다...
이것 때문인가 배열 메모리로 인한 오류가 발생하는데... 자세히 좀 알려 주실 수 있으신지..
</windows.h>이거는 제가 코드를 잘못붙여넣어서 그런것이니 빼면 됩니다.(수정했습니다 ^^;)
인클루드는 헤더에 하시면 됩니다.
배열오류는 모르겠네요.
이 코드는 윈도우 xp 32비트 기준입니다,