#ifndef _xbPTR_
#define _xbPTR_
/*<<<***************************************************************************
The MIT License (MIT)

Copyright(C) 2013 - 2015 Marc Mirti Mancinelli, Christophe Lardau and Philippe Pamart (xdcube.org)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
////////////////////////////////////////////////////////////////////////////////
#Title: xbPtr
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<15/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#ifndef _xbENGINE_
#	include "xbEngine.h"
#endif

#ifndef _xbEXCEPTION_
#	include "xbException.h"
#endif

template<class interf> inline void xbCastInReq(sIxbBase *piBase, interf **ppInterf)
{
	if (!piBase)
		xbThrow xbElib("pointer is NULL, can't perform call !","xbCastInReq(), type "+xbString(__uuidof(interf),true));
	if (!piBase->GetInterface(__uuidof(interf),(void**)ppInterf))
		xbThrow xbElib("pointer is not of asked type, can't perform call !","xbCastInReq(), type "+xbString(__uuidof(interf),true));
}

template<class interf> inline void xbCastInReq(const sIxbBase *piBase, const interf **ppInterf)
{
	if (!piBase)
		xbThrow xbElib("pointer is NULL, can't perform call !","xbCastInReq(), type "+xbString(__uuidof(interf),true));
	if (!piBase->GetInterface(__uuidof(interf),(const void**)ppInterf))
		xbThrow xbElib("pointer is not of asked type, can't perform call !","xbCastInReq(), type "+xbString(__uuidof(interf),true));
}

#define xbPTRSIG_WRITEDOK		5
#define xbPTRSIG_WRITEDERROR	-2

#define xbPTRSIG_ITEMDRAW		4
#define xbPTRSIG_ITEMUPDATE		3

#define xbPTRSIG_CHILDDRAW		2
#define xbPTRSIG_CHILDUPDATE	1

#define xbPTRSIG_LOADEDOK		0
#define xbPTRSIG_LOADEDERROR	-1


//First IUnknown, next sIxbBase in inheritage order : cf QueryInterface (cast IUnknown)
interface sIxbPtr;
interface IxbObjectPtrNotif;
interface IxbObject;

interface xbEXPORT __declspec(uuid("{708AFA3B-E43B-42a3-B11F-48C1B40B4CF4}")) 
	sIxbPtrNotif:public sIxbBase
{
	virtual void				AddObjectToNotif(IxbObjectPtrNotif *pObj) = 0;
	virtual IxbObject			*GetObjectLinked() = 0;
	virtual bool				IsObjectLinked(IxbObject *pObj) = 0;
	virtual bool				HasObjectToNotif() const = 0;
	virtual bool				IsSectPtrLocked() const = 0;
	virtual bool				HasObjectToNotif(IxbObjectPtrNotif *pObj) = 0;
};

interface xbEXPORT __declspec(uuid("{A1D4A5A5-CCC7-4812-910A-B1BB7BEC80F8}")) 
	sIxbPtrCb:public sIxbBase
{
	virtual void				onSignal(sIxbPtrNotif*,sIxbPtr*,int arg) = 0;
	virtual void				onUnlink(sIxbPtrNotif*,sIxbPtr*) = 0;
	virtual void				onLink(sIxbPtrNotif*,sIxbPtr*) = 0;
};

interface xbEXPORT __declspec(uuid("{A1D4A5A5-CCC7-4812-910A-B1BB7BEC80F8}")) 
	IxbObject:public IUnknown,public sIxbBase
{
	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppInterf) = 0;
	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, const void ** ppInterf) const = 0;
	virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
	virtual ULONG STDMETHODCALLTYPE Release() = 0;
	virtual ULONG STDMETHODCALLTYPE AddRef() const = 0;
	virtual ULONG STDMETHODCALLTYPE Release() const = 0;

	virtual bool		AddPtr(sIxbPtr *pPtr,xbOpMode opm,bool bIfEmpty=false) = 0;
	virtual void		RemovePtr(sIxbPtr *pPtr,bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL) = 0;
	virtual void		SignalPtr(int arg) = 0;

	virtual void		LockPtr() const = 0;
	virtual void		UnlockPtr() const = 0;

	virtual bool		IsInDestruction() const = 0;
};

interface xbEXPORT __declspec(uuid("{EE4E3F60-C1D0-44f0-BC98-3A556BF21FE4}")) 
	IxbObjectPtrNotif:public IxbObject
{
	virtual void				onPtrSignal(sIxbPtrNotif*,int arg) = 0;
	virtual void				onPtrUnlink(sIxbPtrNotif*) = 0;
	virtual void				onPtrLink(sIxbPtrNotif*) = 0;
};

interface xbEXPORT __declspec(uuid("{F0003C25-647C-4ce3-BA0C-9862683B6397}")) 
	sIxbPtr:public sIxbBase,public sIxbLock
{
	virtual bool				HasObject(const IxbObject *pObj) const = 0;
	virtual void				Unlink(sIxbPtrNotif*,bool bAddAfter) = 0;
	virtual void				onSignal(sIxbPtrNotif*,int arg) = 0;
	virtual void				onLink(sIxbPtrNotif*) = 0;
	virtual void				onUnlink(sIxbPtrNotif*) = 0;

	virtual void				_setNext(sIxbPtr *pNext) = 0;
	virtual void				_setPrev(sIxbPtr *pPrev) = 0;
	virtual void				_link(IxbObject *ptr,sIxbPtr **ppFirst) = 0;
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *plck) = 0;
	virtual sIxbPtr*			_getNext() = 0;

	virtual	bool				_isPtrProtected() const = 0;
	virtual	bool				_isPtrValid() const = 0;
};

//CAUTION: lock order: always object pointers/contents first (xbPtrLock), pointers (xbLock) next
class xbEXPORT xbPtrLock
{
public:
	xbPtrLock()
	{
		m_pObj = NULL;
	}
	xbPtrLock(const IxbObject *pObj)
	{
		m_pObj = NULL;
		Lock(pObj);
	}
	~xbPtrLock()
	{
		eProtect(Unlock());
	}
	void Lock(const IxbObject *pObj)
	{
		if (m_pObj) Unlock();
		pObj->LockPtr();
		m_pObj = pObj;
	}
	void Unlock()
	{
		if (!m_pObj) return;
		const IxbObject	*pObj = m_pObj;
		m_pObj = NULL;
		pObj->UnlockPtr();
	}
protected:
	const IxbObject	*m_pObj;
};

#define xbImplObject() \
	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppInterf) \
	{ \
		eToHRbegin(); \
		if (!GetInterface(riid,ppInterf)) return E_NOINTERFACE; \
		(*(IUnknown**)ppInterf)->AddRef(); \
		eToHRend(); \
		return S_OK; \
	} \
	virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, const void ** ppInterf) const\
	{ \
		eToHRbegin(); \
		if (!GetInterface(riid,ppInterf)) return E_NOINTERFACE; \
		(*(const IxbObject**)ppInterf)->AddRef(); \
		eToHRend(); \
		return S_OK; \
	} \
	virtual ULONG STDMETHODCALLTYPE AddRef() \
	{ \
		return addRef(); \
	} \
	virtual ULONG STDMETHODCALLTYPE Release() \
	{ \
		return release(); \
	} \
	virtual ULONG STDMETHODCALLTYPE AddRef() const \
	{ \
		return ((xbObjectBase*)this)->AddRef(); \
	} \
	virtual ULONG STDMETHODCALLTYPE Release() const \
	{ \
		return ((xbObjectBase*)this)->Release(); \
	} \
	virtual void		LockPtr() const \
	{ \
		m_pSectPtr->Lock(); \
	} \
	virtual void		UnlockPtr() const \
	{ \
		m_pSectPtr->Unlock(); \
	} \
	virtual bool AddPtr(sIxbPtr *pPtr,xbOpMode opm,bool bIfEmpty = false) \
	{ \
		return addPtr(pPtr,opm,bIfEmpty); \
	} \
	virtual void RemovePtr(sIxbPtr *pPtr,bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL) \
	{ \
		removePtr(pPtr,bAddAfter,pPtrNotif); \
	} \
	virtual void SignalPtr(int arg) \
	{ \
		signalPtr(arg); \
	} \
	virtual bool IsInDestruction() const \
	{ \
		return m_bDestruction; \
	} \
	virtual bool GetInterface(REFIID riid, const void ** ppInterf) const \
	{ \
		return ((xbObjectBase*)this)->GetInterface(riid,(void**)ppInterf); \
	}

#define xbImplPtr(base) \
	virtual void				Lock() const {base::Lock();} \
	virtual void				Unlock() const {base::Unlock();} \
	virtual bool				HasObject(const IxbObject *pObj) const {return base::HasObject(pObj);} \
	virtual void				Unlink(sIxbPtrNotif *pPtrNotif,bool bAddAfter) {base::Unlink(pPtrNotif,bAddAfter);} \
	virtual void				onSignal(sIxbPtrNotif *pPtrNotif,int arg) {base::onSignal(pPtrNotif,arg);} \
	virtual void				onUnlink(sIxbPtrNotif *pPtrNotif) {base::onUnlink(pPtrNotif);} \
	virtual void				onLink(sIxbPtrNotif*pPtrNotif) {base::onLink(pPtrNotif);} \
	virtual void				_setNext(sIxbPtr *pNext) {base::_setNext(pNext);} \
	virtual void				_setPrev(sIxbPtr *pPrev) {base::_setPrev(pPrev);} \
	virtual void				_link(IxbObject *ptr,sIxbPtr **ppFirst) {base::_link(ptr,ppFirst);} \
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *plck) {base::_unlink(ppFirst,plck);} \
	virtual sIxbPtr*			_getNext() {return base::_getNext();} \
	virtual	bool				_isPtrProtected() const {return base::_isPtrProtected();} \
	virtual	bool				_isPtrValid() const {return base::_isPtrValid();}


#define xbImplCreateObject(objclass,objinterf) \
	static void CreateObject(xbRefPtr<objinterf> *ppInterf) \
	{ \
		objclass *pObj = xbDnew objclass(); \
		try  \
		{ \
			pObj->Create(); \
			*ppInterf = pObj; \
		} \
		catch(...) \
		{ \
			pObj->Release(); \
			throw; \
		} \
		pObj->Release(); \
	}

#define xbImplCreateObjectWithArg(objclass,objinterf,argtype) \
	static void CreateObject(xbRefPtr<objinterf> *ppInterf,argtype arg) \
	{ \
		objclass *pObj = xbDnew objclass(); \
		try  \
		{ \
			pObj->Create(arg); \
			*ppInterf = pObj; \
		} \
		catch(...) \
		{ \
			pObj->Release(); \
			throw; \
		} \
		pObj->Release(); \
	}

class xbEXPORT xbObjectBase:public IxbObject
{
public:
	xbObjectBase()
	{
		m_pSectPtr = NULL;
		m_nRefCnt = 1;
		m_pFirstPtr = NULL;
		m_bCreated = false;
		m_bDestruction = false;
		m_bAddPtrAllowed = true;
		m_bReusable = true;
	}

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(IxbObject);
		xbImplInterface(IUnknown);
		xbImplInterface(sIxbBase);
		return false;
	}
	virtual bool GetInterface(REFIID riid, const void ** ppInterf) const
	{
		return ((xbObjectBase*)this)->GetInterface(riid,(void**)ppInterf);
	}

	virtual void Create();
	virtual void Destroy();
	
	bool IsCreated() const
	{
		return m_bCreated;
	}
	bool IsReusable() const
	{
		return m_bReusable;
	}	
	bool IsAddPtrAllowed() const
	{
		return m_bAddPtrAllowed;
	}	

/*
#ifdef xbUSE_HEAP
#ifdef _xbALLOCDEBUG
	void *operator new(size_t sz,sIxbHeap *pHeap,const char *pfile,long line)
#else
	void *operator new(size_t sz,sIxbHeap *pHeap)
#endif
	{
		sIxbHeap **ptr = (sIxbHeap**)
#ifdef _xbALLOCDEBUG 
			pHeap->Alloc(sz+sizeof(sIxbHeap*),xbAlloc_Default,pfile,line);
#else
			pHeap->Alloc(sz+sizeof(sIxbHeap*),xbAlloc_Default);
#endif

		if (!ptr)
			xbThrow xbEsys(E_OUTOFMEMORY,"xbObjectBase::operator new() : not enougth memory");
		*(ptr++) = pHeap;
		return ptr;
	}

	void operator delete(void *ptr)
	{
		if (!ptr) return;

		sIxbHeap **ppHeap = (sIxbHeap**)ptr;
		ppHeap--;
		(*ppHeap)->Free(ppHeap);
	}


#ifdef _xbALLOCDEBUG
	void *operator new[](size_t sz,sIxbHeap *pHeap,const char *pfile,long line) {return operator new(sz,pHeap,pfile,line);}
#else
	void *operator new[](size_t sz,sIxbHeap *pHeap) {return operator new(sz,pHeap);}
#endif
	void operator delete[](void *pt) {operator delete(pt);}

//#ifdef gmEXCEPTION_DELETE
#	ifdef _xbALLOCDEBUG
		void operator delete(void *ptr,sIxbHeap *,const char*,long) {operator delete(ptr);}
		void operator delete(void *ptr,const char *,long) {operator delete(ptr);}
		void operator delete[](void *ptr,sIxbHeap *,const char *,long) {operator delete(ptr);}
		void operator delete[](void *ptr,const char *,long) {operator delete(ptr);}
#	else
		void operator delete(void *ptr,sIxbHeap *) {operator delete(ptr);}
		void operator delete[](void *ptr,sIxbHeap *) {operator delete(ptr);}
#	endif
//#endif

#ifdef _xbALLOCDEBUG
	inline void *operator new(size_t sz,const char *pfile,long line)
	{
		return operator new(sz,&g_xbEngineCenter.m_heap,pfile,line);
	}
	inline void *operator new[](size_t sz,const char *pfile,long line)
	{
		return operator new(sz,&g_xbEngineCenter.m_heap,pfile,line);
	}
#else
	inline void *operator new(size_t sz)
	{
		return operator new(sz,&g_xbEngineCenter.m_heap);
	}
	inline void *operator new[](size_t sz)
	{
		return operator new(sz,&g_xbEngineCenter.m_heap);
	}
#endif

#endif
*/
	xbDefaultHeapDnewImpl(xbObjectBase);
