//***************************************************************************
//
//  Copyright (c) 1998-1999 Microsoft Corporation
//
//  sink.h
//
//  rogerbo  21-May-98   Created.
//
//  Include file for CSWbemSink
//
//***************************************************************************

#ifndef _SINK_H_
#define _SINK_H_

const NUM_CONNECTION_POINTS = 1;
const CCONNMAX = 8;


//***************************************************************************
//
//  CLASS NAME:
//
//  CSWbemSink
//
//  DESCRIPTION:
//
//  Implements the ISWbemSink interface.  
//
//***************************************************************************

typedef struct _WbemObjectListEntry {
	IUnknown *pWbemObjectWrapper;
	IWbemServices *pServices;
} WbemObjectListEntry;


class CConnectionPoint;
class CWbemObjectSink;

class CSWbemSink : public ISWbemSink, 
				   public IConnectionPointContainer, 
				   public IProvideClassInfo2,
				   public IObjectSafety,
				   public ISupportErrorInfo,
				   public ISWbemPrivateSinkLocator
{
private:

	CDispatchHelp		m_Dispatch;		
	CConnectionPoint* m_rgpConnPt[NUM_CONNECTION_POINTS];
	WbemObjectListEntry *m_rgpCWbemObjectSink;   // One of these per outstanding operation
	int m_nMaxSinks;
	int m_nSinks;

	/* 
	 * Here we need to do per interface reference counting.  If the ref count
	 * of the enclosing object goes to zero, and the ref count of the enclosed
	 * object (this one), is non zero, then we have to instigate a cancel, because
	 * there are still outstanding operations.
	 */
	class CSWbemPrivateSink : public ISWbemPrivateSink {
		private:

		CSWbemSink *m_pSink;
		long m_cRef;

		public:

		CSWbemPrivateSink(CSWbemSink *pSink) : m_pSink(pSink), m_cRef(0) {}
		void Detach() { m_pSink = NULL; }

		long GetRef() { return m_cRef; }

		// IUnknown methods

		STDMETHODIMP         QueryInterface(REFIID riid, LPVOID *ppv) {
										if (IID_ISWbemPrivateSink==riid || IID_IUnknown==riid)
										{
											*ppv = (ISWbemPrivateSink *)(this);
											InterlockedIncrement(&m_cRef);
											return S_OK;
										}
										else if (IID_ISWbemPrivateSink==riid)
										{
											*ppv = (ISWbemPrivateSink *)(this);
											InterlockedIncrement(&m_cRef);
											return S_OK;
										}
										return ResultFromScode(E_NOINTERFACE);
									}

		STDMETHODIMP_(ULONG) AddRef(void) {
										InterlockedIncrement(&m_cRef);
										return m_cRef;
									}

		STDMETHODIMP_(ULONG) Release(void) {
										InterlockedDecrement(&m_cRef);
										if(0 == m_cRef)
										{
											delete this;
											return 0;
										}
									  	return m_cRef; 
									}

		// ISWbemPrivateSink methods

		HRESULT STDMETHODCALLTYPE OnObjectReady( 
				/* [in] */ IDispatch __RPC_FAR *objObject,
				/* [in] */ IDispatch __RPC_FAR *objAsyncContext) 
						{ return m_pSink?m_pSink->OnObjectReady(objObject, objAsyncContext):S_OK; }
			
		HRESULT STDMETHODCALLTYPE OnCompleted( 
				/* [in] */ HRESULT iHResult,
				/* [in] */ IDispatch __RPC_FAR *objPath,
				/* [in] */ IDispatch __RPC_FAR *objErrorObject,
				/* [in] */ IDispatch __RPC_FAR *objAsyncContext)
						{ return m_pSink?m_pSink->OnCompleted(iHResult, objPath, objErrorObject, objAsyncContext):S_OK; }
			
		HRESULT STDMETHODCALLTYPE OnProgress( 
				/* [in] */ long iUpperBound,
				/* [in] */ long iCurrent,
				/* [in] */ BSTR strMessage,
				/* [in] */ IDispatch __RPC_FAR *objAsyncContext)
					{ return m_pSink?m_pSink->OnProgress(iUpperBound, iCurrent, strMessage, objAsyncContext):S_OK; }

		HRESULT STDMETHODCALLTYPE AddObjectSink( 
				/* [in] */ IUnknown __RPC_FAR *objWbemSink,
				/* [in] */ IWbemServices __RPC_FAR *objServices)
					{ return m_pSink?m_pSink->AddObjectSink(objWbemSink, objServices):S_OK; }
			
		HRESULT STDMETHODCALLTYPE RemoveObjectSink( 
				/* [in] */ IUnknown __RPC_FAR *objWbemSink)
					{ return m_pSink?m_pSink->RemoveObjectSink(objWbemSink):S_OK; }

	} *m_pPrivateSink;

protected:

	long            m_cRef;         //Object reference count

public:
    
    CSWbemSink();
    ~CSWbemSink(void);

    //Non-delegating object IUnknown

    STDMETHODIMP         QueryInterface(REFIID, LPVOID*);
    STDMETHODIMP_(ULONG) AddRef(void);
    STDMETHODIMP_(ULONG) Release(void);

	// IDispatch methods

	STDMETHODIMP		GetTypeInfoCount(UINT* pctinfo)
		{return  m_Dispatch.GetTypeInfoCount(pctinfo);}
    STDMETHODIMP		GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** pptinfo)
		{return m_Dispatch.GetTypeInfo(itinfo, lcid, pptinfo);}
    STDMETHODIMP		GetIDsOfNames(REFIID riid, OLECHAR** rgszNames, 
							UINT cNames, LCID lcid, DISPID* rgdispid)
		{return m_Dispatch.GetIDsOfNames(riid, rgszNames, cNames,
                          lcid,
                          rgdispid);}
    STDMETHODIMP		Invoke(DISPID dispidMember, REFIID riid, LCID lcid, 
							WORD wFlags, DISPPARAMS* pdispparams, VARIANT* pvarResult, 
									EXCEPINFO* pexcepinfo, UINT* puArgErr)
		{return m_Dispatch.Invoke(dispidMember, riid, lcid, wFlags,
                        pdispparams, pvarResult, pexcepinfo, puArgErr);}


	// ISWbemSink methods
	HRESULT STDMETHODCALLTYPE Cancel();

	// IConnectionPointContainer methods
	HRESULT __stdcall EnumConnectionPoints(IEnumConnectionPoints** ppEnum);
	HRESULT __stdcall FindConnectionPoint(REFIID riid, IConnectionPoint** ppCP);

	// IProvideClassInfo2 methods
	HRESULT __stdcall GetClassInfo(ITypeInfo** pTypeInfo);
	HRESULT __stdcall GetGUID(DWORD dwGuidKind, GUID* pGUID);

	// ISWbemPrivateSink methods
	HRESULT STDMETHODCALLTYPE OnObjectReady( 
            /* [in] */ IDispatch __RPC_FAR *objObject,
            /* [in] */ IDispatch __RPC_FAR *objAsyncContext);
        
	HRESULT STDMETHODCALLTYPE OnCompleted( 
            /* [in] */ HRESULT iHResult,
            /* [in] */ IDispatch __RPC_FAR *objPath,
            /* [in] */ IDispatch __RPC_FAR *objErrorObject,
            /* [in] */ IDispatch __RPC_FAR *objAsyncContext);
        
	HRESULT STDMETHODCALLTYPE OnProgress( 
            /* [in] */ long iUpperBound,
            /* [in] */ long iCurrent,
            /* [in] */ BSTR strMessage,
            /* [in] */ IDispatch __RPC_FAR *objAsyncContext);

	HRESULT STDMETHODCALLTYPE AddObjectSink( 
            /* [in] */ IUnknown __RPC_FAR *objWbemSink,
            /* [in] */ IWbemServices __RPC_FAR *objServices);
        
	HRESULT STDMETHODCALLTYPE RemoveObjectSink( 
            /* [in] */ IUnknown __RPC_FAR *objWbemSink);

	// ISWbemPrivateSinkLocator methods
	HRESULT STDMETHODCALLTYPE GetPrivateSink(
			/* [out] */ IUnknown **objWbemPrivateSink);

	// IObjectSafety methods
	HRESULT STDMETHODCALLTYPE SetInterfaceSafetyOptions
	(     
		/* [in] */ REFIID riid,
		/* [in] */ DWORD dwOptionSetMask,    
		/* [in] */ DWORD dwEnabledOptions
	)
	{ 
		return (dwOptionSetMask & dwEnabledOptions) ? E_FAIL : S_OK;
	}

	HRESULT  STDMETHODCALLTYPE GetInterfaceSafetyOptions( 
		/* [in]  */ REFIID riid,
		/* [out] */ DWORD __RPC_FAR *pdwSupportedOptions,
		/* [out] */ DWORD __RPC_FAR *pdwEnabledOptions
	)
	{ 
		if (pdwSupportedOptions) *pdwSupportedOptions = 0;
		if (pdwEnabledOptions) *pdwEnabledOptions = 0;
		return S_OK;
	}

	// ISupportErrorInfo methods
	HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo 
	(
		/* [in] */ REFIID riid
	);
};

