Programming/C#

C# C++ COM Interop

blueasa 2011. 11. 15. 14:38

관리되는 코드(C# or C++/CLI) 와 비관리되는 코드(C or C++)이 프로젝트에서 함께 사용되는 경우가 발생한다.
이때 사용되는 기술이 Interop 기술이다.

MSDN : 비관리 코드와의 상호운용

다음 두가지 경우를 생각해보자.

1. C++에서 C# 함수 호출


내용 보기


//-- C# Com Server ---------------------------------------------------------------------//

[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface ICOMClass
{
    void HelloWorld();
}

[ClassInterface(ClassInterfaceType.AutoDual)]
public class COMClass : ICOMClass
{
    ...

    public void HelloWorld()
    {
        MessageBox.Show("Hello");
    }
}

--> 이런 클래스가 있다면 클래스 라이브러리로 컴파일을 하고 C++에서 사용할수 있는 형식라이브러리 생성 및 등록       
      
     regasm COMClass.dll /regfile COMClass.reg
     regasm COMClass.dll /tlb:COMClass.tlb
     참고 : http://msdn.microsoft.com/ko-kr/library/tzat5yw6.aspx

//-- C++ Client -------------------------------------------------------------------------//

[[ Heaer ]]
/** #import attribute
 *        no_namespace : Specifies that the namespace name is not generated by the compiler.
 *        raw_interfaces_only : Suppresses the generation of error-handling wrapper functions and property (C++) declarations that use those wrapper functions
 *        named_guids : Tells the compiler to define and initialize GUID variables in old style, of the form LIBID_MyLibCLSID_MyCoClassIID_MyInterface, andDIID_MyDispInterface.
 **/
#import "COMClass.tlb" no_namespace raw_interfaces_only named_guids

[[ CPP ]]

HRESULT hr;
_COMClassPtr pClass;
hr = pClass->CoCreateInstance(CLSID_COMClass,NULL,CLSCTX_ALL,IID__COMClass,(void**)&pClass);
if(hr != S_OK) return;

ICOMClassPtr pIClass;
pClass->QueryInterface(IID_ICOMClass,(void**)&pIClass);
if(SUCCEEDED(hr))
    pClass->HelloWorld();

잘되었다면.. Hello 메시지 박스를 볼수 있을 것이다. 



2. C# 이벤트를 C++에서 받기

내용 보기


C#의 컨트롤에서 발생하는 이벤트를 C++에서 처리할 경우가 있다.
IDispEventSimpleImpl 를 이용하여 이벤트를 등록하는 방식을 알아보자.

[[ C# ]]
    [InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
    public interface _EventInterface
    {
        [DispId(1)]
        void ClickedEvent(int ID, bool selected);       
    }
    [ComSourceInterfaces(typeof(_EventInterface))]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    public class VCGraphControl
    {
        [ComVisible(false)]
        public delegate void ClickedEvent(int ID, bool selected);
        public event ClickedEvent ClickEvent;

        // 이벤트발생시
        public function()
        { 
            if(ClickEvent!= null) ClickEvent();
        }
    }

[[ C++ - Header ]]
extern _ATL_FUNC_INFO OnClickEventInfo;
class CEventSink : public IDispEventSimpleImpl<1, CVCMapEventSink, &DIID__EventInterface>
{
    BEGIN_SINK_MAP(CEventSink )
        SINK_ENTRY_INFO(1,DIID__EventInterface, 1, OnClickEvent, &OnClickEventInfo)
    END_SINK_MAP()

    ...

public:
    void Start()
    {
        DispEventAdvise((IUnkown*) pClass);
    }
    void Stop();
    {
        DispEventUnadvise((IUnknown*) pClass);
    }

    void __stdcall OnClickEvent(int ID, bool selected);

private:
    _COMClassPtr pClass;
    CWnd* m_pTargetWnd;
}

[[ C++ - Cpp ]] 
_ATL_FUNC_INFO OnClickEventInfo= {CC_STDCALL, VT_EMPTY, 2, {VT_INT,VT_BOOL}};

void CEventSink::OnSelectedTeacher(int ID, bool selected)
{
    ...
}

/// main
void main()
{
    ...

    CEventSink  sink = new CEventSink(this);
    sink->Start();
    
    ...

    /// release
    sink->Stop();
    delete sink;    
    ...
}

이런식으로 구현하면 될것이다. 
참고 : http://msdn.microsoft.com/ko-kr/library/b91kf2t0(VS.80).aspx



ps. 여기까지 C#의 컨트롤을 가져와 C++에서 운용하는 VS2003으로 되어있는 프로젝트를 VS2008로 업그레이드 하면서 Interop에 대하여 정리하였다. 

    닷넷1.1에서 동작하던 함수들이 닷넷2.0으로 넘어오면서 발생된 문제.. 
    http://www.codeforum.net/blog/pitoosung/entry/Net-Framework-11-에서-Net-Framework-20-으로의-Migration-CollectionBase-문제#comment1328

    Custom Object를 닷넷2.0에서 직접 가져와 사용하는 부분이 닷넷2.0에서는 불가능해진것 같다.(확실하진 않음)
    Object를 가져오는 인터페이스와 Collection Enumerator를 사용하면서 가져오는 부분은 에러를 리턴한다. 
    그래서 C++은 C#의 인터페이스 함수만 참조하게 단순화 시켰다. 

    그리고 예제 코드는 클래스 이름과 인터페이스이름을 바꾸면서 적은 코드로 동작안할 가능성이 있음.. 참조만 하시길..^^;
    관련 예제 - http://msdn.microsoft.com/ko-kr/library/65t81w8a.aspx



출처 : http://icarosss.egloos.com/1999092#none
반응형