protected:
	virtual void onBeforeDestruction(bool /*bInDestroy*/) {}
	virtual void onDestruction(bool /*bInDestroy*/) {}

	virtual ULONG	addRef();
	virtual ULONG	release();
	virtual bool	addPtr(sIxbPtr *pPtr,xbOpMode opm,bool bIfEmpty);
	virtual void	removePtr(sIxbPtr *pPtr,bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL);
	virtual void	removeAllPtr(xbSectLock *pLckPtr);
	virtual void	signalPtr(int arg);

	virtual ~xbObjectBase()
	{
		xbAssert(!m_pSectPtr);
		xbRdbgAssert(m_nRefCnt == 1);
		xbRdbgAssert(m_pFirstPtr == NULL);
		xbAssert(!m_bCreated || m_bDestruction);
	}
	long						m_nRefCnt;
	mutable xbSectShare	*m_pSectPtr;
	sIxbPtr						*m_pFirstPtr;
	volatile bool				m_bCreated,m_bDestruction,m_bReusable;
	bool						m_bAddPtrAllowed;

	xbDclNoCopyForObject(xbObjectBase);
};

class xbEXPORT xbObject:public xbObjectBase
{
public:
	xbObject()
	{
		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		m_sectPtr.DeadLockOrderDef(1,10);
		m_pSectPtr = &m_sectPtr;
	}
	xbImplObject();
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		return xbObjectBase::GetInterface(riid,ppInterf);
	}

