요즘 한창 C#에서 빠져 살고 있습니다.
이거 쓰면 쓸수록 물건 갖네요. 특히 강력한 윈폼 기능은 정말 매력적입니다.
이걸로 툴을 제작한다면 왠지 뚝딱 뚝딱 만들수 있을것 같아요.

그래서 알아봤습니다.
현재 제가 스터디 삼아 제작하고 있는 엔진을 C#에 연결하고 싶어졌쬬.
어떻게 하면 Native C++로 작성된 엔진을 C#에 띄울수 있을까?

몇 가지 방법이 있지만, 가장 잘 알려진 랩핑 기법을 쓰기로 했습니다.
이것은 엔진단을 정적 라이브러리로 작성한 후 이것을 C++/CLI(Managed C++)로 랩핑하여 DLL로 작성합니다.
그 다음 빌드된 DLL을 C# 프로젝트에서 참조 추가한 후 사용하면 되는 식이죠.

조금 복잡하고, 중간 랩핑 과정이 귀찮지만, 강력한 C#의 윈폼을 쓸수 있다면 이정도는 감수해야겠죠.

간단히 구조를 살펴 보겠습니다. 엔진부분에 해당하는 Native C++쪽은 정적 라이브러리 프로젝트로 작성합니다.
대충 밑의 구조의 클래스가 있다고 칩니다.

class CFramework
{
public:
        void Create( HWND hwnd )
        {
                // 핸들을 받아 D3D 디바이스 생성
        }
};

원래라면 이곳에 윈도우를 생성하고 생성된 윈도우의 핸들을 가져다 Direct3D를 초기화 할 것입니다.
하지만 이미 C#에 윈폼으로 윈도우를 생성해두었으니 그 윈도우를 쓰면 됩니다.
여기서 한가지 유의 할점은 윈도우 자체의 핸들을 넘겨주면 Direct3D에서 화면을 못 그립니다.
대신 윈도우에 PictureBox 컨트롤을 만들어두고 그 PictureBox 컨트롤의 핸들을 넘겨줍니다. 그러면 Direct3D에서 PictureBox에, 화면을 그릴수 있게 됩니다.

다음은 랩핑 부분입니다.
랩핑 프로젝트는 DLL로 작성을 하게 됩니다.
프로젝트 생성 후 프로젝트 속성에서 공용 언어 런타임 지원(/clr)을 설정해줍니다.

// 엔진의 정적 라이브러리
#ifdef _DEBUG
#pragma comment ( lib, "Engine_d.lib" )
#else
#pragma comment ( lib, "Engine.lib")
#endif

// 랩핑 클래스 구현
#pragma once
#include "Framework.h" // 랩핑할 Native C++ 클래스 헤더를 참조

using namespace System;
namespace CWrapper {

        public ref class CFrameworkWrapper
        {
        public:
                CFrameworkWrapper();
                ~CFrameworkWrapper();

        public:
                void Create( IntPtr hWnd )
                {
                        m_hHwnd = (HWND)hWnd.ToInt32();

                        m_pFrameWork = new CFramework();
                        m_pFrameWork->Run( m_hHwnd );
                }

        protected:
                HWND m_hHwnd;
                CFramework* m_pFrameWork;
        };
}

보시면, 랩핑을 하기위한 정적 라이브러리를 불러오고 있습니다.
그리고 해당 클래스의 헤더를 불러와 클래스를 멤버변수로 선언해주고, Create 함수에서 C#에서 보내주는 핸들을 받아 Native 클래스 객체에 넘겨주고 있습니다. 그다지 어려운것 없죠. 이렇게 Create 함수를 랩핑이 완료되었습니다.

이제는 C# 부분입니다. Widnows 응용프로그램으로 작성되어있습니다.
디자이너 페이지에서 창의 크기를 조절해준다음 컨트롤 중 PictureBox를 만들어줍니다.
그리고 솔루션 탐색기에서 C# 프로젝트의 참조 부분에 참조 추가를 해줍니다.


참조 추가 창이 뜨면, [ 찾아 보기 ]탭으로 가서 랩핑 부분인 DLL ( 미리 빌드를 해줍니다 ) 을 추가합니다.


추가가  완료 되면 이제 C#에서 랩핑쪽에 작성해둔 클래스를 가져다 쓸수 있게 됩니다.

public partial class Mainform : Form
{
        private CFrameworkWrapper m_Frameowrk;

        public Mainform()
        {
                InitializeComponent();
        }

        public void InitializeFramework()
        {
                m_Frameowrk = new CFrameworkWrapper(); 
                m_Frameowrk.Create(pictureBox1.Handle);
        }
}

이것으로 모든 준비가 되었고, C#쪽을 빌드 후, 실행해보면 Native C++쪽에 작성한 화면이 C#의 윈도우 폼에 뜨는 것을 확인할수 있을겁니다.

주의할 점은 빌드 순서입니다.
항상 C++ -> CLI -> C# 순으로 빌드를 해주어야 하고, C++쪽이나 CLI쪽이 변경되면 항상 재빌드를 걸어주셔야 합니다.
그렇지 않으면 C#의 참조 DLL이 갱신 되지않아 원하는 결과가 나오지 않을수 있습니다.

+ Recent posts