#pragma once

#include <Unknwn.h>

namespace SOUI
{
    #define COM_INTERFACE_BEGIN() \
    public:\
    virtual HRESULT STDMETHODCALLTYPE QueryInterface2( \
        /* [in] */ REFIID riid,\
        /* [iid_is][out] */  void __RPC_FAR *__RPC_FAR *ppvObject)\
        {\
            HRESULT hr = E_NOINTERFACE; \
            
    #define COM_INTERFACE(IFACE)    \
            if(hr != S_OK && riid == __uuidof(IFACE)) \
            {\
                *ppvObject = static_cast<IFACE*>(this); \
                hr = S_OK;\
            }\
                
    #define COM_INTERFACE_END()  \
            return hr; \
         }
    
     
    template<class T>
    class SUnknownImpl: public T
    {
    public:
        SUnknownImpl():m_cRef(1){}

        template<typename P1>
        SUnknownImpl(P1 p1):T(p1),m_cRef(1)
        {
        }

        template<typename P1,typename P2>
        SUnknownImpl(P1 p1,P2 p2):T(p1,p2),m_cRef(1)
        {
        }

        virtual ~SUnknownImpl(){}
        
        virtual HRESULT STDMETHODCALLTYPE QueryInterface2( 
            /* [in] */ REFIID riid,
            /* [iid_is][out] */  void __RPC_FAR *__RPC_FAR *ppvObject)
        {
			(riid);
			(ppvObject);
            return E_NOINTERFACE;
        }

        HRESULT STDMETHODCALLTYPE QueryInterface( 
            /* [in] */ REFIID riid,
            /* [iid_is][out] */  void __RPC_FAR *__RPC_FAR *ppvObject)
        {
            HRESULT hr = E_NOINTERFACE;
            if(riid == __uuidof(IUnknown))
            {
                *ppvObject = this;
                hr =  S_OK;
            }else
            {
                hr = QueryInterface2(riid,ppvObject);
            }
            if(hr == S_OK)
            {
                static_cast<IUnknown*>(*ppvObject)->AddRef();
            }
            return hr;
        }

        virtual ULONG STDMETHODCALLTYPE AddRef( void)
        {
            return (ULONG)::InterlockedIncrement(&m_cRef);
        }

        virtual ULONG STDMETHODCALLTYPE Release( void)
        {
            LONG uRet = ::InterlockedDecrement(&m_cRef);
            if(uRet == 0)
            {
                OnFinialRelease();
            }
            return uRet;
        }

    public:
    
        virtual void OnFinialRelease(){delete this;}

    protected:
        volatile LONG m_cRef;
    };
}
