#ifndef _xbEXCEPTION_
#define _xbEXCEPTION_
/*<<<***************************************************************************
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: xbException
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<05/09/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

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

#ifndef _xbSTRING_
#	include "xbString.h"
#endif

xbMBretType xbEXPORT xbMBox(xbHWND hWnd,const xbString &sText,const xbString &sTitle,xbMBiconType icon = xbMBicon_Default,xbMBbtnType btn = xbMBbtn_Default);

//interface sIxbDlg;
interface xbEXPORT __declspec(uuid("{853AB0B1-63A3-4f4a-885B-6430D159E75E}"))
	sIxbDlgContainer:public sIxbBase
{
//	virtual bool		ShouldDlgStop(sIxbDlg *pDlg) = 0;
	virtual HWND		GetDlgParentHwnd() const = 0;
};

interface xbEXPORT __declspec(uuid("{3AC61EA0-B406-4a38-9F0A-B1EB415C7A74}"))
	sIxbDlg:public sIxbBase
{
	virtual void		SetCaption(const xbString &str) = 0;
	virtual xbString	GetCaption() const = 0;
	virtual int			ShowModal(sIxbDlgContainer *pCont) = 0;
	virtual void		Show(sIxbDlgContainer *pCont) = 0;
	virtual void		SendStop() = 0;
	virtual bool		IsStopped() = 0;
	virtual void		EndUseDestroy() = 0; //destroy or prepare to reuse
};

interface xbEXPORT __declspec(uuid("{74528C19-47F5-4124-B4DC-50CC74E7C9A9}"))
	sIxbDlgCtx:public sIxbDlgContainer
{
	virtual void				dlgUseLock() const = 0;
	virtual void				dlgUseUnlock() const = 0;
	virtual void				dlgDispLock() const = 0;
	virtual void				dlgDispUnlock() const = 0;
	virtual bool				IsDlgDispLocked() const = 0;	//display forbidden
	virtual bool				IsDlgUseLocked() const = 0;		//dialog(s) in use
	virtual bool				CanShowDlg() const = 0;

	virtual IUnknown			*CreateDlg(const CLSID &dlgid,HWND hWndParent = NULL) = 0;
};

class xbDlgDispLock
{
public:
	xbDlgDispLock()
	{
		m_pObj = NULL;
	}
	xbDlgDispLock(const sIxbDlgCtx *pObj)
	{
		m_pObj = NULL;
		if (pObj) Lock(pObj);
	}
	~xbDlgDispLock()
	{
		eProtect(Unlock());
	}
	void Lock(const sIxbDlgCtx *pObj)
	{
		if (pObj && m_pObj == pObj) return;
		if (m_pObj) Unlock();
		if (pObj)
			pObj->dlgDispLock();
		m_pObj = pObj;
	}
	void Unlock()
	{
		if (!m_pObj) return;
		const sIxbDlgCtx	*pObj = m_pObj;
		m_pObj = NULL;
		pObj->dlgDispUnlock();
	}
	bool IsLocked() const {return m_pObj != NULL;}
protected:
	const sIxbDlgCtx	*m_pObj;
};

class xbDlgUseLock
{
public:
	xbDlgUseLock()
	{
		m_pObj = NULL;
	}
	xbDlgUseLock(const sIxbDlgCtx *pObj)
	{
		m_pObj = NULL;
		if (pObj) Lock(pObj);
	}
	~xbDlgUseLock()
	{
		eProtect(Unlock());
	}
	void Lock(const sIxbDlgCtx *pObj)
	{
		if (pObj && m_pObj == pObj) return;
		if (m_pObj) Unlock();
		if (pObj)
			pObj->dlgUseLock();
		m_pObj = pObj;
	}
	void Unlock()
	{
		if (!m_pObj) return;
		const sIxbDlgCtx	*pObj = m_pObj;
		m_pObj = NULL;
		pObj->dlgUseUnlock();
	}
	bool IsLocked() const {return m_pObj != NULL;}
protected:
	const sIxbDlgCtx	*m_pObj;
};

interface __declspec(uuid("{7ED22EEB-7ECB-4288-B225-53105AD52C5F}")) 
	xbEXPORT sIxbExceptionCtx:public sIxbDlgCtx
{
	virtual bool	ExceptionShow(xbEbase *e,bool bDel,LPCSTR pFile,int nFileLine,LPCSTR pBeforeMsg,LPCSTR pAfterMsg,xbMBbtnType mboxBtns,xbMBretType *pRet) = 0;
	virtual bool	ExceptionTrace(xbEbase *e,bool bDel,LPCSTR pFile,int nFileLine) = 0;
	virtual bool	CanShowExceptionDlg() const = 0;
	virtual bool	ShowMBox(xbHWND hWnd,const xbString &sText,const xbString &sTitle,xbMBiconType mboxIcon,xbMBbtnType mboxBtns,xbMBretType *pRet) = 0;
	virtual bool	GetAppTitle(xbString *pTitle) const = 0;

	virtual void	LockExceptionDlg() const = 0;
	virtual void	UnlockExceptionDlg() const = 0;
};

class xbExceptionDlgLock
{
public:
	xbExceptionDlgLock()
	{
		m_pObj = NULL;
	}
	xbExceptionDlgLock(const sIxbExceptionCtx *pObj)
	{
		m_pObj = NULL;
		if (pObj) Lock(pObj);
	}
	~xbExceptionDlgLock()
	{
		eProtect(Unlock());
	}
	void Lock(const sIxbExceptionCtx *pObj)
	{
		if (m_pObj) Unlock();
		pObj->LockExceptionDlg();
		m_pObj = pObj;
	}
	void Unlock()
	{
		if (!m_pObj) return;
		const sIxbExceptionCtx	*pObj = m_pObj;
		m_pObj = NULL;
		pObj->UnlockExceptionDlg();
	}
	bool IsLocked() const {return m_pObj != NULL;}
protected:
	const sIxbExceptionCtx	*m_pObj;
};
class xbCfgKey;
class xbExceptionCtx;
class xbEXPORT __declspec(uuid("{1CE27827-63AB-4e45-ADA6-2009C0AE4B38}"))
	xbExceptionEngine:public xbEngine
{
public:
	xbExceptionEngine(const char *pLabel,const xbEngines &engUsed = xbEngines())
		:xbEngine(xbEngineStart_Auto,pLabel,engUsed)
	{
		m_bDebugAll = false;
		m_pDfltCtx = NULL;
	}
	virtual ~xbExceptionEngine()
	{
		Destroy();
	}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbExceptionEngine);
		return xbEngine::GetInterface(riid,ppInterf);
	}

	sIxbExceptionCtx	*GetContext();
	sIxbExceptionCtx	*GetDefaultContext();
	bool				IsToDebug(LPCSTR pszEtype,bool bDflt);
	bool				IsToLog(LPCSTR pszEtype,bool bDflt);
	bool				IsToStop(LPCSTR pszEtype,bool bDflt);
	bool				IsToDebug(LPCSTR pszEtype);
	bool				IsToLog(LPCSTR pszEtype);
	bool				IsToStop(LPCSTR pszEtype);
	bool				cfgGetBool(const xbString &szEtype,const xbString &szvalname,bool bDflt,bool bDfltErr);
	bool				cfgGetBool(const xbString &szvalname,bool bDflt,bool bDfltErr);
	ulong				cfgGetUlong(const xbString &szEtype,const xbString &szvalname,ulong dflt,ulong dfltErr);
	ulong				cfgGetUlong(const xbString &szvalname,ulong dflt,ulong dfltErr);
	bool				cfgGetKey(const xbString &szEtype,const xbString &szvalname,xbCfgKey &keyRet);
	bool				cfgGetKey(const xbString &szvalname,xbCfgKey &keyRet);

	sIxbExceptionCtx	*SetContext(sIxbExceptionCtx *pCtx);
	sIxbExceptionCtx	*SetDefaultContext(sIxbExceptionCtx *pCtx);

	virtual bool isLockedByMe() const {return m_sect.IsLockedByMe();}
	mutable xbSectShare	m_sect;
protected:
	virtual void onStart() 
	{
		m_bDebugAll = false;
	}
	virtual bool onStop(bool bForce)
	{
		return true;
	}

	friend xbExceptionCtx;
	bool						m_bDebugAll; //-> big big errors
	sIxbExceptionCtx			*m_pDfltCtx;
};

extern xbExceptionEngine	xbEXPORT g_xbExceptionEngine;

class xbExceptionCtx
{
public:
	xbExceptionCtx()
	{
		m_bSet = false;
		m_pOld = m_pNew = NULL;
	}
	xbExceptionCtx(sIxbExceptionCtx *pCtx)
	{
		m_pOld = g_xbExceptionEngine.SetContext(m_pNew = pCtx);
		m_bSet = true;
	}
	~xbExceptionCtx()
	{
		eProtectTrace(Unset());
	}
	void Set(sIxbExceptionCtx *pCtx)
	{
		if (!m_bSet)
			m_pOld = g_xbExceptionEngine.SetContext(m_pNew = pCtx);
		else
			g_xbExceptionEngine.SetContext(m_pNew = pCtx);
		m_bSet = true;
	}
	void Unset()
	{
		if (!m_bSet) return;
		m_bSet = false;
		sIxbExceptionCtx *pCtx = g_xbExceptionEngine.SetContext(m_pOld);
		if (pCtx != m_pNew)
			xbRelOutput("ERROR: xbExceptionCtx::~xbExceptionCtx() : bad ctx");
	}
	bool IsSet() const {return m_bSet;}
private:
	sIxbExceptionCtx	*m_pOld,*m_pNew;
	bool				m_bSet;
};

class xbEXPORT __declspec(uuid("{D96735CA-00B9-4acc-B14A-C3E1C36C7AB1}")) 
	xbEadv:public xbEbase
{
protected:
	xbEadv(xbHR hr,xbEctorMode ctorMode)
		:xbEbase(hr)
	{
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(xbHR hr,const xbString &msg,xbEctorMode ctorMode)
		:xbEbase(hr),m_msg(msg)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(const xbString &msg,xbEctorMode ctorMode)
		:xbEbase(xbHR_FAIL),m_msg(msg)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(xbHR hr,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode)
		:xbEbase(hr),m_msg(msg),m_ctx(ctx)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(const xbString &msg,const xbString &ctx,xbEctorMode ctorMode)
		:xbEbase(xbHR_FAIL),m_msg(msg),m_ctx(ctx)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(xbEctorMode ctorMode,xbHR hr,const char *pszMsg,va_list ap)
		:xbEbase(hr)
	{
		m_ctxLim=false;
		m_pInnerE=NULL;
		msgFmt(pszMsg,ap);
	}
	xbEadv(xbEctorMode ctorMode,const char *pszMsg,va_list ap)
		:xbEbase()
	{
		m_ctxLim=false;
		m_pInnerE=NULL;
		msgFmt(pszMsg,ap);
	}


	xbEadv(xbEbase *pInnerE,xbHR hr,const xbString &msg,xbEctorMode ctorMode)
		:xbEbase(hr),m_msg(msg)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
	}
	xbEadv(xbEbase *pInnerE,const xbString &msg,xbEctorMode ctorMode)
		:xbEbase(xbHR_FAIL),m_msg(msg)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
		SetInnerE(pInnerE);
	}
	xbEadv(xbEbase *pInnerE,xbHR hr,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode)
		:xbEbase(hr),m_msg(msg),m_ctx(ctx)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
		SetInnerE(pInnerE);
	}
	xbEadv(xbEbase *pInnerE,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode)
		:xbEbase(xbHR_FAIL),m_msg(msg),m_ctx(ctx)
	{
//		m_msg.OwnData();
		m_ctxLim=false;
		m_pInnerE=NULL;
		SetInnerE(pInnerE);
	}
	xbEadv(xbEctorMode ctorMode,xbEbase *pInnerE,xbHR hr,const char *pszMsg,va_list ap)
		:xbEbase(hr)
	{
		m_ctxLim=false;
		m_pInnerE=NULL;
		msgFmt(pszMsg,ap);
		SetInnerE(pInnerE);
	}
	xbEadv(xbEctorMode ctorMode,xbEbase *pInnerE,const char *pszMsg,va_list ap)
		:xbEbase()
	{
		m_ctxLim=false;
		m_pInnerE=NULL;
		msgFmt(pszMsg,ap);
		SetInnerE(pInnerE);
	}
	virtual ~xbEadv();
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEadv";}
	virtual bool IsToWriteOnLogFile() const 
	{
		return g_xbExceptionEngine.IsToLog(GetFullEname(),true);
	}
/*
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "System error";} */
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEadv);
		return xbEbase::GetInterface(riid,ppInterf);
	}

	virtual const char *GetMsg() const {return m_msg;}

	virtual xbString GetCtxString() const
	{
		return m_ctx;
	}
	virtual void	AddCtx(const xbString &ctx)
	{
		if (m_ctxLim)
			return;
		if (m_ctx.Length>=GetCtxLimitLength())
		{
			m_ctxLim=true;
			m_ctx += "${=xhtl}<br><i>[...]</i>";
			return;
		}
		if (m_ctx.IsValid()) m_ctx += "\n${=text}";
		m_ctx += ctx;
		m_ctx.OwnData();
	}
	virtual void	AddCtxDebug(const xbString &ctx)
	{
		AddCtx("${if cppdebug}"+ctx+"${endif}");
	}
	virtual int GetCtxLimitLength() {return 0xFFFF;}
	virtual bool IsCtxLimited() {return m_ctxLim;}

	void SetInnerE(xbEbase *pInnerE);
	xbEbase *GetInnerE() const;
	xbPropertyRW(xbEbase*,InnerE);
