This blog is only to remind myself of what I've learned (from others or by myself) and only for knowledge sharing. External sources will be clearly stated in [Reference] of each article. I hope this blog won't infringe any copyrights and that it can be useful for interested blog readers.

2008年4月15日 星期二

COM client with Connection Point

 

Goal:

Create a project where we use a COM client with Connection Point function.

 

Preface:

(1) VC6 IDE is necessary

 

 

Steps:

(1) Create a Win32 Console Application project

 

(2) create a simple "hello world" application

 

(3) Prepare to create a new class "Sink"

 

(4) "Sink" Class should derive from _IAddEvents, where is used to connect COM server.

 

(5) Just press "ok" when meeting this message

 

(6) Sink.h sample code

// Sink.h: interface for the CSink class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_SINK_H__F90A535B_4A71_433A_9A96_DE06BBEAB53C__INCLUDED_)
#define AFX_SINK_H__F90A535B_4A71_433A_9A96_DE06BBEAB53C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "../Test_COM_Connection_Point/Test_COM_Connection_Point.h"
#import "../Test_COM_Connection_Point/Test_COM_Connection_Point.tlb" named_guids raw_interfaces_only

#include <stdio.h>

class CSink : public _IAddEvents 
{
private:
    DWORD       m_dwRefCount;
public:
    CSink();
    virtual ~CSink();

    // added by Mark manually -- Start

    STDMETHODIMP ExecutionOver(int Result)
      {
      printf("CSink::ExecutionOver::The result is %d", Result);
      return S_OK;;

      };

//IUnknown member functions -- QueryInteface, AddRef, ReleaseRef

    HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject)
      {
        if (iid == DIID__IAddEvents)
        {
          m_dwRefCount++;
          *ppvObject = (void *)this;
          return S_OK;
        }
        if (iid == IID_IUnknown)
        {
          m_dwRefCount++;
          *ppvObject = (void *)this;
          return S_OK;
        }
        return E_NOINTERFACE;

      }

    ULONG STDMETHODCALLTYPE AddRef()
      {
        m_dwRefCount++;
        return m_dwRefCount;
      }

    ULONG STDMETHODCALLTYPE Release()
      {
        ULONG l;
        l  = m_dwRefCount--;
        if ( 0 == m_dwRefCount)
           delete this;

        return l;
      }

    // IDispatch member functions -- GetIDsOfNames, GetTypeInfo, GetTypeInfoCount, Invoke
    STDMETHOD(GetIDsOfNames)( REFIID /*riid*/,
                              OLECHAR FAR *FAR *rgszNames,
                              unsigned int cNames,
                              LCID lcid,
                              DISPID FAR* /*rgDispId*/ )
    {
        UNREFERENCED_PARAMETER(rgszNames);
        UNREFERENCED_PARAMETER(cNames);
        UNREFERENCED_PARAMETER(lcid);
        return E_NOTIMPL;
    }

    STDMETHOD(GetTypeInfo)( unsigned int iTInfo,
                            LCID lcid,
                            ITypeInfo FAR *FAR *ppTInfo )
    {
        UNREFERENCED_PARAMETER(iTInfo);
        UNREFERENCED_PARAMETER(lcid);
        UNREFERENCED_PARAMETER(ppTInfo);       
        return E_NOTIMPL;
    }

    STDMETHOD(GetTypeInfoCount)( unsigned int FAR *pctinfo )
    {
        UNREFERENCED_PARAMETER(pctinfo);
        return E_NOTIMPL;
    }
    STDMETHOD(Invoke)( DISPID  dispIdMember,     
                       REFIID  riid,             
                       LCID  lcid,               
                       WORD  wFlags,             
                       DISPPARAMS FAR*  pDispParams, 
                       VARIANT FAR*  pVarResult, 
                       EXCEPINFO FAR*  pExcepInfo, 
                       unsigned int FAR*  puArgErr );

    // added by Mark manually -- End

};

#endif // !defined(AFX_SINK_H__F90A535B_4A71_433A_9A96_DE06BBEAB53C__INCLUDED_)

 

(7) Sink.cpp sample code

 

// Sink.cpp: implementation of the CSink class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "Sink.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CSink::CSink()
{
    // added by Mark
    m_dwRefCount =0;
}

CSink::~CSink()
{

}

