// mfcdual.h: Helpful macros for adding dual interface support to // MFC applications // This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. ///////////////////////////////////////////////////////////////////// // BEGIN_DUAL_INTERFACE_PART is just like BEGIN_INTERFACE_PART, // except that it also adds the IDispatch methods to your class // declaration. #define BEGIN_DUAL_INTERFACE_PART(localClass, baseClass) \ BEGIN_INTERFACE_PART(localClass, baseClass) \ STDMETHOD(GetTypeInfoCount)(UINT FAR* pctinfo); \ STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo); \ STDMETHOD(GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames, LCID lcid, DISPID FAR* rgdispid); \ STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr); \ ///////////////////////////////////////////////////////////////////// // END_DUAL_INTERFACE_PART is just like END_INTERFACE_PART. It // is only added for symmetry... #define END_DUAL_INTERFACE_PART(localClass) \ END_INTERFACE_PART(localClass) \ ///////////////////////////////////////////////////////////////////// // DELEGATE_DUAL_INTERFACE expands to define the standard IDispatch // methods for a dual interface, delegating back to the default // MFC implementation #define DELEGATE_DUAL_INTERFACE(objectClass, dualClass) \ STDMETHODIMP_(ULONG) objectClass::X##dualClass::AddRef() \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ return pThis->ExternalAddRef(); \ } \ STDMETHODIMP_(ULONG) objectClass::X##dualClass::Release() \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ return pThis->ExternalRelease(); \ } \ STDMETHODIMP objectClass::X##dualClass::QueryInterface( \ REFIID iid, LPVOID* ppvObj) \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ return pThis->ExternalQueryInterface(&iid, ppvObj); \ } \ STDMETHODIMP objectClass::X##dualClass::GetTypeInfoCount( \ UINT FAR* pctinfo) \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE); \ ASSERT(lpDispatch != NULL); \ return lpDispatch->GetTypeInfoCount(pctinfo); \ } \ STDMETHODIMP objectClass::X##dualClass::GetTypeInfo( \ UINT itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo) \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE); \ ASSERT(lpDispatch != NULL); \ return lpDispatch->GetTypeInfo(itinfo, lcid, pptinfo); \ } \ STDMETHODIMP objectClass::X##dualClass::GetIDsOfNames( \ REFIID riid, OLECHAR FAR* FAR* rgszNames, UINT cNames, \ LCID lcid, DISPID FAR* rgdispid) \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE); \ ASSERT(lpDispatch != NULL); \ return lpDispatch->GetIDsOfNames(riid, rgszNames, cNames, \ lcid, rgdispid); \ } \ STDMETHODIMP objectClass::X##dualClass::Invoke( \ DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, \ DISPPARAMS FAR* pdispparams, VARIANT FAR* pvarResult, \ EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) \ { \ METHOD_PROLOGUE(objectClass, dualClass) \ LPDISPATCH lpDispatch = pThis->GetIDispatch(FALSE); \ ASSERT(lpDispatch != NULL); \ return lpDispatch->Invoke(dispidMember, riid, lcid, \ wFlags, pdispparams, pvarResult, \ pexcepinfo, puArgErr); \ } \ ///////////////////////////////////////////////////////////////////// // TRY_DUAL and CATCH_ALL_DUAL are used to provide exception handling // for your dual interface methods. CATCH_ALL_DUAL takes care of // returning the appropriate error code. #define TRY_DUAL(iidSource) \ HRESULT _hr = S_OK; \ REFIID _riidSource = iidSource; \ TRY \ #define CATCH_ALL_DUAL \ CATCH(COleException, e) \ { \ _hr = e->m_sc; \ } \ AND_CATCH_ALL(e) \ { \ AFX_MANAGE_STATE(pThis->m_pModuleState); \ _hr = DualHandleException(_riidSource, e); \ } \ END_CATCH_ALL \ return _hr; \ ///////////////////////////////////////////////////////////////////// // DualHandleException is a helper function used to set the system's // error object, so that container applications that call through // VTBLs can retrieve rich error information HRESULT DualHandleException(REFIID riidSource, const CException* pAnyException); ///////////////////////////////////////////////////////////////////// // DECLARE_DUAL_ERRORINFO expands to declare the ISupportErrorInfo // support class. It works together with DUAL_ERRORINFO_PART and // IMPLEMENT_DUAL_ERRORINFO defined below. #define DECLARE_DUAL_ERRORINFO() \ BEGIN_INTERFACE_PART(SupportErrorInfo, ISupportErrorInfo) \ STDMETHOD(InterfaceSupportsErrorInfo)(THIS_ REFIID riid); \ END_INTERFACE_PART(SupportErrorInfo) \ ///////////////////////////////////////////////////////////////////// // DUAL_ERRORINFO_PART adds the appropriate entry to the interface map // for ISupportErrorInfo, if you used DECLARE_DUAL_ERRORINFO. #define DUAL_ERRORINFO_PART(objectClass) \ INTERFACE_PART(objectClass, IID_ISupportErrorInfo, SupportErrorInfo) \ ///////////////////////////////////////////////////////////////////// // IMPLEMENT_DUAL_ERRORINFO expands to an implementation of // ISupportErrorInfo which matches the declaration in // DECLARE_DUAL_ERRORINFO. #define IMPLEMENT_DUAL_ERRORINFO(objectClass, riidSource) \ STDMETHODIMP_(ULONG) objectClass::XSupportErrorInfo::AddRef() \ { \ METHOD_PROLOGUE(objectClass, SupportErrorInfo) \ return pThis->ExternalAddRef(); \ } \ STDMETHODIMP_(ULONG) objectClass::XSupportErrorInfo::Release() \ { \ METHOD_PROLOGUE(objectClass, SupportErrorInfo) \ return pThis->ExternalRelease(); \ } \ STDMETHODIMP objectClass::XSupportErrorInfo::QueryInterface( \ REFIID iid, LPVOID* ppvObj) \ { \ METHOD_PROLOGUE(objectClass, SupportErrorInfo) \ return pThis->ExternalQueryInterface(&iid, ppvObj); \ } \ STDMETHODIMP objectClass::XSupportErrorInfo::InterfaceSupportsErrorInfo( \ REFIID iid) \ { \ METHOD_PROLOGUE(objectClass, SupportErrorInfo) \ return (iid == riidSource) ? S_OK : S_FALSE; \ } /////////////////////////////////////////////////////////////////////