// dispimpl2.h: IDispatchImpl2
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1998 Chris Sells
// Wszystkie prawa zastrzeżona.
//
// 10/25/98:
// -Pierwsza wersja.
//
// UŻYCIE NA WŁASNE RYZYKO.
//
// Z autorem można skontaktować się pod adresem csells@sellsbrothers.com.
/////////////////////////////////////////////////////////////////////////////
// Ten nagłówek definiuje trzy klasy C++ używane do implementacji
// interfejsów:
//  -IDualDispImpl do implementacji podwójnych interfejsów.
//  -IDelegatingDispImpl do implementacji delegujących interfejsów.
//  -IRawDispImpl do implementacji pierwotnych interfejsów.
/////////////////////////////////////////////////////////////////////////////
// IDualDispImpl: Wykorzystywany wraz z interfejsami zadeklarowanymi w poniższy sposób:
//
// [dual]
// interface IFoo : IDispatch
// {
//    ...
// }
//
// IDualDispImpl implementuje wszystkie cztery metody IDispatch.
// IDualDispImpl uzyskuje wpisy vtbl IDispatch poprzez dziedziczenie
// z IDispatch, który służy jako klasa bazowa dla podwójnych interfejsów.
//
// Użycie:
//  class CFoo : ..., public IDualDispImpl<IFoo>
//
// Aktualny IDispatchImpl może być wykorzystany tylko dla podwójnych interfejsów.
// UWAGA: Można tu użyć typedef, ale wolę uzyskać piid poprzez __uuidof.
/////////////////////////////////////////////////////////////////////////////
// IDelegatingDispImpl: Wykorzystywany wraz z interfejsami zadeklarowanymi w poniższy sposób:
//
// [oleautomation]
// interface IFoo : IUnknown
// {
//    ...
// }
//
// dispinterface DFoo
// {
//    interface IFoo; // Logiczna delegacja do innego interfejsu
// }
//
// IDelegatingDispImpl implementuje wszystkie cztery metody IDispatch.
// IDelegatingDispImpl uzyskuje wpisy vtbl IDispatch poprzez dziedziczenie
// z IDispatch w uzupełnieniu interfejsu nie opartego na IDispatch.
//
// Użycie:
//  class CFoo : ..., public IDelegatingDispImpl<DFoo, IFoo>
/////////////////////////////////////////////////////////////////////////////
// IRawDispImpl: Wykorzystywany wraz z interfejsami zadeklarowanymi w poniższy sposób:
//
// dispinterface DFoo
// {
// properties:
//   ...
// methods:
//   ...
// }
//
// IRawDispImpl implementuje trzy metody IDispatch.
// Wywołanie jest zależne od użytkownika.
// IRawDispImpl uzyskuje wpisy vtbl IDispatch poprzez dziedziczenie
// z IDispatch w uzupełnieniu interfejsu nie opartego na IDispatch.
//
// Użycie:
//  class CFoo : ..., public IRawDispImpl<DFoo>
//  {
//  ...
//      STDMETHODIMP Invoke(...);   // Implementowane ręcznie.
//  };
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
// IDualDispImpl

template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CComModule::m_libid, WORD wMajor = 1,
          WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
class ATL_NO_VTABLE IDualDispImpl : public IDispatchImpl<T, piid, plibid, wMajor, wMinor, tihclass> {};

/////////////////////////////////////////////////////////////////////////////
// IDelegatingDispImpl

template <class D, class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CComModule::m_libid, WORD wMajor = 1,
          WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
class ATL_NO_VTABLE IDelegatingDispImpl : public T, public D
{
public:
	typedef tihclass _tihclass;
// IDispatch
	STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
	{
		*pctinfo = 1;
		return S_OK;
	}
	STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
	{
		return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
	}
	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
		LCID lcid, DISPID* rgdispid)
	{
		return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
	}
	STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid,
		LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult,
		EXCEPINFO* pexcepinfo, UINT* puArgErr)
	{
        
		return _tih.Invoke(reinterpret_cast<IDispatch*>(static_cast<T*>(this)),
                           dispidMember, riid, lcid, wFlags, pdispparams,
                           pvarResult, pexcepinfo, puArgErr);
	}
protected:
	static _tihclass _tih;
	static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
	{
		return _tih.GetTI(lcid, ppInfo);
	}
};

template <class D, class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
IDelegatingDispImpl<D, T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
    IDelegatingDispImpl<D, T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
        {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};

/////////////////////////////////////////////////////////////////////////////
// IRawDispImpl

template <class T, const IID* piid = &__uuidof(T), const GUID* plibid = &CComModule::m_libid, WORD wMajor = 1,
          WORD wMinor = 0, class tihclass = CComTypeInfoHolder>
class ATL_NO_VTABLE IRawDispImpl : public T
{
public:
	typedef tihclass _tihclass;
// IDispatch
	STDMETHOD(GetTypeInfoCount)(UINT* pctinfo)
	{
		*pctinfo = 1;
		return S_OK;
	}
	STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
	{
		return _tih.GetTypeInfo(itinfo, lcid, pptinfo);
	}
	STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* rgszNames, UINT cNames,
		LCID lcid, DISPID* rgdispid)
	{
		return _tih.GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
	}

    // Wywołanie powinno być zaimplementowane samodzielnie.
	STDMETHOD(Invoke)(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, EXCEPINFO* pexcepinfo, UINT* puArgErr) = 0;

protected:
	static _tihclass _tih;
	static HRESULT GetTI(LCID lcid, ITypeInfo** ppInfo)
	{
		return _tih.GetTI(lcid, ppInfo);
	}
};

template <class T, const IID* piid, const GUID* plibid, WORD wMajor, WORD wMinor, class tihclass>
IRawDispImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tihclass
    IRawDispImpl<T, piid, plibid, wMajor, wMinor, tihclass>::_tih =
        {piid, plibid, wMajor, wMinor, NULL, 0, NULL, 0};
