[C++] C++ Dll 만들어서 C#에서 사용하기 (마샬링)


Development note/C , C++ , MFC  2012. 9. 23. 22:14

안녕하세요. 명월입니다.


이번 글은 C++에서 Dll을 만들어 C#에서 사용하는 방법에 대한 내용입니다.


마샬링에 대한 내용은 어트리뷰트의 내용이 포함되어있습니다.

링크 - [C#] 어튜리뷰트 - (Atturibute)


우리가 C#으로 프로그램을 만들 때는 .Net Framwork 기반으로 개발합니다. 그래서 .Net Framework의 안에 있는 라이브러리와 구조를 벗어나서 개발할 수가 없습니다. 예를 들면 후크에 대해서 MSDN을 살펴보면 C#은 전역후크(Window API)를 지원 하지 않습니다. 그냥 Com+ 를 사용하라고 되어있습니다.(링크를 찾아보려 했는데 나오지 않네요.)

이럴 때는 C++의 Window Api를 가져와서 사용할 수밖에 없습니다.


또, 프로그램 언어를 C++에서 C#으로 변경할 경우, C++의 모듈을 몽땅 버리고 처음부터 다시 개발하는 것이 아니고 C++의 라이브러리는 그대로 가져와서 한개한개 개선하는 경우도 많습니다.

그럼 C++과 C#의 라이브러리를 연결하는 방법에 대해 알아보겠습니다.

먼저, C++의 DLL을 작성하겠습니다.

(저는 Visual Studio 2010의 C++ 기본 설정이 달라서 2008에서 작성하였습니다. 2010에서 사용해도 다른 점이 없습니다.)

int test1=0;
CString test2;
//외부 함수
extern "C" __declspec(dllexport) void Dll_Int_Insert(int _data)
{
  test1 = _data;
  printf("%d\n",test1);
}
//외부 함수
extern "C" __declspec(dllexport) int Dll_Int_Return()
{
  return test1;
}
//외부 함수
extern "C" __declspec(dllexport) void Dll_String_Insert(char* _data)
{
  test2.Format("%s",_data);
  printf("%s\n",test2);
}
//외부 함수
extern "C" __declspec(dllexport) LPCTSTR Dll_String_Return()
{
  return (LPCTSTR)test2;
}

여기서 잠깐 살펴보고 갈 내용은 C++ 과 C#은 대부분의 자료형은 같습니다. 그러나 C++를 자료형이 없으므로 약간의 형 변환이 필요합니다. String을 받을 때는 포인터로 이용한 동적 배열로 받아들리면 되겠습니다.

Return을 할 때는 LPCSTR(Long Pointer Char String) 형으로 반환을 하면 되겠습니다.


다음은 C# 코드의 마샬링 부분이겠습니다.

using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace Dll_20120923_1_
{
  class Program
  {
    //외부 함수 Import
    [DllImport("Dll_20120923[0].dll")] 
    public static extern void Dll_Int_Insert(int _data);

    //외부 함수 Import
    [DllImport("Dll_20120923[0].dll")] 
    public static extern int Dll_Int_Return();
    
    //외부 함수 Import
    [DllImport("Dll_20120923[0].dll")] 
    public static extern void Dll_String_Insert(char[] _data);
    
    //외부 함수 Import
    [DllImport("Dll_20120923[0].dll")]
    public static extern StringBuilder Dll_String_Return();

    static void Main(string[] args)
    {
      //외부 함수 호출
      //10을 입력하고 콘솔 창에 10출력
      Dll_Int_Insert(10);

      //10이 출력됨
      Console.WriteLine("Dll_Int_Return : {0}",Dll_Int_Return());


      //String을 char 배열 형식으로 변환한다.
      //Char배열로 바꾼후 넘긴다.
      //콘솔 창에 명월 출력
      String _data = "명월";
      char[] _data_char = _data.ToCharArray();              
      Dll_String_Insert(_data_char);

      //메모리 타입으로 참조받음
      StringBuilder SB = Dll_String_Return();
      Console.WriteLine("Dll_String_Return: {0}",SB);

      Console.WriteLine("Press Any key...");
      Console.ReadLine();
    }
  }
}

어튜리뷰트로 해당 라이브러리를 취득해오고 해당 함수을 선언합니다.

String의 부분은 체크를 해야 하는데(C++은 String이 없습니다.) C++에서의 포인터로 String값을 받는 부분은 char배열(메모리 배멸)로 넘깁니다.

문제는 LPCSTR 부분인데 String도 클래스이기는 하지만 파라미터로 참조형식으로 받을 수가 없기 때문에 Stringbuilder클래스로 받아와야 합니다.

C++로 작성한 Dll를 복사해 넣겠습니다.

예제 파일 첨부합니다.

Dll_20120923[0].zip

Dll_20120923[1].zip