C로 작성된 Dll을 C#에서 작업해야 하는 상황
우선 문제가 되는 것은 다음 사항이었다.
1. 어떻게 호출해서 사용하는가?
2. 포인터는 어떤게 전달하고 전달 받는가?
● 어떻게 호출해서 사용하는가?
C++로 작성된 Dll은 Standard 호출 방식으로 선언해 주어야 한다. <== 요게 포인터다.
(Dll 작성시 아주 중요한 부분이다. 체크)
extern "C" int __declspec(dllexport) Test(int a, void* b);
C#에서 함수를 호출해서 사용하는 방법과 클래스를 호출해서 사용하는 방법 2가지가 있다.
1. 함수를 호출하는 방법
[DllImport("test.dll")]
public static extern Test(int a, IntPtr b);
2. 클래스를 받아서 사용하는 방법
해당 부분에 대해서는 정확히 설명해 놓은 부분이 없어서 엄청 고생했다. ㅋㅋ
보통 PC는 네이티브 DLL 파일을 COM에 등록시킨 다음 C#에서 참조 추가하는 방법.
요 방법이 좀 까다롭다. 그래서 추천하는 방법은 다음과 같다.
- C++에서 이런 클래스가 DLL로 되어 있고 사용하고 있다면.
class TestClass
{
public:
TestClass(int);
void foo(void);
float bar(float);
}
- 다음과 같이 Export하는 함수를 만든다.
extern "C" TestClass* __declspec(dllexport) TestClass_Ctor(int v) { return new TestClass(v); }
- C#에서는 TestClass와 동일한 함수를 갖는 인터페이스를 만들고 Export 함수로 클래스의 객체 인스턴스를
받아서 사용한다.
public interface TestClass
{
void foo();
float bar(float value);
}
public class Test
{
[DllImport("test.dll")]
public static extern TestClass TestClass_Ctor(int v);
}
static void Main(string[] args)
{
TestClass tc = TestClass_Ctor(10);
}
------------------------------------------------------------------------------------------------------------------
3. Wrapper 클래스를 사용한 방법도 있습니다.
이 방법은 PC에서는 사용할 수 있으나, 스마트장치 개발환경에서는 지원하지 않는 사항입니다.
출처: http://kindtis.tistory.com/66
-엔진단을 정적 라이브러리로 작성한 후 이것을 C++/CLI(Managed C++)로 랩핑하여 Dll로 작성합니다.
그 다음 빌드된 Dll을 C# 프로젝트에서 참조 추가한 후 사용하면 되는 식입니다.
즉, 사용하고자 하는 C++ 엔진 부분은 정적 라이브러리로 작성을 하고 C++에서 랩핑 프로젝트를
추가하여 Dll을 만든다. 이때 [프로젝트 속서]-[일반]-[공용 언어 런타임 지원]을 선택하여 만든다.
(Tip) 윈도우 자체 핸들을 받아서 Drawing 작업하면 화면에 못 그립니다.
대신 윈도우에 PictureBox 컨트롤을 만들어두고 그 PictureBox 컨트롤의 핸들을 넘겨줍니다. 그 화면에
그리면 됩니다.
● 포인터는 어떤게 전달하고 전달 받는가?
1. C++ 로 만든 Dll에서의 정의 부분
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;
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);
2. C# 호출부 작성 코드
C/C++ DLL 을 참조하기 위해 [C# 프로젝트의 속성] - [빌드 이벤트] - [빌드 후 이벤트 명령줄] 에 다음을 추가합니다.
COPY /Y "$(SolutionDir)BND.Native\$(ConfigurationName)\BND.Native.dll" "$(TargetDir)BND.Native.dll"
C/C++ DLL 파일을 C# 프로젝트의 출력 디렉토리로 복사해 오는 것입니다.
이를 위해서 프로젝트 '종속성'에 'BND.Native' 프로젝트를 추가해야 합니다.
- 구조체 캡슐화
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();
// 구조체를 초기화하는 코드를 생성자 내부에 작성합니다.
- 함수 참조 선언
// 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);
- 함수 캡슐화
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;
}
구조체를 캡슐화 했듯이, 함수들도 캡슐화해 줍니다
'프로그래밍 > 프로그래밍' 카테고리의 다른 글
[ADB] Airplane Mode 변경 (0) | 2020.11.12 |
---|---|
c# 다중언어 (0) | 2020.11.02 |
버블정렬 (0) | 2018.03.22 |
C++로 간단한 퀴즈 프로그램 만들기 (0) | 2018.03.22 |