atl atladvise解析

本文详细介绍了COM组件模型中接口注册的过程。重点讲述了[source]属性如何让组件声明支持哪些对外接口,以及客户端如何实现这些接口并与组件进行注册和链接,从而实现组件间的通信。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      
 

IDL中提供的[source]属性,是为了让实现类宣扬它支持哪几个对外接口注册。

分类: 组件   484人阅读  评论(1)  收藏  举报

IDL中提供的[source]属性,是为了让实现类宣扬它支持哪几个对外接口注册。

主要表达的意思的是--组件内部在某种条件下将调用该接口,向外界传递信息。如果你对此信息感兴趣,就要自己实现这个接口,并向该组件注册并连接。这样当组件调用该接口时,会向你及时传递你感兴趣的信息。

例如: 

coclass Math
 {
         [default] interface IMath;
         [source, default]  dispinterface _IMathEvents;       <==== 对外宣扬 Math组件支持_IMathEvents对外接口的注册。
 }; 

com包括引入接口和引出接口,来描述组件可以支持的两种不同类型的接口。
. 一个引入接口是指由组件实现的接口,这里的IMath接口就是一个引入接口。因为它是有组件来实现的。

.一个引出接口是指在组件的类型库中描述的接口,这里的_IMathEvents接口就是一个引入接口。它实际上是由Math组件的客户机来实现的。

 下面展示_IMathEvents接口是如何实现,并与组件Math组件注册并链接的。

========================_IMathEvents接口的实现==========================
class CMathEvents :
   public CComObjectRoot,
   public _IMathEvents
{
public:
   CMathEvents()
   {
   }
BEGIN_COM_MAP(CMathEvents)
 COM_INTERFACE_ENTRY(IDispatch)
 COM_INTERFACE_ENTRY(_IMathEvents)
END_COM_MAP()
// IMathEvents
public:
   STDMETHODIMP GetTypeInfoCount(UINT*)
   {
      return E_NOTIMPL;
   }
   STDMETHODIMP GetTypeInfo( UINT iTInfo,
                          LCID lcid,
                             ITypeInfo **ppTInfo)
   { 
      return E_NOTIMPL;
   }
   STDMETHODIMP GetIDsOfNames( REFIID riid,
                               LPOLESTR *rgszNames,
                               UINT cNames,
                               LCID lcid,
                               DISPID *rgDispId)
   { 
      return E_NOTIMPL;
   }
   STDMETHODIMP Invoke( DISPID dispIdMember,
                        REFIID riid,
                        LCID lcid,
                        WORD wFlags,
                        DISPPARAMS *pDispParams,
                        VARIANT *pVarResult,
                        EXCEPINFO *pExcepInfo,
                        UINT *puArgErr)
   {
      switch( dispIdMember )
      {
         case 0x1:
            // Make sure the is just one argument
            if ( pDispParams->cArgs != 1 )
               return DISP_E_BADPARAMCOUNT;
            // We don't support named arguments
            if ( pDispParams->cNamedArgs )
               return DISP_E_NONAMEDARGS;
            // Coerce the argument into a long
            HRESULT hr;
            VARIANTARG var;
            VariantInit( &var );
            hr = VariantChangeTypeEx( &var,
                                      &(pDispParams->rgvarg[0]),
                                      lcid, 0, VT_I4 );
            if FAILED( hr )
               return DISP_E_BADVARTYPE;
            ComputationComplete( var.lVal );
            break;
         default:
            DisplayMessage( "Error" );
            break;
      }
      return S_OK;
   }
       
   STDMETHODIMP ComputationComplete(long lResult)
   {
      char szMsg[128];
      sprintf( szMsg, "The result is %d", lResult );
      DisplayMessage( szMsg );
      return S_OK;
   }
};

  =========================与Math组件注册并链接============================
  CComPtr < IMath >  ptrMath;
   HRESULT hr;
   hr 
=  CoCreateInstance( CLSID_Math,               <==== 创建宣扬支持_IMathEvents对外接口的组件
                          NULL,
                          CLSCTX_SERVER,
                          IID_IMath,
                          (
void ** & ptrMath );

   
if  ( FAILED( hr ))
   {
      HandleError( 
" Failed to create server instance " , hr );
      
return   - 1 ;
   }

   CComObject
< CMathEvents >*  ptrMathEvents;       
   CComObject < CMathEvents > ::CreateInstance(  & ptrMathEvents );   <======= 创建实现_IMathEvents的组件实例

   CComPtr
< IUnknown >  ptrEventsUnk  =  ptrMathEvents;
   //
   IMathEvents *pMathEvents;
   hr = ptrMathEvents->QueryInterface(IID_IMathEvents, (void **)&pMathEvents);    <=======获得_IMathEvents接口指针

  
//  Set up the connection 
  DWORD dwCookie;
  hr 
=  AtlAdvise( ptrMath,
      pMathEvents,              
      DIID__IMathEvents,
      
& dwCookie );               <======_IMathEvents接口指针pMathEvents在ptrMath组件实例中注册并链接
  
if  (FAILED( hr ))
  {
     HandleError( 
" Unable to setup the connection for IMathEvents " , hr );
     
return   - 1 ;
  }

  
//  Access the IMath interface
    long  lResult;
   ptrMath
-> Add(  300 10 & lResult );     <========调用ptrMath组件方法。组件方法执行过程中会适时通过传入的_IMathEvents接口指针pMathEvents向调用者返回信息--回调。
   ptrMath
-> Subtract(  300 10 & lResult );
   ptrMath
-> Multiply(  300 10 & lResult );
   ptrMath
-> Divide(  300 10 & lResult );

   
//  Shut down the event connection
   AtlUnadvise( ptrMath,
                       DIID__IMathEvents,
                       dwCookie );                <======中断_IMathEvents接口指针与ptrMath组件实例的链接

  .....


 其中AtlAdvise和AtlUnadvise的实现过程是这样的:

CComPtr < IUnknown >
  spSource 
=   /* Set to the source of the events */  ;
CComPtr
< _ISpeakerEvents >
  spSink 
=   /* Sink to receive the events */  ;
DWORD dwCookie ;

CComPtr
< IConnectionPointContainer >  spcpc;
HRESULT hr 
=  spSource.QueryInterface ( & spcpc);

CComPtr
< IConnectionPoint >  spcp ;
hr 
=  spcpc -> FindConnectionPoint(__uuidof(_ISpeakerEvents), 
  
& spcp);       <======根据_ISpeakerEvents来查找ConnectionPoint。只有组件宣扬的对外接口,才可以查找成功。
hr 
=  spcp -> Advise (spSink,  & dwCookie) ;     //  Establish connection
//  Time goes by, callbacks occur...
hr  =  spcp -> Unadvise (dwCookie) ;        // Break connection


hr = AtlAdvise( ptrMath,      // 对外宣扬 支持_IMathEvents接口
      pMathEvents,           //  _IMathEvents类型接口指针
      DIID__IMathEvents,    
      
&dwCookie );  

结论:对于AtlAdvise,只有组件宣扬的对外接口,才可以注册成功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值