protected:	
	virtual ~xbObject()
	{
		m_pSectPtr = NULL;
	}
	mutable xbSectShare	m_sectPtr;
};

#ifdef _RELDBG
template <class T>
class _xbNoAddRefRelease : public T
{
	private:
		STDMETHOD_(ULONG, AddRef)()=0;
		STDMETHOD_(ULONG, Release)()=0;
};
#define xbNOADDREF(T)			_xbNoAddRefRelease<T>*
#define xbNOADDREFPTR(T,ptr)	(_xbNoAddRefRelease<T>*)ptr
#else
#define xbNOADDREF(T)			T*
#define xbNOADDREFPTR(T,ptr)	ptr
#endif

template <class T, const IID* piid = &__uuidof(T)> 
class xbRefPtr
{
public:
	typedef T _PtrClass;
	xbRefPtr()
	{
		m_pObj=NULL;
	}
	xbRefPtr(T* pObj)
	{
		if ((m_pObj = pObj) != NULL)
			m_pObj->AddRef();
	}
	xbRefPtr(const xbRefPtr<T,piid>& pObj)
	{
		if ((m_pObj = pObj.m_pObj) != NULL)
			m_pObj->AddRef();
	}
	~xbRefPtr()
	{
		eProtectBegin();
		Release();
		eProtectEndTrace();
	}
	void Release()
	{
		T* pTemp = m_pObj;
		if (pTemp)
		{
			m_pObj = NULL;
			pTemp->Release();
		}
	}
	operator T*() const
	{
		return (T*)m_pObj;
	}
	T& operator*() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T& xbRefPtr()::operator*() const");
		return *m_pObj;
	}
	T**	Addr()
	{
		if (m_pObj) 
			xbThrow xbElib("pointer is not NULL, can't perform affectation !","T** xbRefPtr()::Addr()");
		return &m_pObj;
	}
	void**	AddrV()
	{
		if (m_pObj) 
			xbThrow xbElib("pointer is not NULL, can't perform affectation !","T** xbRefPtr()::AddrV()");
		return (void**)&m_pObj;
	}
	T**	IOaddr()
	{
		return &m_pObj;
	}
	xbNOADDREF(T) operator->() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T* xbRefPtr()::operator->() const");
		return xbNOADDREFPTR(T,m_pObj);
	}
	xbRefPtr<T,piid> &operator=(T* pObj)
	{
		if (pObj) pObj->AddRef(); 
		Release();
		m_pObj = pObj;
		return *this;
	}
	xbRefPtr<T,piid> &operator=(const xbRefPtr<T,piid>& pObj)
	{
		if (pObj.m_pObj) pObj.m_pObj->AddRef();
		Release();
		m_pObj = pObj.m_pObj;
		return *this;
	}
	bool operator!() const
	{
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
	bool operator==(const xbRefPtr<T,piid> &pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(const xbRefPtr<T,piid> &pT) const
	{
		return !IsEqualObject(pT);
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbRefPtr<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}
	void Attach(T* pT)
	{
		Release();
		m_pObj = pT;
	}
	T* Detach()
	{
		T* pt = m_pObj;
		m_pObj = NULL;
		return pt;
	}
	void CreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
	{
		if (m_pObj) xbThrow xbEsys("T** xbRefPtr()::CreateInstance(), pointer is not NULL !");
		HRtoE(::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, *piid, (void**)&m_pObj));
	}
	void CreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
	{
		if (m_pObj) xbThrow xbEsys("T** xbRefPtr()::CreateInstance(), pointer is not NULL !");
		CLSID clsid;
		HRtoE(::CLSIDFromProgID(szProgID, &clsid));
		HRtoE(::CoCreateInstance(clsid, pUnkOuter, dwClsContext, *piid, (void**)&m_pObj));
	}
	bool IsEmpty() const {return !m_pObj;}
	bool IsValid() const {return m_pObj!=NULL;}
	inline void Empty()
	{
		Release();
	}
protected:
	T* m_pObj;

	xbDclNoNewForObject(xbRefPtr);
};