class CEnumConnectionPoints : public IEnumConnectionPoints
{
public:
	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IEnumConnectionPoints
	HRESULT __stdcall Next(ULONG cConnections, IConnectionPoint** rgpcn, ULONG* pcFetched); 
	HRESULT __stdcall Skip(ULONG cConnections);
	HRESULT __stdcall Reset();
	HRESULT __stdcall Clone(IEnumConnectionPoints** ppEnum);

	CEnumConnectionPoints(IUnknown* pUnkRef, void** rgpCP);
	~CEnumConnectionPoints();

private:
	long m_cRef;
    IUnknown* m_pUnkRef;         // IUnknown for ref counting
    int m_iCur;                  // Current element
    IConnectionPoint* m_rgpCP[NUM_CONNECTION_POINTS];  // Array of connection points
};


class CConnectionPoint : public IConnectionPoint
{
private:

	int m_cRef;
	CSWbemSink* m_pObj;
	IID m_iid;
    int m_cConn;
    int m_nCookieNext;
	int m_nMaxConnections;
	unsigned *m_rgnCookies;
	IUnknown **m_rgpUnknown;

public:

	CConnectionPoint(CSWbemSink* pObj, REFIID refiid);
	~CConnectionPoint();

	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IConnectionPoint
	HRESULT __stdcall GetConnectionInterface(IID *pIID);
	HRESULT __stdcall GetConnectionPointContainer(IConnectionPointContainer** ppCPC);
	HRESULT __stdcall Advise(IUnknown* pUnknownSink, DWORD* pdwCookie);
	HRESULT __stdcall Unadvise(DWORD dwCookie);
	HRESULT __stdcall EnumConnections(IEnumConnections** ppEnum);

