본문 바로가기
컴퓨터/C#

C#에서 C++ DLL 사용하기

by Luyin 2013. 6. 29.

C#에서 C++ DLL 사용하기

C++ DLL return char *, C++ DLL 문자열 인자 전달


예제에서 사용된 DLL은 Unmanaged C++(관리되지 않은 C++)로 만들어졌다.

예제에서는 Static DLL 호출 방법을 사용하였다.

예제는 (Visual Studio 2012) 비주얼 스튜디오 2012에서 작성하였다.


[새 프로젝트]-[Visual C++]-[Win32 프로젝트]

솔루션이름 : JINGUDLL

응용프로그램 종류 : DLL

추가 옵션 : 빈 프로젝트

 jingudll.cpp

#include <stdio.h>
#include <string.h>
#include <windows.h>		//LocalAlloc, LPTR

#define EXPORTDLL extern "C" __declspec(dllexport)

EXPORTDLL char* getMessage();
EXPORTDLL void copyMessage(char * _input, char * _output);
extern "C" void printMessage(char* _input);

//dll 내부의 모든 코드는 extern "C" 안에 정의 되어야 한다.
extern "C"
{
	//C#에서 불러다 쓸 수 없다.
	//dll 내부에서만 호출이 가능하다.
	char * result = "C++ Dll로부터 응답"; 

	void printMessage(char * _input)
	{
		printf("'%s' is came from C# \n",_input);
	}
}

EXPORTDLL char* getMessage()
{
	char * returnchar = (char*)LocalAlloc(LPTR, strlen(result)+1);

	strcat(returnchar, result);
	return returnchar;
}

EXPORTDLL void copyMessage(char * _input, char * _output)
{
	printMessage(_input);
	strcpy(_output, _input);
}


위의 소스를 빌드 후 프로젝트 폴더의 경로에 가보면 "JINGUDLL.dll" 파일이 생성되어 있다. 이 파일을 아래에 새롭게 생성한 C# 프로젝트 내의 실행 파일과 같은 경로에 파일을 복사한다.



[새프로젝트] - [Visual C#] - [콘솔 응용프로그램]

 Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;

namespace DLLTEST
{
    class Program
    {
        [DllImport("JINGUDLL.dll", CallingConvention =CallingConvention.Cdecl)]
        private static extern IntPtr getMessage();

        [DllImport("JINGUDLL.dll", CallingConvention = CallingConvention.Cdecl)]
        private static extern void copyMessage(StringBuilder _input, StringBuilder _output);

        static void Main(string[] args)
        {
            IntPtr ptr = getMessage();
            string Message = Marshal.PtrToStringAnsi(ptr);
            Marshal.FreeHGlobal(ptr);
            Console.WriteLine("C++ Dll로 부터 리턴된 char* : {0}", Message);

            StringBuilder _input = new StringBuilder("This is value");
            StringBuilder _output = new StringBuilder();
            copyMessage(_input, _output);
            Console.WriteLine("C++ DLL 내에서 변경된 _output의 값은 {0}",_output);
        }
    }
}


C, C++언어에서의 char * 에 대응 되는 C#의 자료형은 String이 아니다. StringBuilder 이다.

C, C++언어에서의 char * 리턴을 받을 때 주소값을 저장할 수 있는 IntPtr 자료형을 사용하여야 한다.

DllImport시에 CallingConvention =CallingConvention.Cdecl 을 꼭 선언해주어야 한다.

DLL에서 LocalAlloc으로 할당한 메모리는 C#에서 Marshal.FreeGlobal()로 제거해 주어야 한다.