template <class T, const IID* piid = &__uuidof(T)>
class xbRefQIPtr
{
public:
	typedef T _PtrClass;
	xbRefQIPtr()
	{
		m_pObj=NULL;
	}
	xbRefQIPtr(T* pObj)
	{
		if ((m_pObj = pObj) != NULL)
			m_pObj->AddRef();
	}
	xbRefQIPtr(const xbRefQIPtr<T,piid>& pObj)
	{
		if ((m_pObj = pObj.m_pObj) != NULL)
			m_pObj->AddRef();
	}
	xbRefQIPtr(IUnknown* pObj,xbOpMode opMode = xbOp_Required)
	{
		m_pObj=NULL;
		if (pObj != NULL)
		{
			if (opMode != xbOp_Required)
			{
				if (FAILED(pObj->QueryInterface(*piid, (void **)&m_pObj)))
					m_pObj = NULL;
			}
			else
			{
				HRESULT hr;
				if (FAILED(hr = pObj->QueryInterface(*piid, (void **)&m_pObj)))
					xbThrow xbElib(hr,"pointer is not of asked type, can't perform call !","xbRefQIPtr(), type "+xbString(*piid,true));
			}
		}
		else if (opMode == xbOp_Required)
			xbThrow xbElib("pointer is NULL, can't perform call !","xbRefQIPtr(), type "+xbString(*piid,true));
	}
	~xbRefQIPtr()
	{
		eProtectBegin();
		Release();
		eProtectEndTrace();
	}
	void Release()
	{
		T* pTemp = m_pObj;
		if (pTemp)
		{
			m_pObj = NULL;
			pTemp->Release();
		}
	}
	operator T*() const
	{
		return m_pObj;
	}
	T& operator*() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T& xbRefQIPtr()::operator*() const");
		ATLASSERT(m_pObj!=NULL); return *m_pObj;
	}
	T**	Addr()
	{
		if (m_pObj) 
			xbThrow xbElib("pointer is not NULL, can't perform affectation !","T** xbRefQIPtr()::Addr()");
		return &m_pObj;
	}
	void**	AddrV()
	{
		if (m_pObj) 
			xbThrow xbElib("pointer is not NULL, can't perform affectation !","T** xbRefQIPtr()::AddrV()");
//			xbThrow xbEsys("T** xbRefQIPtr()::AddrV(), pointer is not NULL !");
		return (void**)&m_pObj;
	}
	T**	IOaddr()
	{
		return &m_pObj;
	}
	xbNOADDREF(T) operator->() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T* xbRefQIPtr()::operator->() const");
		return xbNOADDREFPTR(T,m_pObj);
	}
	T* operator=(T* pObj)
	{
		if (pObj) pObj->AddRef();
		Release();
		m_pObj = pObj;
		return (T*)m_pObj;
	}
	T* operator=(const xbRefQIPtr<T>& pObj)
	{
		if (pObj.m_pObj) pObj.m_pObj->AddRef();
		Release();
		m_pObj = pObj.m_pObj;
		return (T*)m_pObj;
	}
	T* operator=(IUnknown* pObj)
	{
		T *ptr = NULL;
		HRtoE(pObj->QueryInterface(*piid,(void**)&ptr));
		Release();
		m_pObj = ptr;
		return (T*)m_pObj;
	}
	bool operator!() const
	{
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
	bool operator==(const xbRefQIPtr<T,piid> &pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(const xbRefQIPtr<T,piid> &pT) const
	{
		return !IsEqualObject(pT);
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbRefQIPtr<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}
	void Attach(T* pT)
	{
		Release();
		m_pObj = pT;
	}
	T* Detach()
	{
		T* pt = m_pObj;
		m_pObj = NULL;
		return pt;
	}
	void CreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
	{
		if (m_pObj) xbThrow xbEsys("T** xbRefQIPtr()::CreateInstance(), pointer is not NULL !");
		HRtoE(::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, *piid, (void**)&m_pObj));
	}
	void CreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
	{
		if (m_pObj) xbThrow xbEsys("T** xbRefQIPtr()::CreateInstance(), pointer is not NULL !");
		CLSID clsid;
		HRtoE(::CLSIDFromProgID(szProgID, &clsid));
		HRtoE(::CoCreateInstance(clsid, pUnkOuter, dwClsContext, *piid, (void**)&m_pObj));
	}
	bool IsEmpty() const {return !m_pObj;}
	bool IsValid() const {return m_pObj!=NULL;}
	inline void Empty()
	{
		Release();
	}
protected:
	T* m_pObj;

	xbDclNoNewForObject(xbRefQIPtr);
};

template <class T, const IID* piid = &__uuidof(T)> 
class xbObsPtr:public sIxbPtr
{
public:
	typedef T _PtrClass;
	xbObsPtr()
	{
		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		m_sect.DeadLockOrderDef(1,20);
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
	}
	xbObsPtr(T* pObj,xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		if (pObj != NULL)
			pObj->AddPtr(this,opm);
	}
	xbObsPtr(const xbObsPtr<T,piid>& pObj,xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		xbRefPtr<T,piid>	ref;
		if (pObj.GetPtr(&ref))
			ref->AddPtr(this,opm);
	}
	~xbObsPtr()
	{
		eProtectTrace(Empty());
	}
	void SetPtrCb(sIxbPtrCb *pCb)
	{
		xbSectLock	lck(&m_sect);
		m_pPtrCb = pCb;
	}

