/* ///////////////////////////////////////////////////////////////////////// * File: atlstl/automation/automation_collections.hpp * * Purpose: Adaptor classes for creating COM collection instances. * * Created: 16th April 1999 * Updated: 10th August 2009 * * Home: http://stlsoft.org/ * * Copyright (c) 1999-2009, Matthew Wilson and Synesis Software * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name(s) of Matthew Wilson and Synesis Software nor the names of * any contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * ////////////////////////////////////////////////////////////////////// */ /** \file atlstl/automation/automation_collections.hpp * \brief [C++ only; requires ATL library] Definition of the * atlstl::generic_automation_collection class template, with which * COM Collections may be readily defined * (\ref group__library__com_automation "COM Automation" Library). */ #ifndef ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS #define ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS #ifndef STLSOFT_DOCUMENTATION_SKIP_SECTION # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS_MAJOR 3 # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS_MINOR 2 # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS_REVISION 2 # define ATLSTL_VER_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS_EDIT 107 #endif /* !STLSOFT_DOCUMENTATION_SKIP_SECTION */ /* ///////////////////////////////////////////////////////////////////////// * Compatibility */ /* [Incompatibilies-start] STLSOFT_COMPILER_IS_DMC: [Incompatibilies-end] */ /* ///////////////////////////////////////////////////////////////////////// * Includes */ #ifndef ATLSTL_INCL_ATLSTL_HPP_ATLSTL # include #endif /* !ATLSTL_INCL_ATLSTL_HPP_ATLSTL */ #ifndef STLSOFT_INCL_SYS_H_ATLCOM # define STLSOFT_INCL_SYS_H_ATLCOM # include #endif /* !STLSOFT_INCL_SYS_H_ATLCOM */ /* ///////////////////////////////////////////////////////////////////////// * Namespace */ #ifndef _ATLSTL_NO_NAMESPACE # if defined(_STLSOFT_NO_NAMESPACE) || \ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) /* There is no stlsoft namespace, so must define ::atlstl */ namespace atlstl { # else /* Define stlsoft::atlstl_project */ namespace stlsoft { namespace atlstl_project { # endif /* _STLSOFT_NO_NAMESPACE */ #endif /* !_ATLSTL_NO_NAMESPACE */ /* ///////////////////////////////////////////////////////////////////////// * Classes */ // [[synesis:class:collection: atlstl::generic_collection_base, T, T, int>]] template< ss_typename_param_k D , ss_typename_param_k ThreadModel , ss_typename_param_k I , int DispidCount > class generic_collection_base : public I , public CComObjectRootEx { /// \name Member Types /// @{ public: typedef D derived_class_type; // typedef generic_collection_base class_type; typedef generic_collection_base class_type; /// @} /// \name Construction /// @{ protected: generic_collection_base() {} /// @} /// \name Interface map /// @{ protected: BEGIN_COM_MAP(generic_collection_base) COM_INTERFACE_ENTRY(IDispatch) // This is a constraint for I to be IDispatch, or a dual interface END_COM_MAP() /// @} /// \name IDispatch members /// @{ protected: STDMETHOD(GetTypeInfoCount)(UINT* pctinfo) { *pctinfo = 0; return S_OK; } STDMETHOD(GetTypeInfo)(UINT iTInfo, LCID /* lcid */, ITypeInfo** ppTInfo) { if(0 != iTInfo) { return DISP_E_BADINDEX; } else if(NULL == ppTInfo) { return E_POINTER; } else { *ppTInfo = NULL; return S_FALSE; } } STDMETHOD(GetIDsOfNames)( REFIID /* riid */ , LPOLESTR* rgszNames , UINT cNames , LCID /* lcid */ , DISPID* rgDispId) { if(1 == cNames) { if(0 == ::wcscmp(rgszNames[0], L"Count")) { derived_class_type* pThis = static_cast(this); HRESULT hr = pThis->SupportsCount(); if(S_OK == hr) { rgDispId[0] = DispidCount; return hr; } } } return DISP_E_UNKNOWNNAME; } STDMETHOD(Invoke)( DISPID dispidMember , REFIID /* riid */ , LCID /* lcid */ , WORD /* wFlags */ , DISPPARAMS* pDispParams , VARIANT* pVarResult , EXCEPINFO* /* pExcepInfo */ , UINT* /* puArgErr */) { if(DISPID_NEWENUM == dispidMember) { derived_class_type* pThis = static_cast(this); if(0 != pDispParams->cArgs) { return DISP_E_BADPARAMCOUNT; } else { LPUNKNOWN punkEnumerator; HRESULT hr; ::VariantInit(pVarResult); // hr = (pThis->*pfn)(&punkEnumerator); hr = pThis->get__NewEnum(&punkEnumerator); if(SUCCEEDED(hr)) { pVarResult->vt = VT_UNKNOWN; pVarResult->punkVal = punkEnumerator; } return hr; } } else if(DispidCount == dispidMember) { derived_class_type* pThis = static_cast(this); HRESULT hr; ::VariantInit(pVarResult); hr = pThis->get_Count(&pVarResult->lVal); if(SUCCEEDED(hr)) { pVarResult->vt = VT_I4; } return hr; } else { return DISP_E_MEMBERNOTFOUND; } } /// @} }; template< ss_typename_param_k I1 , ss_typename_param_k I2 , ss_typename_param_k I3 > inline LPUNKNOWN get_clone(I1* instance, HRESULT (STDAPICALLTYPE I3::*pfn)(I2**), HRESULT &hr) { I2* clone; hr = (instance->*pfn)(&clone); if(FAILED(hr)) { clone = NULL; } return clone; } /** Class for defining COM Automation collections */ // [[synesis:class:collection: atlstl::generic_automation_collection, T, T, int>]] template< ss_typename_param_k E , ss_typename_param_k ThreadModel = CComObjectThreadModel , ss_typename_param_k I = IDispatch , int DispidCount = 20001 > // Enumerator type class generic_automation_collection : public generic_collection_base, ThreadModel, I, DispidCount> { public: typedef E enumerator_type; typedef generic_automation_collection class_type; public: generic_automation_collection() : m_enumerator(NULL) , m_count(static_cast(~0)) {} void SetEnumerator(enumerator_type* enumerator, as_bool_t bAddRef) { ATLSTL_ASSERT(NULL != enumerator); ATLSTL_ASSERT(NULL == m_enumerator); m_enumerator = enumerator; if(bAddRef) { m_enumerator->AddRef(); } } void SetCount(as_size_t count) { m_count = count; } ~generic_automation_collection() { m_enumerator->Release(); } HRESULT SupportsCount() const { return (static_cast(~0) == m_count) ? S_FALSE : S_OK; } public: template< ss_typename_param_k ITER , ss_typename_param_k ITF , ss_typename_param_k N > HRESULT Init(ITER begin, ITER end, ITF* owner, N flags) { ATLSTL_ASSERT(NULL != m_enumerator); return m_enumerator->Init(begin, end, owner, flags); } template< ss_typename_param_k ITER , ss_typename_param_k ITF > HRESULT Init(ITER begin, ITER end, ITF* owner) { ATLSTL_ASSERT(NULL != m_enumerator); return m_enumerator->Init(begin, end, owner); } public: HRESULT get__NewEnum(LPUNKNOWN* punk) { ATLSTL_ASSERT(NULL != m_enumerator); HRESULT hr; *punk = get_clone(m_enumerator, &enumerator_type::Clone, hr); #if 0 typedef HRESULT (STDAPICALLTYPE enumerator_type::_CComEnumBase::*pfn_t)(LPUNKNOWN*); typedef HRESULT (STDAPICALLTYPE enumerator_type::_CComEnumBase::*pfnv_t)(void*); union { pfn_t pfn; pfnv_t pfnv; } u; u.pfnv = (pfnv_t)(&enumerator_type::Clone); return (m_enumerator->*u.pfn)(punk); #else /* ? 0 */ return hr; #endif /* 0 */ } HRESULT get_Count(long* pVal) { ATLSTL_ASSERT(NULL != pVal); if(static_cast(~0) == m_count) { return E_UNEXPECTED; } else { *pVal = static_cast(m_count); return S_OK; } } /// \name Member Variables /// @{ private: enumerator_type* m_enumerator; as_size_t m_count; /// @} private: generic_automation_collection(class_type const&); class_type& operator =(class_type const&); }; #if 0 template< ss_typename_param_k C //!< Collection interface , ss_typename_param_k E //!< Enumerator interface , ss_typename_param_k T //!< Element type , ss_typename_param_k XXXXXXXXX > class simple_automation_collection { }; #endif /* 0 */ //////////////////////////////////////////////////////////////////////////// // Unit-testing #ifdef STLSOFT_UNITTEST # include "./unittest/automation_collections_unittest_.h" #endif /* STLSOFT_UNITTEST */ /* ////////////////////////////////////////////////////////////////////// */ #ifndef _ATLSTL_NO_NAMESPACE # if defined(_STLSOFT_NO_NAMESPACE) || \ defined(STLSOFT_DOCUMENTATION_SKIP_SECTION) } // namespace atlstl # else } // namespace atlstl_project } // namespace stlsoft # endif /* _STLSOFT_NO_NAMESPACE */ #endif /* !_ATLSTL_NO_NAMESPACE */ /* ////////////////////////////////////////////////////////////////////// */ #endif /* !ATLSTL_INCL_ATLSTL_AUTOMATION_HPP_AUTOMATION_COLLECTIONS */ /* ///////////////////////////// end of file //////////////////////////// */