2009. 3. 20. 08:26

MFC를 이용한 COM Connection Point 구현

커넥션은 아래 부분으로 구성되어 있다.

 

소스 (Source)

           인터페이스를 호출하는 객체

싱크 (Sink)

           인터페이스를 구현하는 객체

 

커넥션 포인트는 소스에 의해 노출되는 인터페이스이다. 커넥션 포인트 매커니즘(IConnectionPoint 인터페이스) 통해서, 싱크 인터페이스 포인터가 소스 객체에 전달된다. 싱크 인터페이스 포인터를 이용하여 싱크 객체의 멤버 함수를 호출할 있다.

 


 

MFC CConnectionPoint CCmdTarget 클래스 내에 모델을 구현하였다. 다른 객체에 커넥션 포인트를 노출하기 위해 CConnectionPoint 상속한 클래스가 IConnectionPoint 인터페이스를 구현한다. CCmdTarget 상속한 클래스는 IConnectionPointContainer 구현하고, 그리고 클래스는 모든 이용 가능한 커넥션 포인터를 열거하거나 특정 커넥션 포인트를 찾을 있다.

 

각각의 커넥션 포인트마다 커넥션 포인트를 구현하는 connection part 선언해야 한다. 하나 이상의 커넥션 포인트를 구현한다면, 클래스 내에 single connection map 선언해야 한다. Connection Map ActiveX 컨트롤에 의해 지원되는 커넥션 포인트 테이블이다.

 

class CMyClass : public CCmdTarget

{

           ...

protected:

           // Connection point for ISample interface

           BEGIN_CONNECTION_PART(CMyClass, SampleConnPt)

                     CONNECTION_IID(IID_ISampleSink)

           END_CONNECTION_PART(SampleConnPt)

 

           DECLARE_CONNECTION_MAP()

 

};

 

BEGIN_CONNECTION_PART END_CONNECTION_PART 매크로는 내장 클래스(embedded class) XSampleConnPt (ConnectionPoint 상속한) 선언한다. CConnectinPoint 멤버함수를 재정의 하거나 멤버 함수를 추가하길 원한다면, 매크로 사이에 선언하면 된다. 예를 들면, CONNECTION_IID 매크로는 매크로 사이에 선언될 CConnectionPoint::GetIID 멤버함수를 재정의한다.

 

두번째 예제에서는, 구현 파일에 코드가 추가된다. 코드는 connection map 구현한다.

 

BEGIN_CONNECTION_MAP(CMyClass, CMyBaseClass)

        CONNECTION_PART(CMyClass, IID_ISampleSink, SampleConnPt)

END_CONNECTION_MAP()

 

하나 이상의 커넥션 포인트를 가지고 있다면, BEGIN_CONNECTION_MAP END_CONNECTION_MAP 매크로 사이에 CONNECTION_PART 매크로를 추가하면 된다.

 

마지막으로, 클래스의 생성자에 EnableConnection 호출하는 코드를 추가한다.

 

CMyClass::CMyClass()

{

        EnableConnections();

        ...

}

 

Dl 코드가 추가되면, CCmdTarget 상속한 클래스는 ISampleSink 인터페이스에 대한 커넥션 포인트를 노출시킨다.

 


 

 

보통, 커넥션 포인트는 “multicasting” 지원한다 동일한 인터페이스에 연결된 다수의 싱크에게 브로드캐스팅. 아래 예는 커넥션 포인트에 대한 각각의 싱크를 반복하면 멀티캐스트하는 방법을 보여준다.

 

void CMyClass::CallSinkFunc()

{

        const CPtrArray* pConnections = m_xSampleConnPt.GetConnections();

        ASSERT(pConnections != NULL);

 

        int cConnections = pConnections->GetSize();

        ISampleSink* pSampleSink;

        for (int i = 0; i < cConnections; i++)

        {

               pSampleSink = (ISampleSink*)(pConnections->GetAt(i));

               if(pSampleSink != NULL)

                       pSampleSink->SinkFunc();

        }

}

 

예제는 CConnectionPoint::GetConnections 호출하여 SampleConnPtr 커넥션 포인트에 대한 현재 커넥션들을 가져온다. 그러고 나서 커넥션을 탐색하면서 모든 커넥션에 대해 ISampleSink::SinkFunc 호출한다.


추가 (2009-06-08) : 연결 지점 (Connection point) 이 제대로 동작하려면 소스 파일의 BEGIN_INTERFACE_MAP 에 IID_IConnectionPointContainer 를 선언해 주어야 한다.


BEGIN_INTERFACE_MAP(CMyClass, CDocument)

        INTERFACE_PART(CMyClass, IID_ITestExeuction, Dispatch)

        INTERFACE_PART(CMyClass, IID_IConnectionPointContainer, ConnPtContainer)

END_INTERFACE_MAP()


관련글 : http://codemuri.tistory.com/entry/%EB%B2%88%EC%97%AD-ActiveX-script-hosting

From : MSDN (ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_vclib/html/bc9fd7c7-8df6-4752-ac8c-0b177442c88d.htm)