	xbRefPtr<T,piid> Ptr() const
	{
		xbSectLock	lck(&m_sect);
		return m_pObj;
	}
	bool GetPtr(xbRefPtr<T,piid> *pprPtr) const
	{
		xbSectLock	lck(&m_sect);
		if (!m_pObj) return false;
		*pprPtr = m_pObj;
		return true;
	}
/*	xbRefPtr<T,piid> operator*() const
	{
		xbSectLock	lck(&m_sect);
		if (!m_pObj) xbThrow xbEsys("T& xbRefPtr()::operator*() const, pointer is NULL !");
		return m_pObj;
	}*/
	xbObsPtr<T,piid> &operator=(T* pObj)
	{
		if (!pObj || !pObj->AddPtr(this,xbOp_Optional))
			Empty();
		return *this;
	}
	xbObsPtr<T,piid> &operator=(const xbObsPtr<T,piid>& pObj)
	{
		xbRefPtr<T,piid>	ref;
		if (!pObj.GetPtr(&ref) || !ref->AddPtr(this,xbOp_Optional))
			Empty();
		return *this;
	}
	bool operator!() const
	{
		xbSectLock	lck(&m_sect);
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
	bool operator==(const xbObsPtr<T,piid>& pObj) const
	{
		return IsEqualObject(pObj.Ptr());
	}
	bool operator!=(const xbObsPtr<T,piid>& pObj) const
	{
		return !IsEqualObject(pObj.Ptr());
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		xbSectLock	lck(&m_sect);
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbObsPtr<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}

//Methods of sIxbBase
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbPtr);
		xbImplInterface(sIxbLock);
		xbImplInterface(sIxbBase);
		return false;
	}
//Methods of sIxbLock
	virtual void				Lock() const
	{
		m_sect.Lock();
	}
	virtual void				Unlock() const
	{
		m_sect.Unlock();
	}
//Methods of sIxbPtr
	virtual bool				HasObject(const IxbObject *pObj) const
	{
		xbSectLock	lck(&m_sect);
		if (!pObj && !m_pObj) return true;
		if (!pObj || !m_pObj) return false;
		const IxbObject *ptr;
		if (!m_pObj->GetInterface(__uuidof(IxbObject),(const void**)&ptr))
			xbThrow xbEsys(E_NOINTERFACE,"xbObsPtr::HasObject() : object doesn't have interface IxbObject");

		return pObj == ptr;
	}
	virtual void				Unlink(sIxbPtrNotif *pPtrNotif,bool bAddAfter)
	{
		Empty(bAddAfter,pPtrNotif);
	}
	virtual void				onSignal(sIxbPtrNotif *pPtrNotif,int arg) 
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onSignal(pPtrNotif,this,arg);
	}
	virtual void				onUnlink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onUnlink(pPtrNotif,this);
	}
	virtual void				onLink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onLink(pPtrNotif,this);
	}
	virtual	bool				_isPtrProtected() const {return true;}
	virtual	bool				_isPtrValid() const {return m_pObj != NULL;}

	inline bool	SetPtr(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm);
	}
	inline bool	SetPtrIfEmpty(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm,true);
	}
	void Empty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
	}
	bool PtrEmpty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return false;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
		return true;
	}
	bool IsEmpty() const {/*xbSectLock lck(&m_sect);*/return !m_pObj;}
	bool IsValid() const {/*xbSectLock lck(&m_sect);*/return m_pObj!=NULL;}
protected:
	virtual void				_setNext(sIxbPtr *pNext)
	{
		m_pNext = pNext;
	}
	virtual void				_setPrev(sIxbPtr *pPrev)
	{
		m_pPrev = pPrev;
	}
	virtual void				_link(IxbObject *pObj,sIxbPtr **ppFirst)
	{
		xbRdbgAssert(!m_pPrev&&!m_pNext&&(*ppFirst)!=this);
		if (!pObj->GetInterface(*piid,(void**)&m_pObj)) xbThrow xbEsys(E_NOINTERFACE,"xbObsPtr()::_link() : can't get desired interface from pObj");
		m_pPrev = NULL;
		if (*ppFirst) (*ppFirst)->_setPrev(this);
		m_pNext = *ppFirst;
		*ppFirst = this;
	}
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *)
	{
		xbRdbgAssert(m_pPrev || (*ppFirst)==this);
		if (m_pNext) m_pNext->_setPrev(m_pPrev);
		if (m_pPrev) m_pPrev->_setNext(m_pNext);
		else *ppFirst = m_pNext;
		m_pObj = NULL;
		m_pPrev = m_pNext = NULL;
	}
	virtual sIxbPtr*			_getNext()
	{
		return m_pNext;
	}

	mutable xbSectShare	m_sect;
	T*							m_pObj;
	sIxbPtr						*m_pNext,*m_pPrev;
	sIxbPtrCb					*m_pPtrCb;

public:
	xbHeapNewImpl(xbObsPtr);
};

template <class T, const IID* piid = &__uuidof(T)> 
class xbObsPtrExt:public sIxbPtr
{
public:
	typedef T _PtrClass;
	xbObsPtrExt(xbSectShare *pSect)
	{
		m_pPtrCb = NULL;
		m_pSect = pSect;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;

		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		pSect->DeadLockOrderDef(1,20);
	}
	xbObsPtrExt(xbSectShare *pSect, T* pObj, xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pSect = pSect;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		pSect->DeadLockOrderDef(1,20);
		if (pObj != NULL)
			pObj->AddPtr(this,opm);
	}
	xbObsPtrExt(xbSectShare *pSect, const xbObsPtrExt<T,piid>& pObj, xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pSect = pSect;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		pSect->DeadLockOrderDef(1,20);
		xbRefPtr<T,piid>	ref;
		if (pObj.GetPtr(&ref))
			ref->AddPtr(this,opm);
	}
	~xbObsPtrExt()
	{
		eProtectTrace(Empty());
	}
	void SetPtrCb(sIxbPtrCb *pCb)
	{
		xbSectLock	lck(m_pSect);
		m_pPtrCb = pCb;
	}