// added by Mark for Invoke member -- Start
HRESULT CSink::Invoke(        DISPID  dispIdMember,     
                            REFIID  riid,             
                            LCID  lcid,               
                            WORD  wFlags,             
                            DISPPARAMS FAR*  pDispParams, 
                            VARIANT FAR*  pVarResult, 
                            EXCEPINFO FAR*  pExcepInfo, 
                            unsigned int FAR*  puArgErr )
{
    if (!pDispParams)
        return E_POINTER;
    if (!pVarResult)
        return E_POINTER;
    if (pDispParams->cNamedArgs != 0)
        return DISP_E_NONAMEDARGS;

    switch (dispIdMember)
    {
    case 0x01: // 0x01 from COM server's Invoke
        printf("0x01 is invoked from COM server\n");
        break;

//     case DISPID_CAPEVENT_ONPRECHANNELCHANGE:
//         pVarResult->scode = m_pSinkCallback->OnPreChannelChanged(pDispParams->rgvarg[3].lVal, pDispParams->rgvarg[2].lVal, pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].lVal);
//         break;
//     case DISPID_CAPEVENT_ONCHANNELCHANGE:
//         pVarResult->scode = m_pSinkCallback->OnChannelChanged(pDispParams->rgvarg[3].lVal, pDispParams->rgvarg[2].lVal, pDispParams->rgvarg[1].bstrVal, pDispParams->rgvarg[0].lVal);
        break;

    default:
        break;
    }
    return S_OK;
}

// added by Mark for Invoke member -- End

 

(8) main(..) function

#include "stdafx.h"

// -- Mark:: header files -- Start
#include "Sink.h"
#include <stdio.h>
#include <atlbase.h>
// -- Mark:: header files -- End

HRESULT test_COM_ConnectionPoint();

int main(int argc, char* argv[])
{
    test_COM_ConnectionPoint();
    return 0;
}

HRESULT test_COM_ConnectionPoint() {

    HRESULT hr;

    //call CoInitialize for COM initialisation
    hr =CoInitialize(NULL);
    if(hr != S_OK)
      return -1;

    // create an instance of the COM object
    CComPtr<IAdd> pAdd;
    hr =pAdd.CoCreateInstance(CLSID_Add);
    if(hr != S_OK)
      return -1;

    IConnectionPointContainer  * pCPC;
      IConnectionPoint       * pCP;

      DWORD                  dwAdvise;

      hr = pAdd->QueryInterface(IID_IConnectionPointContainer,
                               (void **)&pCPC);

      if ( !SUCCEEDED(hr) )
      {
        return hr;
      }

      //

      //OK, it does; now get the correct connection point interface

      //in our case IID_IAddEvents

     hr = pCPC->FindConnectionPoint(DIID__IAddEvents,&pCP);

    if ( !SUCCEEDED(hr) )
      {
        return hr;
      }

    //we are done with the connection point container interface

    pCPC->Release();

    IUnknown *pSinkUnk;

    // create a notification object from our CSink class

    //

    CSink *pSink = new CSink;

      if ( NULL == pSink )
      {
        return E_FAIL;
      }

      //Get the pointer to CSink's IUnknown pointer (note we have

      //implemented all this QueryInterface stuff earlier in our

      //CSinkclass

    hr = pSink->QueryInterface (IID_IUnknown,(void **)&pSinkUnk);

    //Pass it to the COM through the COM's _IAddEvents

    //interface (pCP) Advise method; Note that (pCP) was retrieved

    //through the earlier FindConnectoinPoint call

    //This is how the com gets our interface, so that it just needs

    //to call the interface method when it has to notify us

    _IAddEvents *pSinkAddEvents;

    hr = pSink->QueryInterface (DIID__IAddEvents,(void **)&pSinkAddEvents);
    if ( !SUCCEEDED(hr) )
      {
        return hr;
      }
    hr = pCP->Advise(pSinkAddEvents,&dwAdvise);

    //now call the COM's add method, passing in 2 numbers

     hr =  pAdd->Add(2 ,4);
    //do whatever u want here; once addition is here a message box

    //will pop up showing the result

    pCP->Unadvise(dwAdvise); // call this when you need to disconnect from server

    printf("press any key to continue...");
    getchar();

    pCP->Release();

    // Uninitialize COM
    //CoUninitialize();

      return hr;
}

 

(9) Results:

 

 

沒有留言: