본문 바로가기
2_ 바삭바삭 프로그래밍/C# and Visual C++

C/C++ 코드를 C# 에서 사용하는 방법(C++/CLI)

by 준환이형님_ 2011. 2. 23.

이 포스팅은 나중에 공부를 하기 위해서 가져온 것입니다.. dll을 만들어서 다른 언어에서 사용하는 이야기는 이론적으로만 간간히 들었을 뿐 아직 시도 해보지 못했거든요., 기다려, 조만간 공략해주겠어 +ㅡ+!


출처 : http://six605.tistory.com/384

■ C++/CLI 예제의 전체적인 흐름



C/C++ 코드를 C# 에서 사용하는 가장 기본적인 방법은 Wrapper 클래스를 통한 방법이다. 
C++ 코드를 컴파일 하여 Static Library 파일로 만든다. 만들어진 lib 파일을 C++/CLI 을 이용하여
감싸서 dll 파일로 만든다. 이로써 C++ 로 작성된 Native Code 를 C# 에서 이용 가능한 Managed Code 로 만든 것이다.
C# 에서는 C++/CLI 로 만들어진 dll 파일을 참조하여 사용하기만 하면 된다.




■ C++ 로 작성된 Native Code

간단하게 두개의 정수값을 인자로 받아 두 값의 합을 리턴하는 함수를 작성한다.
추후에 C++/CLI 로 감싸기 쉽게 하기 위하여 클래스로 작성한다.



Visual C++ 프로젝트 형식 → Win32 → Win32 콘솔 응용프로그램 선택




사용하려는 Native Code 를 Static Library 로 만들어야 하기 때문에 응용프로그램 설정에 "정적 라이브러리" 체크 해준다.
"미리 컴파일된 헤더" 에도 체크를 해주자(Default 설정)


솔루션 탐색기를 보면 stdafx.cpp, stdafx.h, targetver.h 3개의 파일이 만들어진다.


두개의 정수값을 인자로 받아 합을 리턴하는 함수를 클래스로 작성해 보았다.

class AddCal
{
private:    
    explicit AddCal(const AddCal &_rAddCal);    
    AddCal &operator=(const AddCal &_rAddCal);

public:
    explicit AddCal();
    virtual ~AddCal();

    int Add(int _num1, int _num2);
};
< AddCal.h >


#include "stdafx.h"
#include "AddCal.h"


AddCal::AddCal(void)
{
    // nothing
}


AddCal::~AddCal()
{
    // nothing
}


int AddCal::Add(int _num1, int _num2)
{
    return (_num1 + _num2);
}
< AddCal.cpp >


 위 코드를 컴파일 하면 "UnmanagedCal.lib" 라이브러리 파일이 생성 된다.




■ C++/CLI 를 이용하여 Native Code 감싸기

Native Code 를 Managed Assembly (.dll) 파일로 만들어야 한다.
이때 사용하는 것이 C++/CLI 로서 클래스를 작성하여 Native Code 를 감싼다.

솔루션에 새로운 프로젝트를 생성한다. 프로젝트 이름은 managedCal 이라고 정했다.



Visual C++ → CLR → 클래스 라이브러리 선택
(C++/CLI 는 Visual Studio 2005 이상부터 지원한다. 위에서와 같이 툴 자체에서 템블릿을 제공)




생성된 managedCal 프로젝트에 Native Code 로 작성했던 "AddCal.h" 헤더 파일을 추가한다.




솔루션 탐색기에서 마우스 오른족 버튼을 누르고 팝업 메뉴에서 "참조" 를 선택한다.
앞서 작성한 UnmanagedCal 프로젝트를 참조로 추가한다.


C++/CLI 를 이용하여 Native Code 를 클래스를 작성하여 감싸준다.

// managedCal.h
#pragma once
#include "..\UnmanagedCal\AddCal.h"
using namespace System;