	xbRefPtr<T,piid> Ptr() const
	{
		xbSectLock	lck(m_pSect);
		return m_pObj;
	}
	bool GetPtr(xbRefPtr<T,piid> *pprPtr) const
	{
		xbSectLock	lck(m_pSect);
		if (!m_pObj) return false;
		*pprPtr = m_pObj;
		return true;
	}
/*	xbRefPtr<T,piid> operator*() const
	{
		xbSectLock	lck(m_pSect);
		if (!m_pObj) xbThrow xbEsys("T& xbRefPtr()::operator*() const, pointer is NULL !");
		return m_pObj;
	}*/
	xbObsPtrExt<T,piid> &operator=(T* pObj)
	{
		if (!pObj || !pObj->AddPtr(this,xbOp_Optional))
			Empty();
		return *this;
	}
	xbObsPtrExt<T,piid> &operator=(const xbObsPtrExt<T,piid>& pObj)
	{
		xbRefPtr<T,piid>	ref;
		if (!pObj.GetPtr(&ref) || !ref->AddPtr(this,xbOp_Optional))
			Empty();
		return *this;
	}
	bool operator!() const
	{
//		xbSectLock	lck(m_pSect);
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
	bool operator==(const xbObsPtrExt<T,piid>& pObj) const
	{
		return IsEqualObject(pObj.Ptr());
	}
	bool operator!=(const xbObsPtrExt<T,piid>& pObj) const
	{
		return !IsEqualObject(pObj.Ptr());
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		xbSectLock	lck(m_pSect);
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbObsPtrExt<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}

//Methods of sIxbBase
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbPtr);
		xbImplInterface(sIxbLock);
		xbImplInterface(sIxbBase);
		return false;
	}
//Methods of sIxbLock
	virtual void				Lock() const
	{
		m_pSect->Lock();
	}
	virtual void				Unlock() const
	{
		m_pSect->Unlock();
	}
//Methods of sIxbPtr
	virtual bool				HasObject(const IxbObject *pObj) const
	{
		xbSectLock	lck(m_pSect);
		if (!pObj && !m_pObj) return true;
		if (!pObj || !m_pObj) return false;
		const IxbObject *ptr;
		if (!m_pObj->GetInterface(__uuidof(IxbObject),(void**)&ptr))
			xbThrow xbEsys(E_NOINTERFACE,"xbObsPtrExt::HasObject() : object doesn't have interface IxbObject");

		return pObj == ptr;
	}
	virtual void				Unlink(sIxbPtrNotif *pPtrNotif,bool bAddAfter)
	{
		Empty(bAddAfter,pPtrNotif);
	}
	virtual void				onSignal(sIxbPtrNotif *pPtrNotif,int arg) 
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onSignal(pPtrNotif,this,arg);
	}
	virtual void				onUnlink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onUnlink(pPtrNotif,this);
	}
	virtual void				onLink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onLink(pPtrNotif,this);
	}
	virtual	bool				_isPtrProtected() const {return true;}
	virtual	bool				_isPtrValid() const {return m_pObj != NULL;}

	inline bool SetPtr(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm);
	}
	inline bool SetPtrIfEmpty(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm,true);
	}
	void Empty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
	}
	bool PtrEmpty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return false;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
		return true;
	}
	bool IsEmpty() const {/*xbSectLock lck(m_pSect);*/return !m_pObj;}
	bool IsValid() const {/*xbSectLock lck(m_pSect);*/return m_pObj!=NULL;}
protected:
	virtual void				_setNext(sIxbPtr *pNext)
	{
		m_pNext = pNext;
	}
	virtual void				_setPrev(sIxbPtr *pPrev)
	{
		m_pPrev = pPrev;
	}
	virtual void				_link(IxbObject *pObj,sIxbPtr **ppFirst)
	{
		xbRdbgAssert(!m_pPrev&&!m_pNext&&(*ppFirst)!=this);
		if (!pObj->GetInterface(*piid,(void**)&m_pObj)) xbThrow xbEsys(E_NOINTERFACE,"xbObsPtrExt()::_link() : can't get desired interface from pObj");
		m_pPrev = NULL;
		if (*ppFirst) (*ppFirst)->_setPrev(this);
		m_pNext = *ppFirst;
		*ppFirst = this;
	}
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *)
	{
		xbRdbgAssert(m_pPrev || (*ppFirst)==this);
		if (m_pNext) m_pNext->_setPrev(m_pPrev);
		if (m_pPrev) m_pPrev->_setNext(m_pNext);
		else *ppFirst = m_pNext;
		m_pObj = NULL;
		m_pPrev = m_pNext = NULL;
	}
	virtual sIxbPtr*			_getNext()
	{
		return m_pNext;
	}

	mutable xbSectShare	*m_pSect;
	T*							m_pObj;
	sIxbPtr						*m_pNext,*m_pPrev;
	sIxbPtrCb					*m_pPtrCb;

	xbDclNoNewForObject(xbObsPtrExt);

};

template <class T, const IID* piid = &__uuidof(T)> 
class xbPtr:public sIxbPtr
{
public:
	typedef T _PtrClass;
	xbPtr()
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
	}
	xbPtr(T* pObj,xbOpMode opm =xbOp_Required)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		if (pObj != NULL)
			pObj->AddPtr(this,opm);
	}
	xbPtr(const xbPtr<T,piid>& pObj,xbOpMode opm =xbOp_Required)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		if (pObj != NULL)
			pObj->AddPtr(this,opm);
	}
	~xbPtr()
	{
		eProtectTrace(Empty());
	}
	void SetPtrCb(sIxbPtrCb *pCb)
	{
		m_pPtrCb = pCb;
	}

	xbRefPtr<T,piid> operator*() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T& xbPtr()::operator*() const");
//			xbThrow xbEsys("T& xbPtr()::operator*() const, pointer is NULL !");
		return m_pObj;
	}
	operator T*() const
	{
		return (T*)m_pObj;
	}
	xbNOADDREF(T) operator->() const
	{
		if (!m_pObj) 
			xbThrow xbElib("pointer is NULL, can't perform call !","T* xbPtr()::operator->() const");
//			xbThrow xbEsys("T* xbPtr()::operator->() const, pointer is NULL !");
		return xbNOADDREFPTR(T,m_pObj);
	}
	void operator=(T* pObj)
	{
		if (pObj) pObj->AddPtr(this,xbOp_Required);
		else Empty();
	}
	void operator=(const xbPtr<T>& pObj)
	{
		if (pObj.IsValid()) pObj->AddPtr(this,xbOp_Required);
		else Empty();
	}
	bool operator!() const
	{
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
/*	bool operator==(const xbPtr<T,piid>& pObj) const
	{
		return IsEqualObject((IxbObject*)pObj);
	}
	bool operator!=(const xbPtr<T,piid>& pObj) const
	{
		return !IsEqualObject(pObj);
	}*/
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbPtr<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}

//Methods of sIxbBase
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbPtr);
		xbImplInterface(sIxbLock);
		xbImplInterface(sIxbBase);
		return false;
	}
