C#과 C++ 사이의 Interop 완성하기 – Step 3.

이번 시간에는 지난 번 시간을 이어 마지막으로 C++에서 제작한 클래스를 바인딩하는 C# 클래스를 만들어보도록 하겠습니다.


* 지난번 글을 다시 여시지 않도록 하기 위하여 클래스를 다시 정의합니다.



    // TestClass.h에 정의하는 내용입니다.


    class TestClass


    {


    public:


        void TestFunction(int value);


        int MyFunction(void);

    private:


        int m_myValue;

    public:


        int GetMyValue(void);


        void SetMyValue(int value);

    public:


        TestClass(int value);


    }

    // TestClass.cpp에 정의하는 내용입니다.


    #include <iostream>

    void TestClass::TestFunction(int value)


    {


        stdout << value;


    }

    int TestClass::MyFunction(void)


    {


        return 123;


    }

    int TestClass::GetMyValue(void)


    {


        return this->m_myValue;


    }

    void TestClass::SetMyValue(int value)


    {


        this->m_myValue = value;


    }

    TestClass::TestClass(int value)


    {


        SetMyValue(value);


    }

6. 프록시 함수의 완성본 만들기

    #ifdef MSC_VER // VC++ 컴파일러를 위한 Export 구문 설정 (DLL 버전)


       #define EXPORT extern “C” __declspec(dllexport)


    #else // VC++ 이외의 컴파일러를 위한 Export 구문 설정 (적절한 설정이 필요할 수도 있습니다.)


       #define EXPORT


    #endif

    EXPORT TestClass* TestClass_ctor(int value)


    {


       return new TestClass(value);


    }

    EXPORT void TestClass_dtor(TestClass* pInstance)


    {


       if(pInstance != NULL)


            delete pInstance;


       pInstance = NULL;


    }

    EXPORT void TestClass_TestFunction(TestClass* pInstance, int value)


    {


       if(pInstance != NULL)


           pInstance->TestFunction(value);


    }

    EXPORT int TestClass_MyFunction(TestClass* pInstance)


    {


       if(pInstance != NULL)


           return pInstance->MyFunction();


       return 0;


    }

    EXPORT int TestClass_GetMyValue(TestClass* pInstance)


    {


       if(pInstance != NULL)


           return pInstance->GetMyValue();


       return 0;


    }

    EXPORT int TestClass_SetMyValue(TestClass* pInstance, int value)


    {


       if(pInstance != NULL)


       {


           pInstance->SetMyValue(value);


           return 1;


       }


       return 0;


    }


7. C#에서 라이브러리 참조하기


Windows의 C++ 컴파일러를 사용해서 컴파일할 경우 DLL로 컴파일시키며, Linux/Unix/Mac OS X 등의 C++ 컴파일러를 사용해서 컴파일할 경우 Dynamic Library (확장자는 대개 so 파일)로 컴파일시킵니다. 그리고 Windows에서는 %windir%system32 디렉터리에, Linux에서는 /usr/lib과 같은 라이브러리 파일을 집결시키는 디렉터리에 만들어진 라이브러리를 배치합니다. 혹은 C# 프로그램 파일이 있는 곳에 같이 배치해도 됩니다.



    using System;


    using System.Runtime.InteropService;

    public sealed class TestClassBinding


    {


       // 모든 프록시 함수는 이 변수를 참조합니다.


       private IntPtr rawValue = null;

       [DllImport(“라이브러리 파일 이름”)]


       private static extern IntPtr TestClass_ctor(int value);

       [DllImport(“라이브러리 파일 이름”)]


       private static extern void TestClass_dtor(IntPtr instance);

       [DllImport(“라이브러리 파일 이름”)]


       private static extern void TestClass_TestFunction(IntPtr instance, int value);

       [DllImport(“라이브러리 파일 이름”)]


       private static extern int TestClass_MyFunction(IntPtr instance);

       [DllImport(“라이브러리 파일 이름”)]


       private static extern int TestClass_GetMyValue(IntPtr instance);

       [DllImport(“라이브러리 파일 이름”)]


       private static extern int TestClass_SetMyValue(IntPtr instance, int value);

       public TestClassBinding(int value)


       {


           this->rawValue = TestClass_ctor(value);


       }

       ~TestClassBinding()


       {


           TestClass_dtor(this->rawValue);


       }

       public void TestFunction(int value)


       {


           TestClass_TestFunction(this->rawValue, value);


       }

       public int MyFunction()


       {


           return TestClass_MyFunction(this->rawValue);


       }

       public int MyValue


       {


           get


           {


               return TestClass_GetMyValue(this->rawValue);


           }


           set


           {


               try


               {


                   if(TestClass_SetMyValue(this->rawValue, value) == 0)


                       throw new Exception(“할당되지 않은 포인터를 사용하려 했습니다.”);


               }


               catch(Exception ex)


               {


                   Console.WriteLine(ex.Message);


               }


           }


       }

       public int GetMyValue()


       {


           return TestClass_GetMyValue(this->rawValue);


       }

       public void SetMyValue(int value)


       {


           try


           {


               if(TestClass_SetMyValue(this->rawValue, value) == 0)


                   throw new Exception(“할당되지 않은 포인터를 사용하려 했습니다.”);


           }


           catch(Exception ex)


           {


               Console.WriteLine(ex.Message);


           }


       }


    }


이것으로 세 단계에 걸친 강좌를 모두 끝내도록 하겠습니다. 다음 시간에는 또 다른 토픽을 가지고 강좌를 올리도록 하겠습니다. 많은 도움이 되셨기를 바랍니다. ^^

댓글 남기기