namespace managedCal
{
    public ref class AddCalWrap
	{
    protected:
        AddCal *m_pAddCal;

    public:
        AddCalWrap();
        virtual ~AddCalWrap();

        int Add(int _num1, int _num2);
	};
}
< managedCal.h >

앞서 프로젝트에 추가한 AddCal.h 헤더파일을 include 해준다.
ref class 키워드 처럼 C++/CLI 문법을 이용하여 작성해야 한다.
여기서는 Native Code 의 AddCal 클래스 인스턴스를 참조하는 포인터 변수와 
AddCal 클래스의 Add() 함수를 호출할 멤버 함수를 정의 하였다.


// 기본 DLL 파일입니다.

#include "stdafx.h"
#include "managedCal.h"

namespace managedCal
{
    AddCalWrap::AddCalWrap()
        : m_pAddCal(new AddCal)
    {

    }

    AddCalWrap::~AddCalWrap()
    {
        if (m_pAddCal)
        {
            delete m_pAddCal;
            m_pAddCal = 0;
        }
    }

    int AddCalWrap::Add(int _num1, int _num2)
    {
        return (m_pAddCal->Add(_num1, _num2));
    }
}
< managedCal.cpp>

기본 생성자에서 Native Code 의 AddCal 클래스를 동적으로 생성한다.
소멸자 에서는 생성자에서 생성한 AddCal 클래스 인스턴스를 메모리 해제 한다.
Add() 함수는 AddCal 클래스의 Add() 함수를 호출한다.


컴파일 하면 "managedCal.dll" 파일이 만들어 진다.




■ C# 을 이용하여 C++/CLI 로 생성된 dll 파일 이용하기

이제 Managed Code 인 C# 을 이용하여 C++/CLI 로 작성된 클래스 라이브러리 파일을 사용하면 된다.

테스트할 C# 프로젝트는 간단하게 콘솔 어플리케이션으로 작성 했다.



프로젝트 이름은 CliDemo 이다.




솔루션 탐색기에서 CliDemo 프로젝트에 위에서 작성한 "managedCal" 프로젝트를 참조 추가 시킨다.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CliDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            managedCal.AddCalWrap obj = new managedCal.AddCalWrap();

            Console.WriteLine(obj.Add(1, 2));
            Console.Read();
        }
    }
}
< Program.cs >  

managedCal 프로젝트를 참조 추가 시켰으므로 managedCal 클래스를 참조할 수 있다. 인텔리센스에서 managedCal 네임스페이스가 보이지 않은다면 무엇인가 문제가 있는 것이다.
C++ Native Code 를 감싸고 있는 AddCalWrap 클래스를 동적으로 생성 시킨다. 사용하는 코드는 C# 프로그래밍을 하는 것처럼 사용한다. 생성된 인스턴스에서 Add 메소드를 호출 시키면 결과 값이 리턴된다.










개체 브라우저를 이용하여 C++/CLI 로 작성한 AddCalWrap 클래스를 보았다.
Managed Code 이기에 최상의 클래스는 Object 클래스 이며, IDisposable 인터페이스를 상속 받으므로
가비지 컬렉터가 자동적으로 메모리 해제 시켜 준다. 단, AddCalWrap 클래스에서 동적으로 생성한 AddCal 클래스는
가비지 컬렉터의 소관이 아니므로 ~AddCalWrap() 소멸자에서 명식적으로 메모리 해제 시켜줘야 한다.

 참고로 C++/CLI 를 이용한 프로젝트를 참조추가 하지 않고, 해당 dll 을 참조해도 똑같이 사용할 수 있다.
지금은 int 와 같은 간단한 정수형을 마샬링 했기 때문에 쉽게 되었지만 전달되는 인수가 복잡해지면 쉽지 않을 것 같다.
필요할 때 하나씩 알아봐야 겠다.





참조한 웹사이트는 다음과 같다.
1. c++ lib 를 c# 에서 사용하기 (c++/cli)
2. C++/CLI 강좌:C++/CLI와 C#
3. C++로 만든 라이브러리를 C#에서 사용하기