//Methods of sIxbLock
	virtual void				Lock() const
	{
//		m_sect.Lock();
	}
	virtual void				Unlock() const
	{
//		m_sect.Unlock();
	}
//Methods of sIxbPtr
	virtual bool				HasObject(const IxbObject *pObj) const
	{
		if (!pObj && !m_pObj) return true;
		if (!pObj || !m_pObj) return false;
		const IxbObject *ptr;
		if (!m_pObj->GetInterface(__uuidof(IxbObject),(void**)&ptr))
			xbThrow xbEsys(E_NOINTERFACE,"xbPtr::HasObject() : object doesn't have interface IxbObject");

		return pObj == ptr;
	}
	virtual void				Unlink(sIxbPtrNotif *pPtrNotif,bool bAddAfter)
	{
		Empty(bAddAfter,pPtrNotif);
	}
	virtual void				onSignal(sIxbPtrNotif *pPtrNotif,int arg) 
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onSignal(pPtrNotif,this,arg);
	}
	virtual void				onUnlink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onUnlink(pPtrNotif,this);
	}
	virtual void				onLink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onLink(pPtrNotif,this);
	}

	inline bool	SetPtr(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm);
	}
	inline bool	SetPtrIfEmpty(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm,true);
	}
	void Empty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		if (!m_pObj) return;
		m_pObj->RemovePtr(this,bAddAfter,pPtrNotif);
	}
	bool PtrEmpty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		if (!m_pObj) return false;
		m_pObj->RemovePtr(this,bAddAfter,pPtrNotif);
		return true;
	}
	bool IsEmpty() const {return !m_pObj;}
	bool IsValid() const {return m_pObj!=NULL;}
protected:
	virtual void				_setNext(sIxbPtr *pNext)
	{
		m_pNext = pNext;
	}
	virtual void				_setPrev(sIxbPtr *pPrev)
	{
		m_pPrev = pPrev;
	}
	virtual void				_link(IxbObject *pObj,sIxbPtr **ppFirst)
	{
		xbRdbgAssert(!m_pPrev&&!m_pNext&&(*ppFirst)!=this);
		pObj->AddRef();
		if (!pObj->GetInterface(*piid,(void**)&m_pObj))
		{
			pObj->Release();
			xbThrow xbEsys(E_NOINTERFACE,"xbPtr()::_link() : can't get desired interface from pObj");
		}
		m_pPrev = NULL;
		if (*ppFirst) (*ppFirst)->_setPrev(this);
		m_pNext = *ppFirst;
		*ppFirst = this;
	}
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *plck)
	{
		T *pObj = m_pObj;
		xbRdbgAssert(m_pPrev || (*ppFirst)==this);
		if (m_pNext) m_pNext->_setPrev(m_pPrev);
		if (m_pPrev) m_pPrev->_setNext(m_pNext);
		else *ppFirst = m_pNext;
		m_pObj = NULL;
		m_pPrev = m_pNext = NULL;
		if (plck) plck->Unlock();
		pObj->Release();
	}
	virtual sIxbPtr*			_getNext()
	{
		return m_pNext;
	}
	virtual	bool				_isPtrProtected() const {return false;}
	virtual	bool				_isPtrValid() const {return m_pObj != NULL;}

	T*							m_pObj;
	sIxbPtr						*m_pNext,*m_pPrev;
	sIxbPtrCb					*m_pPtrCb;

	xbDclNoNewForObject(xbPtr);
};

template <class T, const IID* piid = &__uuidof(T)> 
class xbObsRefPtr:public sIxbPtr
{
public:
	typedef T _PtrClass;
	xbObsRefPtr()
	{
		//Lock order: 1=xbObject.m_sectPtr, 2=xbObsPtr.m_sect
		m_sect.DeadLockOrderDef(1,20);
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
	}
	xbObsRefPtr(T* pObj,xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		if (pObj != NULL)
			pObj->AddPtr(this,opm);
	}
	xbObsRefPtr(const xbObsRefPtr<T,piid>& pObj,xbOpMode opm =xbOp_Optional)
	{
		m_pPtrCb = NULL;
		m_pObj=NULL;
		m_pNext=m_pPrev=NULL;
		xbRefPtr<T,piid>	ref;
		if (pObj.GetPtr(&ref))
			ref->AddPtr(this,opm);
	}
	~xbObsRefPtr()
	{
		eProtectTrace(Empty());
	}
	void SetPtrCb(sIxbPtrCb *pCb)
	{
		xbSectLock	lck(&m_sect);
		m_pPtrCb = pCb;
	}

	xbRefPtr<T,piid> Ptr() const
	{
		xbSectLock	lck(&m_sect);
		return m_pObj;
	}
	bool GetPtr(xbRefPtr<T,piid> *pprPtr) const
	{
		xbSectLock	lck(&m_sect);
		if (!m_pObj) return false;
		*pprPtr = m_pObj;
		return true;
	}
	xbObsRefPtr<T,piid> &operator=(T* pObj)
	{
		if (!pObj || !pObj->AddPtr(this,false))
			Empty();
		return *this;
	}
	xbObsRefPtr<T,piid> &operator=(const xbObsRefPtr<T,piid>& pObj)
	{
		xbRefPtr<T,piid>	ref;
		if (!pObj.GetPtr(&ref) || !ref->AddPtr(this,false))
			Empty();
		return *this;
	}
	bool operator!() const
	{
//		xbSectLock	lck(&m_sect);
		return (m_pObj == NULL);
	}
	bool operator==(IUnknown* pT) const
	{
		return IsEqualObject(pT);
	}
	bool operator!=(IUnknown* pT) const
	{
		return !IsEqualObject(pT);
	}
	bool operator==(const xbObsRefPtr<T,piid>& pObj) const
	{
		return IsEqualObject(pObj.Ptr());
	}
	bool operator!=(const xbObsRefPtr<T,piid>& pObj) const
	{
		return !IsEqualObject(pObj.Ptr());
	}
	// Compare two objects for equivalence
	bool IsEqualObject(IUnknown* pOther) const
	{
		xbSectLock	lck(&m_sect);
		if (m_pObj == NULL && pOther == NULL)
			return true; // They are both NULL objects

		if (m_pObj == NULL || pOther == NULL)
			return false; // One is NULL the other is not

		xbRefPtr<IUnknown> punk1;
		xbRefPtr<IUnknown> punk2;
		((xbObsRefPtr<T,piid>*)this)->m_pObj->QueryInterface(IID_IUnknown, punk1.AddrV());
		pOther->QueryInterface(IID_IUnknown, punk2.AddrV());
		return (IUnknown*)punk1 == (IUnknown*)punk2;
	}

//Methods of sIxbBase
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbPtr);
		xbImplInterface(sIxbLock);
		xbImplInterface(sIxbBase);
		return false;
	}