	// Other methods
	void OnObjectReady( 
		/* [in] */ IDispatch __RPC_FAR *pObject,
		/* [in] */ IDispatch __RPC_FAR *pAsyncContext);
	void OnCompleted( 
		/* [in] */ HRESULT hResult,
		/* [in] */ IDispatch __RPC_FAR *path,
		/* [in] */ IDispatch __RPC_FAR *pErrorObject,
		/* [in] */ IDispatch __RPC_FAR *pAsyncContext);
	void CConnectionPoint::OnProgress( 
		/* [in] */ long upperBound,
		/* [in] */ long current,
		/* [in] */ BSTR message,
		/* [in] */ IDispatch __RPC_FAR *pAsyncContext);

	void UnadviseAll();

};

class CEnumConnections : public IEnumConnections
{
public:
	// IUnknown
	ULONG __stdcall AddRef();
	ULONG __stdcall Release();
	HRESULT __stdcall QueryInterface(REFIID iid, void** ppv);

	// IEnumConnections
	HRESULT __stdcall Next(ULONG cConnections, CONNECTDATA* rgpcd, ULONG* pcFetched);
	HRESULT __stdcall Skip(ULONG cConnections);
	HRESULT __stdcall Reset();
	HRESULT __stdcall Clone(IEnumConnections** ppEnum);

	CEnumConnections(IUnknown* pUnknown, int cConn, CONNECTDATA* pConnData);
	~CEnumConnections();

private:
	int m_cRef;
    IUnknown* m_pUnkRef;       // IUnknown for ref counting
    unsigned m_iCur;           // Current element
    unsigned m_cConn;          // Number of connections
    CONNECTDATA* m_rgConnData; // Source of connections
};


#endif