protected:
	void traceExcept(xbEctorMode ctorMode);

	xbString	m_msg,m_ctx;
	xbEbase		*m_pInnerE;
	bool		m_ctxLim;

	void msgFmt(const char *pszMsg,va_list ap);
private:
	xbDclNoNewForObject(xbEadv);
	xbDclNoCopyForObject(xbEadv);
};


#define xbEdclStart(ename,baseclass,euid,exportd) \
	class exportd __declspec(uuid(# euid)) \
		ename:public baseclass \
	{ \
	public: \
		static xbEinfoSt s_info; \
		virtual const xbEinfoSt *GetInfo() const {return &s_info;} \
		virtual LPCSTR GetFullEname() const {return # ename;} \
		virtual bool GetInterface(REFIID riid, void ** ppInterf) \
		{ \
			xbImplInterface(ename); \
			return baseclass::GetInterface(riid,ppInterf); \
		} \
		\
		ename(xbHR hr,const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(hr,msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbHR hr,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(hr,msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,xbHR hr,const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,hr,msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,xbHR hr,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,hr,msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,xbHR hr,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,hr,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,xbEbase *pInnerE,xbHR hr,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,pInnerE,hr,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,xbEbase *pInnerE,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,pInnerE,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		static void Throw(xbHR hr,const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(hr,msg,ctx); \
		} \
		static void Throw(xbHR hr,const xbString &msg) \
		{ \
			xbThrow ename(hr,msg); \
		} \
		static void ThrowV(xbHR hr,const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,hr,pszMsg,ap); \
			va_end(ap); \
		} \
		static void Throw(const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(msg,ctx); \
		} \
		static void Throw(const xbString &msg) \
		{ \
			xbThrow ename(msg); \
		} \
		static void ThrowV(const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,pszMsg,ap); \
			va_end(ap); \
		} \
		static void Throw(xbEbase *pInnerE,xbHR hr,const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(pInnerE,hr,msg,ctx); \
		} \
		static void Throw(xbEbase *pInnerE,xbHR hr,const xbString &msg) \
		{ \
			xbThrow ename(pInnerE,hr,msg); \
		} \
		static void ThrowV(xbEbase *pInnerE,xbHR hr,const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,pInnerE,hr,pszMsg,ap); \
			va_end(ap); \
		} \
		static void Throw(xbEbase *pInnerE,const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(pInnerE,msg,ctx); \
		} \
		static void Throw(xbEbase *pInnerE,const xbString &msg) \
		{ \
			xbThrow ename(pInnerE,msg); \
		} \
		static void ThrowV(xbEbase *pInnerE,const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,pInnerE,pszMsg,ap); \
			va_end(ap); \
		}

#define xbEdclHRstart(ename,baseclass,hr,euid,exportd) \
	class exportd __declspec(uuid(# euid)) \
		ename:public baseclass \
	{ \
	public: \
		static xbEinfoSt s_info; \
		virtual const xbEinfoSt *GetInfo() const {return &s_info;} \
		virtual LPCSTR GetFullEname() const {return # ename;} \
		virtual bool GetInterface(REFIID riid, void ** ppInterf) \
		{ \
			xbImplInterface(ename); \
			return baseclass::GetInterface(riid,ppInterf); \
		} \
		\
		ename(const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(hr,msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(hr,msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,hr,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,const xbString &msg,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,hr,msg,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEbase *pInnerE,const xbString &msg,const xbString &ctx,xbEctorMode ctorMode = xbEctor_final) \
			:baseclass(pInnerE,hr,msg,ctx,xbEctor_base) \
		{ \
			traceExcept(ctorMode); \
		} \
		ename(xbEctorMode ctorMode,xbEbase *pInnerE,const char *pszMsg,va_list ap) \
			:baseclass(xbEctor_base,pInnerE,hr,pszMsg,ap) \
		{ \
			traceExcept(ctorMode); \
		} \
		static void Throw(const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(msg,ctx); \
		} \
		static void Throw(const xbString &msg) \
		{ \
			xbThrow ename(msg); \
		} \
		static void ThrowV(const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,pszMsg,ap); \
			va_end(ap); \
		} \
		static void Throw(xbEbase *pInnerE,const xbString &msg,const xbString &ctx) \
		{ \
			xbThrow ename(pInnerE,msg,ctx); \
		} \
		static void Throw(xbEbase *pInnerE,const xbString &msg) \
		{ \
			xbThrow ename(pInnerE,msg); \
		} \
		static void ThrowV(xbEbase *pInnerE,const char *pszMsg,...) \
		{ \
			va_list ap; \
			va_start(ap,pszMsg); \
			xbThrow ename(xbEctor_final,pInnerE,pszMsg,ap); \
			va_end(ap); \
		}



#define xbEdclHRend(ename) xbEdclEnd(ename) 
#define xbEdclEnd(ename) \
	public: \
		xbDefaultHeapDnewImpl(ename); \
	private: \
		xbDclNoCopyForObject(ename); \
	};

#define xbEimpl(ename,baseclass) \
	xbEinfoSt ename::s_info(#ename,&baseclass::s_info)

//Exception xbEuser: to use to display user message and user error (field required or invalid value entered, nothing to do, ...)
xbEdclStart(xbEuser,xbEadv,{47030F84-EDD9-47f6-AC27-9822B5E65C6B},xbEXPORT)
	virtual bool IsToWriteOnLogFile() const 
	{
		return g_xbExceptionEngine.IsToLog(GetFullEname(),false);
	}

	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Message";} 
xbEdclEnd(xbEuser);


//Exception xbEapp: an exception which can be used by final applications
xbEdclStart(xbEapp,xbEadv,{791FA23F-675E-4bd4-9F20-54734E1769EB},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Application error";} 
xbEdclEnd(xbEapp);


//Exception xbEappCfg: an exception which can be used by final applications to indicate config errors
xbEdclStart(xbEappCfg,xbEapp,{10DEB25F-83FB-44ce-8016-A18DA42A6FD6},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Exclamation;}
	virtual const char *GetMBoxTitle() const {return "Configuration error";} 
xbEdclEnd(xbEappCfg);

//Exception xbEarg: to use when invalid arguments are given to a function call (invalid value, enum, conversion, token parse, ...)
xbEdclStart(xbEarg,xbEadv,{7C3073CF-E6A2-44f6-8608-D82CA61F32A6},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Invalid argument error";} 
xbEdclEnd(xbEarg);

//Exception xbElib: to use by library for unclassified errors
xbEdclStart(xbElib,xbEadv,{2007B3DB-7900-41e6-B2B4-1178BE44B22B},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Library error";} 
xbEdclEnd(xbElib);


#define eCtxBegin() \
	try \
	{

#define eCtxEnd(msg) \
	} \
	catch(xbEadv *__e) \
	{ \
		eProtectTrace(__e->AddCtxDebug(xbString(__FILE__) + '(' + xbString(__LINE__) + "): " + msg)); \
		throw; \
	} \
	catch(xbEbase *__e) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = new xbEadvCtx(__e); \
		if (__pE) \
			__pE->AddCtxDebug(xbString(__FILE__) + '(' + xbString(__LINE__) + "): " + msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		__e->Delete(); \
		throw __pE; \
	} \
	catch(...) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = new xbEadvCtx(NULL); \
		if (__pE) \
			__pE->AddCtxDebug(xbString(__FILE__) + '(' + xbString(__LINE__) + "): " + msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		throw __pE; \
	}

#define eCtxEndNoLoc(msg) \
	} \
	catch(xbEadv *__e) \
	{ \
		eProtectTrace(__e->AddCtx(msg)); \
		throw; \
	} \
	catch(xbEbase *__e) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = xbDnew xbEadvCtx(__e); \
		if (__pE) \
			__pE->AddCtx(msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		__e->Delete(); \
		throw __pE; \
	} \
	catch(...) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = xbDnew xbEadvCtx(NULL); \
		if (__pE) \
			__pE->AddCtx(msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		throw __pE; \
	}

#define eCtxEndNoLocDebug(msg) \
	} \
	catch(xbEadv *__e) \
	{ \
		eProtectTrace(__e->AddCtxDebug(msg)); \
		throw; \
	} \
	catch(xbEbase *__e) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = xbDnew xbEadvCtx(__e); \
		if (__pE) \
			__pE->AddCtxDebug(msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		__e->Delete(); \
		throw __pE; \
	} \
	catch(...) \
	{ \
		xbEadvCtx *__pE = NULL; \
		eProtectBegin(); \
		__pE = xbDnew xbEadvCtx(NULL); \
		if (__pE) \
			__pE->AddCtxDebug(msg); \
		eProtectEndTrace(); \
		if (!__pE) throw; \
		throw __pE; \
	}

class xbEXPORT __declspec(uuid("{0438CBCA-AC69-4c8c-9C01-17E62F170261}")) 
	xbEadvCtx:public xbEadv
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEadvCtx);
		return xbEadv::GetInterface(riid,ppInterf);
	}

	xbEadvCtx(xbEbase *pE,xbEctorMode ctorMode = xbEctor_final)
		:xbEadv(xbGetHR(pE),xbGetMsg("raw",pE),xbGetCtx("raw",pE,false,false),xbEctor_base),
		m_eName(xbGetFullEname(pE))
	{
		m_mboxIcon = xbMBicon_Stop;
		m_bWriteToLog = true;
		if (pE)
		{
			m_mboxTitle =	pE->GetMBoxTitle();
			m_mboxIcon =	pE->GetMBoxIcon();
			m_bWriteToLog = pE->IsToWriteOnLogFile();
		}
		else 
			m_mboxTitle = "System error";
	}

	virtual bool IsToWriteOnLogFile() const {return m_bWriteToLog;}

	virtual xbMBiconType GetMBoxIcon() const {return m_mboxIcon;}
	virtual const char *GetMBoxTitle() const {return m_mboxTitle;} 

	virtual LPCSTR GetFullEname() const {return m_eName;}
protected:
	xbString		m_eName;
	xbString		m_mboxTitle;
	bool			m_bWriteToLog;
	xbMBiconType	m_mboxIcon;
private:
	xbDclNoCopyForObject(xbEadvCtx);
public:
	xbDefaultHeapDnewImpl(xbEadvCtx);
};

class xbEXPORT __declspec(uuid("{25A80160-8FB0-4d42-A964-553ECEB2ECD8}")) 
	xbEstack:public xbEadv
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEstack";}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEstack);
		return xbEadv::GetInterface(riid,ppInterf);
	}

	xbEstack(bool bResumed = false,bool bCtxSet = false);

	virtual void exceptionProcess(bool bDtor=false);

	virtual const char *GetMsg() const {return m_msg.IsEmpty()?"Stack overflow":m_msg;}

	virtual bool IsToWriteOnLogFile() const {return true;}

	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Low level system error";} 
	
	bool ToResume() {return !m_bResumed;}
	virtual void SetResumed(bool bFlg=true) {m_bResumed = bFlg;}
protected:
	virtual ~xbEstack() {exceptionProcess(true);} 
	bool	m_bResumed,m_bCtxSet;
private:
	xbDclNoCopyForObject(xbEstack);
public:
	xbDefaultHeapDnewImpl(xbEstack);
};

class xbEXPORT  __declspec(uuid("{74FF5BD8-4E64-4518-A9B5-841F1A48AB63}")) 
	xbEseh:public xbEadv
{
public:
	static xbEinfoSt s_info;
	virtual const xbEinfoSt *GetInfo() const {return &s_info;}

	virtual LPCSTR GetFullEname() const {return "xbEseh";}
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(xbEseh);
		return xbEadv::GetInterface(riid,ppInterf);
	}

	xbEseh(HRESULT hr,const xbString &msg)
		:xbEadv(hr,msg,xbEctor_base)
	{
		m_bCtxSet = false;
		traceExcept(xbEctor_final);
	}
	xbEseh(const xbString &msg)
		:xbEadv(msg,xbEctor_base)
	{
		m_bCtxSet = false;
		traceExcept(xbEctor_final);
	}
	xbEseh(HRESULT hr,const xbString &msg,const xbString &ctx,bool bCtxSet = false)
		:xbEadv(hr,msg,ctx,xbEctor_base)
	{
		m_bCtxSet = bCtxSet;
		traceExcept(xbEctor_final);
	}
	xbEseh(xbEctorMode ctorMode,HRESULT hr,const char *pszMsg,va_list ap)
		:xbEadv(hr,pszMsg,ap,xbEctor_base)
	{
		traceExcept(ctorMode);
	}
	virtual ~xbEseh() {exceptionProcess(true);} 
	virtual void exceptionProcess(bool bDtor=false);

	virtual bool IsToWriteOnLogFile() const 
	{
		return true;
	}

	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "Low level system error";} 
protected:
	bool	m_bCtxSet;
private:
	xbDclNoCopyForObject(xbEseh);
public:
	xbDefaultHeapDnewImpl(xbEseh);
};

//Exception xbElock: to use to signal multithread locks problems (timeouts, deadlocks, ...)
xbEdclStart(xbElock,xbEadv,{9D466170-7074-448a-BFA2-0F03FD3D3518},xbEXPORT)
	virtual xbMBiconType GetMBoxIcon() const {return xbMBicon_Stop;}
	virtual const char *GetMBoxTitle() const {return "MT Locks system error";} 
	virtual bool IsToWriteOnLogFile() const 
	{
		return true;
	}
xbEdclEnd(xbElock);


class xbEXPORT __declspec(uuid("{5EA020FD-0ADD-412d-A0C7-3B0181FDC4A5}"))
	xbAppBase:public xbBase,public sIxbExceptionCtx,public sIxbThreadContextObject
{
public:
	xbAppBase(LPCSTR pszAppId,LPCSTR pszAppLabel = NULL);
	virtual ~xbAppBase();

	virtual xbString	GetAppId() const {return m_appId;}
	virtual xbString	GetAppLabel() const;
	virtual xbString	GetAppName() const;
	virtual xbString	GetAppPath() const;
	virtual xbString	GetAppDir() const;

// sIxbExceptionCtx methods
	virtual bool GetInterface(REFIID riid, void ** ppInterf)
	{
		xbImplInterface(sIxbThreadContextObject);
		xbImplInterface(sIxbExceptionCtx);
		xbImplInterface(sIxbDlgCtx);
		xbImplInterface(xbAppBase);
		return xbBase::GetInterface(riid,ppInterf);
	}
	virtual bool GetInterface(REFIID riid, const void ** ppInterf) const
	{
		return ((xbAppBase*)this)->GetInterface(riid,(void**)ppInterf);
	}
	virtual bool	ExceptionShow(xbEbase *e,bool bDel,LPCSTR pFile,int nFileLine,LPCSTR pBeforeMsg,LPCSTR pAfterMsg,xbMBbtnType btn,xbMBretType *pRet)
	{
		return false;
	}
	virtual bool	ExceptionTrace(xbEbase *e,bool bDel,LPCSTR pFile,int nFileLine)
	{
		return false;
	}
	virtual bool	CanShowExceptionDlg() const
	{
		return m_cLockExceptionDlg <= 0;
	}
	virtual bool	ShowMBox(xbHWND hWnd,const xbString &sText,const xbString &sTitle,xbMBiconType icon,xbMBbtnType btn,xbMBretType *pRet)
	{
		return false;
	}
	virtual bool	GetAppTitle(xbString *pTitle) const
	{
		*pTitle = GetAppLabel();
		return pTitle->IsValid();
	}
	virtual void LockExceptionDlg() const
	{
		m_cLockExceptionDlg++;
	}
	virtual void UnlockExceptionDlg() const
	{
		m_cLockExceptionDlg--;
		xbAssert(m_cLockExceptionDlg>=0);
	}

// sIxbDlgCtx methods
	virtual void				dlgUseLock() const
	{
		m_cLockDlgUse++;
	}
	virtual void				dlgUseUnlock() const
	{
		m_cLockDlgUse--;
		xbAssert(m_cLockDlgUse>=0);
	}
	virtual void				dlgDispLock() const
	{
		m_cLockDlgDisp++;
	}
	virtual void				dlgDispUnlock() const
	{
		m_cLockDlgDisp--;
		xbAssert(m_cLockDlgDisp>=0);
	}
	virtual bool				IsDlgDispLocked() const
	{
		return m_cLockDlgDisp > 0;
	}
	virtual bool				IsDlgUseLocked() const
	{
		return m_cLockDlgUse > 0;
	}
	virtual bool				CanShowDlg() const
	{
		return m_cLockDlgDisp <= 0 && m_cLockExceptionDlg <= 0;
	}
	virtual HWND				GetDlgParentHwnd()const
	{
		return NULL;
	}

	virtual IUnknown			*CreateDlg(const CLSID &dlgid,HWND hWndParent)
	{
		return NULL;
	}

	// sIxbThreadContextObject methods
	virtual void	ThreadContextRelease();
	virtual sIxbThreadContextObject *ThreadContextOld() {return NULL;}
	virtual xbThreadEventObject *ThreadEvent() {return m_eventPtr;}
	virtual bool onThreadShouldStop( ulong evMask ) const;
	virtual bool	onThreadMsg(MSG *pMsg,bool *pbQuit);

	//implementation
	static xbAppBase *Appli()
	{
		return s_pAppli;
	}
	void checkStop() const;
	void checkStop(const xbString &oplabel) const;
	inline bool shouldStop() const
	{
		ulong ev = m_eventPtr.ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldStop(bool bNoStopSection) const
	{
		if (bNoStopSection)
			return m_eventPtr.ProcessToKill();
		ulong ev = m_eventPtr.ProcessEvents();
		if (!ev)
			return false;
		return onThreadShouldStop(ev);
	}
	inline bool shouldKill() const
	{
		return m_eventPtr.ProcessToKill();
	}
protected:
	static xbAppBase	*s_pAppli;
	xbThreadContext		m_ctx;
	xbString			m_appId;
	mutable xbString	m_appLabel;

	mutable long		m_cLockExceptionDlg,m_cLockDlgUse,m_cLockDlgDisp;
public:
	xbThreadEventPtr	m_eventPtr;
};

class xbThreadContext;
xbEXPORT void xbSEHtranslate2( xbThreadContext *pThCtx, unsigned int sehCode, struct _EXCEPTION_POINTERS *psehInfo);
xbEXPORT void xbSEHtranslate( unsigned int sehCode, struct _EXCEPTION_POINTERS *psehInfo);
xbEXPORT void xbUnexpected();
xbEXPORT void xbTerminated();
#endif