//Methods of sIxbLock
	virtual void				Lock() const
	{
		m_sect.Lock();
	}
	virtual void				Unlock() const
	{
		m_sect.Unlock();
	}
//Methods of sIxbPtr
	virtual bool				HasObject(const IxbObject *pObj) const
	{
		xbSectLock	lck(&m_sect);
		if (!pObj && !m_pObj) return true;
		if (!pObj || !m_pObj) return false;
		const IxbObject *ptr;
		if (!m_pObj->GetInterface(__uuidof(IxbObject),(const void**)&ptr))
			xbThrow xbEsys(E_NOINTERFACE,"xbObsRefPtr::HasObject() : object doesn't have interface IxbObject");

		return pObj == ptr;
	}
	virtual void				Unlink(sIxbPtrNotif *pPtrNotif,bool bAddAfter)
	{
		Empty(bAddAfter,pPtrNotif);
	}
	virtual void				onSignal(sIxbPtrNotif *pPtrNotif,int arg) 
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onSignal(pPtrNotif,this,arg);
	}
	virtual void				onUnlink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onUnlink(pPtrNotif,this);
	}
	virtual void				onLink(sIxbPtrNotif *pPtrNotif)
	{
		if (!m_pPtrCb) return;
		m_pPtrCb->onLink(pPtrNotif,this);
	}
	virtual	bool				_isPtrProtected() const {return true;}
	virtual	bool				_isPtrValid() const {return m_pObj != NULL;}

	inline bool	SetPtr(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm);
	}
	inline bool	SetPtrIfEmpty(IxbObject *ptr,xbOpMode opm =xbOp_Required)
	{
		return ptr->AddPtr(this,opm,true);
	}
	void Empty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
	}
	bool PtrEmpty(bool bAddAfter = false,sIxbPtrNotif *pPtrNotif = NULL)
	{
		xbRefPtr<T,piid>	ref;
		if (!GetPtr(&ref)) return false;
		ref->RemovePtr(this,bAddAfter,pPtrNotif);
		return true;
	}
	bool IsEmpty() const {/*xbSectLock lck(&m_sect);*/return !m_pObj;}
	bool IsValid() const {/*xbSectLock lck(&m_sect);*/return m_pObj!=NULL;}
protected:
	virtual void				_setNext(sIxbPtr *pNext)
	{
		m_pNext = pNext;
	}
	virtual void				_setPrev(sIxbPtr *pPrev)
	{
		m_pPrev = pPrev;
	}
	virtual void				_link(IxbObject *pObj,sIxbPtr **ppFirst)
	{
		xbRdbgAssert(!m_pPrev&&!m_pNext&&(*ppFirst)!=this);
		pObj->AddRef();
		if (!pObj->GetInterface(*piid,(void**)&m_pObj)) 
		{
			pObj->Release();
			xbThrow xbEsys(E_NOINTERFACE,"xbObsRefPtr()::_link() : can't get desired interface from pObj");
		}
		m_pPrev = NULL;
		if (*ppFirst) (*ppFirst)->_setPrev(this);
		m_pNext = *ppFirst;
		*ppFirst = this;
	}
	virtual void				_unlink(sIxbPtr **ppFirst,xbSectLock *plck)
	{
		T *pObj = m_pObj;
		xbRdbgAssert(m_pPrev || (*ppFirst)==this);
		if (m_pNext) m_pNext->_setPrev(m_pPrev);
		if (m_pPrev) m_pPrev->_setNext(m_pNext);
		else *ppFirst = m_pNext;
		m_pObj = NULL;
		m_pPrev = m_pNext = NULL;
		if (plck) plck->Unlock();
		pObj->Release();
	}
	virtual sIxbPtr*			_getNext()
	{
		return m_pNext;
	}

	mutable xbSectShare	m_sect;
	T*							m_pObj;
	sIxbPtr						*m_pNext,*m_pPrev;
	sIxbPtrCb					*m_pPtrCb;

public:
	xbHeapNewImpl(xbObsRefPtr);
};

template<class interf> inline bool xbCastIn(xbObjectBase *pBase, interf **ppInterf)
{
	if (!pBase) return false;
	return pBase->GetInterface(__uuidof(interf),(void**)ppInterf);
}

class xbEXPORT xbPtrNotif:public sIxbPtrNotif
{
public:
/*	xbPtrNotif()
	{
		m_pObj = NULL;
		m_bObjAdded = false;
		m_bSectLocked = false;
	}*/
	xbPtrNotif(IxbObject *pObj,bool bSectLocked)
	{
		m_pObj = pObj;
		m_bObjAdded = false;
		m_bSectLocked = bSectLocked;
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbPtrNotif);
		xbImplInterface(sIxbBase);
		return false;
	}

	virtual void				AddObjectToNotif(IxbObjectPtrNotif *pObj)
	{
		if (!pObj)
			return;
		if (m_arrObj.Length > 10000)
			xbThrow xbEsys("Too many objects to notify on pointers changes");
		m_arrObj.Add(pObj);
		m_bObjAdded = true;
	}
	virtual IxbObject			*GetObjectLinked() {return m_pObj;}
	virtual bool				IsObjectLinked(IxbObject *pObj) 
	{
		IxbObject *pObj1;
		IxbObject *pObj2;
		xbCastIn<IxbObject>(m_pObj,&pObj1);
		xbCastIn<IxbObject>(pObj,&pObj2);
		return pObj1 == pObj2;
	}

	virtual bool				HasObjectToNotif() const {return m_arrObj.IsValid();}
	virtual bool				IsSectPtrLocked() const {return m_bSectLocked;}
	virtual bool				HasObjectToNotif(IxbObjectPtrNotif *pObj);


	inline bool	hasObjectToNotif() const {return m_arrObj.IsValid();}
	void onSignal(int arg);
	void onLink();
	void onUnlink();
protected:
	xbArray< xbRefPtr<IxbObjectPtrNotif> >	m_arrObj;
	IxbObject								*m_pObj;
	bool									m_bSectLocked,m_bObjAdded;
};

#endif
