#ifndef _xbVARIANT_
#define _xbVARIANT_
/*<<<***************************************************************************
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: xbVariant
#Project: xdcBase
////////////////////////////////////////////////////////////////////////////////
#Author: Marc MIRTI MANCINELLI
#History:
<28/08/2013: creation.
12/02/2014: this notice inserted.
***************************************************************************>>>*/

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

/*#ifndef _xbDATA_
#	include "xbData.h"
#endif
*/

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

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

#ifndef _xbDATETIME_
#	include "xbDateTime.h"
#endif

#ifndef _xbDATA_
#	include "xbData.h"
#endif

void	xbEXPORT xbVariantCopy( VARIANT* dst, const VARIANT* src );
void	xbEXPORT xbVariantClear( VARIANT* var );
INT		xbEXPORT xbVariantCmp(const VARIANT* pOp1, const VARIANT* pOp2,bool can_convert = false,LCID lcid = 0);

void xbEXPORT xbVariantChangeType(VARIANT *pDest,const VARIANT *pSrce,VARTYPE vt,LCID lcid = 0);

/////////////////////////////////////////////////////////////////////////////
// xbBSTR : from ATL CComBSTR //TODO: method IsEmpty() / Empty() / ...
enum xbAllocHeap
{
	xbAllocSys,
		xbAllocLib
};

#define xbBSTR_ALLOCSYS	0x80000000
#define xbBSTR_TOFREE	0x40000000

#ifdef _DEBUG
#	define	xbBSTRcheck(str) check(str)
#else
#	define	xbBSTRcheck(str)
#endif


class xbEXPORT xbBSTR
{
	int modLg(int lg,int allocBy) const
	{
		if (!allocBy)
			return lg;

		return ((lg+allocBy-1)/allocBy*allocBy);
	}
	inline int modLg(int lg) const
	{
		return lg; //aligner par le heap deja à 32 ou 64
	}
public:
	static BSTR SysAlloc(LPCWSTR pStr, int nSize)
	{
		if (nSize < 0 || nSize >= xbSIZE_LIMIT/2)
			xbThrow xbEsizeLimit("Memory allocation for xbBSTR.SysAlloc greater than size limit (asked="+xbString(nSize*2)+", limit="+xbString(xbSIZE_LIMIT)+")");

		BSTR str = ::SysAllocStringLen(pStr, nSize);
		if (!str)
			xbThrow xbEmem("Out of memory for xbBSTR.SysAlloc, string size="+xbString(nSize));
		return str;
	}
	static BSTR SysAlloc(LPCWSTR pStr)
	{
		BSTR str = ::SysAllocString(pStr);
		if (!str)
			xbThrow xbEmem("Out of memory for xbBSTR.SysAlloc");
		return str;
	}
	xbBSTR()
	{
		m_str = NULL;
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
	}
	xbBSTR(xbAllocHeap mode)
	{
		m_str = NULL;
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
	}
/*	xbBSTR(int nSize,bool bInit,wchar ch = 0)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = SysAlloc(NULL, nSize);
		if (bInit)
		{
			wchar *ptr = m_str;
			while(nSize > 0)
			{
				*(ptr++) = ch;
				nSize--;
			}
		}
	}*/
	xbBSTR(xbAllocHeap mode,int nSize,bool bInit,wchar ch/* = 0*/)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			m_str = SysAlloc(NULL, nSize);
		}
		else
		{
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nSize+3)*sizeof(wchar)));
			*((ulong*)m_str) = nSize;
			m_str += 2;
			m_str[nSize] = 0;
		}

		if (bInit)
		{
			register wchar *ptr = m_str;
			while(nSize > 0)
			{
				*(ptr++) = ch;
				nSize--;
			}
		}
	}
	xbBSTR(LPCWSTR pszStr, int nSize)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		if (pszStr == NULL && nSize > 0) 
			xbThrowEsys(E_POINTER,"xbBSTR::xbBSTR(LPCWSTR pszStr, int nSize) : pszStr is null");
		m_str = SysAlloc(pszStr, nSize);
	}
	xbBSTR(xbAllocHeap mode,LPCWSTR pszStr, int nSize)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		if (pszStr == NULL && nSize > 0) 
			xbThrowEsys(E_POINTER,"xbBSTR::xbBSTR(LPCWSTR pszStr, int nSize) : pszStr is null");
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			m_str = SysAlloc(pszStr, nSize);
		}
		else
		{
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nSize+3)*sizeof(wchar)));
			*((ulong*)m_str) = nSize;
			m_str += 2;
			if (nSize)
				memcpy(m_str,pszStr,nSize*sizeof(wchar));
			m_str[nSize] = 0;
		}
	}
	xbBSTR(LPCWSTR pszStr)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		if (pszStr == NULL) 
		{
			m_str = NULL;
			return;
		}
		m_str = SysAlloc(pszStr);
	}
	xbBSTR(xbAllocHeap mode,LPCWSTR pszStr)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		if (pszStr == NULL) 
		{
			m_str = NULL;
			return;
		}
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			m_str = SysAlloc(pszStr);
		}
		else
		{
			int nSize = int(wcslen(pszStr));
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nSize+3)*sizeof(wchar)));
			*((ulong*)m_str) = nSize;
			m_str += 2;
			if (nSize)
				memcpy(m_str,pszStr,nSize*sizeof(wchar));
			m_str[nSize] = 0;
		}
	}
	xbBSTR(const xbBSTR& src)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = src.Copy(xbAllocSys);
	}
	xbBSTR(xbAllocHeap mode,const xbBSTR& src)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = src.Copy(mode);
	}

	xbBSTR(LPCSTR pSrc)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = NULL;
		if (pSrc)
			::xbCPconvert(CP_ACP,pSrc,int(strlen(pSrc)),this);
	}
	xbBSTR(xbAllocHeap mode,LPCSTR pSrc)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = NULL;
		if (pSrc)
			::xbCPconvert(CP_ACP,pSrc,int(strlen(pSrc)),this);
	}

	xbBSTR(ulong cp,LPCSTR pSrc)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = NULL;
		if (pSrc)
			::xbCPconvert(cp,pSrc,int(strlen(pSrc)),this);
	}
	xbBSTR(xbAllocHeap mode,ulong cp,LPCSTR pSrc)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = NULL;
		if (pSrc)
			::xbCPconvert(cp,pSrc,int(strlen(pSrc)),this);
	}
	xbBSTR(LPCSTR pSrc,int nLen)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = NULL;
		::xbCPconvert(CP_ACP,pSrc,nLen,this);
	}

	xbBSTR(xbAllocHeap mode,LPCSTR pSrc,int nLen)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = NULL;
		::xbCPconvert(CP_ACP,pSrc,nLen,this);
	}

	xbBSTR(ulong cp,LPCSTR pSrc,int nLen)
	{
		m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		m_str = NULL;
		::xbCPconvert(cp,pSrc,nLen,this);
	}

	xbBSTR(xbAllocHeap mode,ulong cp,LPCSTR pSrc,int nLen)
	{
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = NULL;
		::xbCPconvert(cp,pSrc,nLen,this);
	}

	xbBSTR& operator=(const xbBSTR& src)
	{
		xbAssert(this != &src && (!m_str || m_str != src.m_str) );
		Clear();
		m_str = src.Copy(GetAllocHeap());
		return *this;
	}

	xbBSTR& operator=(LPCWSTR pszStr)
	{
		Clear();
		if (!pszStr) 
			return *this;
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			m_str = SysAlloc(pszStr);
		}
		else
		{
			int nSize = int(wcslen(pszStr));
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nSize+3)*sizeof(wchar)));
			*((ulong*)m_str) = nSize;
			m_str += 2;
			if (nSize)
				memcpy(m_str,pszStr,nSize*sizeof(wchar));
			m_str[nSize] = 0;
		}
		return *this;
	}

	~xbBSTR()
	{
		eProtect(Clear());
	}
	int GetLength() const
	{
		if (!m_str)
			return 0;
		if (m_bstrMode & xbBSTR_ALLOCSYS)
			return SysStringLen(m_str);
		return *(((ulong*)m_str)-1);
	}
	int SetLength(int nLen,bool bAutoOwn = true)
	{
		if (bAutoOwn && !(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			if(!::SysReAllocStringLen(&m_str,NULL,nLen))
				xbThrow xbEmem("xbBSTR::SetLength(int nLen) : not enough memory");
			return nLen;
		}
		m_str = (wchar*)g_xbEngineCenter.m_heap.xbReAlloc(m_str?m_str-2:NULL,modLg((nLen+3)*sizeof(wchar)));
		//xbRdbgAssert(g_xbEngineCenter.m_heap.GetSize(m_str) == 80);
		*((ulong*)m_str) = nLen;
		m_str += 2;
		m_str[nLen] = 0;
		return nLen;
	}
	int SetLengthInit(int nLen)
	{
		if (!(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			if(!::SysReAllocStringLen(&m_str,NULL,nLen))
				xbThrow xbEmem("xbBSTR::SetLength(int nLen) : not enough memory");
			return nLen;
		}
		m_str = (wchar*)g_xbEngineCenter.m_heap.xbReAllocInit(m_str?m_str-2:NULL,(nLen+3)*sizeof(wchar));
		//xbRdbgAssert(g_xbEngineCenter.m_heap.GetSize(m_str) == 80);
		*((ulong*)m_str) = nLen;
		m_str += 2;
		m_str[nLen] = 0;
		return nLen;
	}
	xbPropertyRW(int,Length);
	int GetByteLength() const
	{
		if (!m_str)
			return 0;
		if (m_bstrMode & xbBSTR_ALLOCSYS)
			return SysStringByteLen(m_str);
		return (*(((ulong*)m_str)-1))*sizeof(wchar);
	}
	xbPropertyR(int,ByteLength);

	operator const wchar*() const
	{
		xbBSTRcheck(m_str);
		return m_str;
	}
	operator xbStringW() const
	{
		return m_str==NULL?L"":m_str;
	}
	wchar	*GetWritePtr(int len)
	{
		SetLength(len);
		xbRdbgAssert(m_str);
		return m_str;
	}
	wchar	*GetWritePtr()
	{
		xbRdbgAssert(m_str);
		return m_str;
	}

	BSTR* Addr()
	{
		if (m_str != NULL || !(m_bstrMode & xbBSTR_TOFREE))
			xbThrowEsys("BSTR* xbBSTR::Addr() : bstr not empty !");
		return &m_str;
	}
	BSTR* IOaddr()
	{
		if (!(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		return &m_str;
	}
	BSTR Copy() const
	{
		if (m_str == NULL) 
			return NULL;
		xbBSTRcheck(m_str);
		if (m_bstrMode & xbBSTR_ALLOCSYS)
			return SysAlloc(m_str, ::SysStringLen(m_str));

		int nLen = *(((ulong*)m_str)-1);
		BSTR bstr = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nLen+3)*sizeof(wchar)));
		*((ulong*)bstr) = nLen;
		bstr += 2;
		if (nLen)
			memcpy(bstr,m_str,nLen*sizeof(wchar));
		bstr[nLen] = 0;
		return bstr;
	}
	BSTR Copy(xbAllocHeap mode) const
	{
		if (m_str == NULL) 
			return NULL;
		xbBSTRcheck(m_str);
		int nLen;
		if (m_bstrMode & xbBSTR_ALLOCSYS)
			nLen = ::SysStringLen(m_str);
		else
			nLen = *(((ulong*)m_str)-1);

		BSTR bstr;
		if (mode == xbAllocSys)
		{
			bstr = SysAlloc(m_str, nLen);
		}
		else
		{
			bstr = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nLen+3)*sizeof(wchar)));
			*((ulong*)bstr) = nLen;
			bstr += 2;
			if (nLen)
				memcpy(bstr,m_str,nLen*sizeof(wchar));
			bstr[nLen] = 0;
		}

		return bstr;
	}
	xbAllocHeap GetAllocHeap() const
	{
		if (m_bstrMode & xbBSTR_ALLOCSYS)
			return xbAllocSys;
		return xbAllocLib;
	}
	xbBSTR& SetAllocHeap(xbAllocHeap mode)
	{
		if (GetAllocHeap() == mode)
		{
			if (!(m_bstrMode & xbBSTR_TOFREE))
			{
				m_str = Copy();
				m_bstrMode |= xbBSTR_TOFREE;
			}
			return *this;
		}
		BSTR bstr = Copy(mode);
		try
		{
			Clear();
		}
		catch(...)
		{
			xbBSTR _bstr;
			_bstr.Attach(mode,&bstr);

			throw;
		}
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = bstr;
		return *this;
	}
	xbPropertyRW(xbAllocHeap,AllocHeap);

	xbBSTR& CopyTo(BSTR* pbstr)
	{
		xbAssert(pbstr != NULL);
		if (pbstr == NULL) 
			xbThrowEsys(E_POINTER,"xbBSTR::CopyTo(BSTR* pbstr) : pbstr is NULL");
		*pbstr = Copy();
		return *this;
	}
	xbBSTR& Attach(BSTR *pSrc)
	{
		xbBSTRcheck(*pSrc);
		Clear();
		m_str = *pSrc;
		*pSrc = NULL;
		return *this;
	}
	xbBSTR& Attach(xbAllocHeap mode,BSTR *pSrc)
	{
		Clear();
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		xbBSTRcheck(*pSrc);
		m_str = *pSrc;
		*pSrc = NULL;
		return *this;
	}
	xbBSTR& Attach(xbBSTR *pSrc)
	{
		pSrc->OwnData();

		Clear();

		if (pSrc->AllocHeap == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS|xbBSTR_TOFREE;
		else
			m_bstrMode = xbBSTR_TOFREE;
		m_str = pSrc->m_str;
		pSrc->m_str = NULL;
		return *this;
	}
	xbBSTR& AttachEx(const BSTR Src)
	{
		xbBSTRcheck(Src);
		Clear();
		m_bstrMode &= ~xbBSTR_TOFREE;
		m_str = Src;
		return *this;
	}
	xbBSTR& AttachEx(xbAllocHeap mode,const BSTR Src)
	{
		Clear();
		if (mode == xbAllocSys)
			m_bstrMode = xbBSTR_ALLOCSYS;
		else
			m_bstrMode = 0;
		xbBSTRcheck(Src);
		m_str = Src;
		return *this;
	}
	BSTR Detach()
	{
		if (!(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		xbBSTRcheck(m_str);
		BSTR s = m_str;
		m_str = NULL;
		return s;
	}
	inline void Clear()
	{
		if (!m_str) 
		{
			m_bstrMode |= xbBSTR_TOFREE;
			return;
		}
		
		xbBSTRcheck(m_str);
		if (m_bstrMode & xbBSTR_TOFREE) 
		{
			if (m_bstrMode & xbBSTR_ALLOCSYS)
				::SysFreeString(m_str);
			else
				g_xbEngineCenter.m_heap.Free(m_str-2);
		}
		else 
			m_bstrMode |= xbBSTR_TOFREE;
		m_str = NULL;
	}
	inline void Empty() {Clear();}
	inline bool IsNull() const
	{
		return (m_str == NULL);
	}
	inline bool IsEmpty() const
	{
		return (m_str == NULL) || (GetLength() == 0);
	}
	inline bool IsValid() const
	{
		return (m_str != NULL) && (GetLength() > 0);
	}
/*	bool operator!() const
	{
		return (m_str == NULL);
	}*/
	xbBSTR& Add(const xbBSTR& bstrSrc)
	{
		Add(bstrSrc.m_str, bstrSrc.Length);
		return *this;
	}
	xbBSTR& Add(LPCWSTR lpsz)
	{
		Add(lpsz, int(wcslen(lpsz)));
		return *this;
	}
	// a BSTR is just a LPCWSTR so we need a special version to signify
	// that we are appending a BSTR
	xbBSTR& AppendBSTR(xbAllocHeap mode,BSTR p)
	{
		xbBSTR _p;
		_p.AttachEx(mode,p);
		Add(_p);
		return *this;
	}
	xbBSTR& Add(LPCWSTR lpsz, int nLen)
	{
		if (!(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		int prevLen = GetLength();
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			if(!::SysReAllocStringLen(&m_str,NULL,prevLen+nLen))
				xbThrow xbEmem("xbBSTR::Add(LPCWSTR lpsz, int nLen) : not enough memory");
		}
		else
		{
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbReAlloc(m_str?m_str-2:NULL,modLg((prevLen+nLen+3)*sizeof(wchar)));
			*((ulong*)m_str) = prevLen+nLen;
			m_str += 2;
			m_str[prevLen+nLen] = 0;
		}

		if (nLen)
			memcpy(m_str+prevLen, lpsz, nLen*sizeof(wchar));
		return *this;
	}
	xbBSTR& AppendEx(const xbBSTR& bstrSrc,int allocBy, bool bAutoOwn = true)
	{
		AppendEx(bstrSrc.m_str, bstrSrc.Length, allocBy,bAutoOwn);
		return *this;
	}
	xbBSTR& AppendEx(LPCWSTR lpsz, int nLen,int allocBy, bool bAutoOwn=true)
	{
		if (allocBy < 0)
			xbThrowEsys(E_INVALIDARG,"xbBSTR::AppendEx(LPCWSTR lpsz, int nLen, int allocBy) : allocBy invalid");

		if (bAutoOwn && !(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		int prevLen = GetLength();
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			if(!::SysReAllocStringLen(&m_str,NULL,prevLen+nLen))
				xbThrow xbEmem("xbBSTR::Add(LPCWSTR lpsz, int nLen) : not enough memory");
		}
		else
		{
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbReAlloc(m_str?m_str-2:NULL,modLg((prevLen+nLen+3)*sizeof(wchar),allocBy*2));
			*((ulong*)m_str) = prevLen+nLen;
			m_str += 2;
			m_str[prevLen+nLen] = 0;
		}

		if (nLen)
			memcpy(m_str+prevLen, lpsz, nLen*sizeof(wchar));
		return *this;
	}
	void Lower(bool bAutoOwn=true)
	{
		if (bAutoOwn && !(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		if (m_str != NULL) 
			xbWcslwr(m_str,GetLength());
	}
	void Upper(bool bAutoOwn=true)
	{
		if (bAutoOwn && !(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		if (m_str != NULL) 
			xbWcsupr(m_str,GetLength());
	}
	xbBSTR&		LoadFromRes(UINT id,LPCWSTR dflt = NULL,HINSTANCE hInst = NULL)
	{
		wchar pszStr[512];
		uint nLen = ::LoadStringW(hInst, id, pszStr, 512);
		xbAssert(nLen < 512);
		Clear();
		if (nLen) 
			dflt = pszStr;
		else if (!dflt) 
			xbThrowEsysFmt(xbHR_LAST,"xbBSTR::LoadFromRes(UINT id=0x%lX,LPCSTR dflt,HINSTANCE hInst)",id);
		return operator=(dflt);
	}

	xbBSTR& operator+=(const xbBSTR& bstrSrc)
	{
		Add(bstrSrc);
		return *this;
	}
	bool operator<(BSTR bstrSrc) const
	{
		if (bstrSrc == NULL && m_str == NULL)
			return false;
		if (bstrSrc != NULL && m_str != NULL)
			return wcscmp(m_str, bstrSrc) < 0;
		return m_str == NULL;
	}
	bool operator==(BSTR bstrSrc) const
	{
		if (bstrSrc == NULL && m_str == NULL)
			return true;
		if (bstrSrc != NULL && m_str != NULL)
			return wcscmp(m_str, bstrSrc) == 0;
		return false;
	}
	bool operator<(LPCSTR pszSrc) const
	{
		if (pszSrc == NULL && m_str == NULL)
			return false;
		if (pszSrc != NULL && m_str != NULL)
			return wcscmp(m_str, xbBSTR(xbAllocLib,pszSrc)) < 0;
		return m_str == NULL;
	}
	bool operator==(LPCSTR pszSrc) const
	{
		if (pszSrc == NULL && m_str == NULL)
			return true;
		if (pszSrc != NULL && m_str != NULL)
			return wcscmp(m_str, xbBSTR(xbAllocLib,pszSrc)) == 0;
		return false;
	}
	xbBSTR&  Add(LPCSTR lpsz)
	{
		xbBSTR		str(xbAllocLib,lpsz);
		return Add(str);
	}
	xbBSTR&  Add(LPCSTR lpsz,int nLen)
	{
		xbBSTR		str(xbAllocLib,lpsz,nLen);
		return Add(str);
	}
	xbBSTR&  Add(ulong cp,LPCSTR lpsz)
	{
		xbBSTR		str(xbAllocLib,cp,lpsz);
		return Add(str);
	}
	xbBSTR&  Add(ulong cp,LPCSTR lpsz,int nLen)
	{
		xbBSTR		str(xbAllocLib,cp,lpsz,nLen);
		return Add(str);
	}

	xbBSTR& operator=(LPCSTR pSrc)
	{
		if (!pSrc)
		{
			Clear();
			return *this;
		}
		::xbCPconvert(CP_ACP,pSrc,int(strlen(pSrc)),this);
		return *this;
	}

	xbBSTR&  SetBSTR(xbAllocHeap mode,BSTR bstr)
	{
		xbBSTR _bstr;
		_bstr.AttachEx(mode,bstr);
		Set(_bstr,_bstr.Length);
		return *this;
	}
	xbBSTR&  Set(const xbBSTR &bstr)
	{
		Set(bstr,bstr.Length);
		return *this;
	}
	xbBSTR&  Set(LPCSTR pSrc)
	{
		::xbCPconvert(CP_ACP,pSrc,int(strlen(pSrc)),this);
		return *this;
	}
	xbBSTR&  Set(LPCSTR pSrc,int nLen)
	{
		::xbCPconvert(CP_ACP,pSrc,nLen,this);
		return *this;
	}
	xbBSTR&  Set(ulong cp,LPCSTR pSrc)
	{
		::xbCPconvert(cp,pSrc,int(strlen(pSrc)),this);
		return *this;
	}
	xbBSTR&  Set(ulong cp,LPCSTR pSrc,int nLen)
	{
		::xbCPconvert(CP_ACP,pSrc,nLen,this);
		return *this;
	}
	xbBSTR&  Set(LPCWSTR lpsz)
	{
		return operator=(lpsz);
	}
	xbBSTR&  Set(LPCWSTR pszStr,int nLen)
	{
		if (m_bstrMode & xbBSTR_TOFREE)
		{
			SetLength(nLen,false);
			if (nLen > 0)
				memcpy(m_str,pszStr,nLen*sizeof(wchar));
			return *this;
		}
		Clear();
		if (pszStr == NULL && nLen > 0) 
			xbThrowEsys(E_POINTER,"xbBSTR::xbBSTR(LPCWSTR pszStr, int nSize) : pszStr is null");
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			m_str = SysAlloc(pszStr, nLen);
		}
		else
		{
			m_str = (wchar*)g_xbEngineCenter.m_heap.xbAlloc(modLg((nLen+3)*sizeof(wchar)));
			*((ulong*)m_str) = nLen;
			m_str += 2;
			if (nLen > 0)
				memcpy(m_str,pszStr,nLen*sizeof(wchar));
			m_str[nLen] = 0;
		}
		return *this;
	}
	xbBSTR& OwnData()
	{
		if (!(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}
		return *this;
	}
	xbBSTR& Insert(int pos, const xbBSTR &str, bool bAutoOwn=true)
	{
		int lg = GetLength();

		pos--;
		if (pos < 0 || pos > lg)
			xbThrowEarg("xbBSTR::Insert(offset, string) : offset is invalid");

		int lg2 = str.GetLength();
		if (lg2<=0)
			return *this;

		SetLength(lg + lg2, bAutoOwn);

		if (lg > pos)
			memmove(m_str+pos+lg2,m_str+pos,(lg-pos)*sizeof(wchar));
		memcpy(m_str+pos,(LPCWSTR)str,lg2*sizeof(wchar));
		return *this;
	}
	xbBSTR &Delete(int pos, int cnt=1,bool bAutoOwn=true)
	{
		int lg = GetLength();

		pos--;
		if (pos < 0 || pos > lg)
			xbThrowEarg("xbBSTR::Delete(offset, string) : offset is invalid");
		if (cnt < 0 || cnt+pos > lg)
			cnt = lg - pos;
		if (cnt <= 0)
			return *this;
		if (bAutoOwn && !(m_bstrMode & xbBSTR_TOFREE))
		{
			m_str = Copy();
			m_bstrMode |= xbBSTR_TOFREE;
		}

		memmove(m_str+pos,m_str+pos+cnt,(lg-pos-cnt)*sizeof(wchar));

		SetLength(lg - cnt, false);

		return *this;
	}

/*
GetToken functions returns:
		return 0; //parse terminated
		return -1; //string not terminated
		return -2; //delimited block not terminated
		else <= input string lg+1
*/
	int	GetToken(int start,const wchar *pSeps,xbBSTR *pStr,xbBSTR *pStrStaying,wchar *pChSep,
	   const wchar *pStringDelimiter,
	   const wchar *pDelimiterStart,const wchar *pDelimiterEnd,bool bSpcNet) const;
	int GetTokenString(int start,const wchar *pStringDelimiter, xbBSTR *pStr,
			wchar *pchDelimiter,bool *pbMixedDelimiter) const;

	void Trim(const wchar *pTrimChars = xbSTRING_TRIMCHARSW, bool bAutoOwn = true)
	{
		trim(pTrimChars,bAutoOwn,true,true);
	}
	void TrimLeft(const wchar *pTrimChars = xbSTRING_TRIMCHARSW, bool bAutoOwn = true)
	{
		trim(pTrimChars,bAutoOwn,true,false);
	}
	void TrimRight(const wchar *pTrimChars = xbSTRING_TRIMCHARSW, bool bAutoOwn = true)
	{
		trim(pTrimChars,bAutoOwn,false,true);
	}
protected:
	void trim(const wchar *pTrimChars, bool bAutoOwn, bool bLeft, bool bRight);
	BSTR	m_str;
	ulong	m_bstrMode;

#ifdef _DEBUG
	inline void check(BSTR ptr) const
	{
		if (m_bstrMode & xbBSTR_ALLOCSYS)
		{
			xbAssert(!ptr || !::g_xbEngineCenter.m_heap.IsValid(ptr-2));
		}
		else
		{
			xbAssert(!ptr || ::g_xbEngineCenter.m_heap.IsValid(ptr-2));
		}
	}
#endif
};


/////////////////////////////////////////////////////////////////////////////
// xbVariant : from ATL CComVariant
//Bugs corrigés sur 5.0.3.69 / > 14/1/03 (pos <= lg), pbs sur fonctions IsInterface, ... en cas de passage par ref
class xbEXPORT xbVariant:public sIxbStreamable
{
public:
// Constructors
	xbVariant()
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
	}
	~xbVariant()
	{
		eProtect(Clear());
	}

	xbVariant(const VARIANT& varSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		CopyFrom(varSrc);
	}

	xbVariant(const xbVariant& varSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		CopyFrom(varSrc);
	}

	xbVariant(BSTR bstrSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		*this = bstrSrc;
	}

	xbVariant(const xbBSTR &bstrSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		*this = bstrSrc;
	}

	xbVariant(const xbStringA &lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		//PPAMDIS
		*this = (LPCSTR)lpszSrc;
	}

	xbVariant(const xbStringW &lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		//PPAMDIS
		*this = (LPCWSTR)lpszSrc;
	}

	xbVariant(ulong cp,const xbStringA &lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		SetAsString(cp,lpszSrc);
	}

	xbVariant(LPCWSTR lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		*this = lpszSrc;
	}

	xbVariant(LPCSTR lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		*this = lpszSrc;
	}

	xbVariant(ulong cp,LPCSTR lpszSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_EMPTY;
		SetAsString(cp,lpszSrc);
	}

	xbVariant(bool bSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_BOOL;
#pragma warning(disable: 4310) // cast truncates constant value
		m_var.boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
#pragma warning(default: 4310) // cast truncates constant value
	}

	xbVariant(int nSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_I4;
		m_var.lVal = nSrc;
	}
	xbVariant(uchar nSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_UI1;
		m_var.bVal = nSrc;
	}
	xbVariant(short nSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_I2;
		m_var.iVal = nSrc;
	}
	xbVariant(long nSrc, VARTYPE vtSrc = VT_I4)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		xbAssert(vtSrc == VT_I4 || vtSrc == VT_ERROR);
		m_var.vt = vtSrc;
		m_var.lVal = nSrc;
	}
	xbVariant(float fltSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_R4;
		m_var.fltVal = fltSrc;
	}
	xbVariant(double dblSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_R8;
		m_var.dblVal = dblSrc;
	}
	xbVariant(CY cySrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_CY;
		m_var.cyVal.Hi = cySrc.Hi;
		m_var.cyVal.Lo = cySrc.Lo;
	}
	xbVariant(const xbDateTime &dt)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_DATE;
		m_var.date = dt;
	}
	xbVariant(int64 cySrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_I8;
		m_var.cyVal.int64 = cySrc;
	}
	xbVariant(IDispatch* pSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_DISPATCH;
		m_var.pdispVal = pSrc;
		if (m_var.pdispVal != NULL)
			m_var.pdispVal->AddRef();
	}
	xbVariant(IUnknown* pSrc)
	{
		m_lcid = xbLCID_USER;
		m_bDeref = false;
		m_bToFree = true;
		m_var.vt = VT_UNKNOWN;
		m_var.punkVal = pSrc;
		if (m_var.punkVal != NULL)
			m_var.punkVal->AddRef();
	}

// Assignment Operators
	xbVariant& operator=(const xbVariant& varSrc)
	{
		CopyFrom(varSrc);
		return *this;
	}
	xbVariant& SetRef(const xbVariant& varSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var.SetRef(varSrc);
			var.Detach(m_var.pvarVal);
			return *this;
		}
		CopyFrom(varSrc);
		return *this;
	}
	xbVariant& operator=(const VARIANT& varSrc)
	{
		CopyFrom(varSrc);
		return *this;
	}
	xbVariant& SetRef(const VARIANT& varSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var.SetRef(varSrc);
			var.Detach(m_var.pvarVal);
			return *this;
		}
		CopyFrom(varSrc);
		return *this;
	}

	xbVariant& operator=(BSTR bstrSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = bstrSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		xbBSTR bstr(bstrSrc);

		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = bstr.Detach();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = bstr.Detach();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& operator=(const xbBSTR &bstrSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = bstrSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = bstrSrc.Copy();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = bstrSrc.Copy();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& operator=(const xbStringA &lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = lpszSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = lpszSrc.AllocSysString();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = lpszSrc.AllocSysString();
		m_var.vt = VT_BSTR;
		return *this;
	}
	xbVariant& operator=(const xbStringW &lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = lpszSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = lpszSrc.AllocSysString();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = lpszSrc.AllocSysString();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& SetAsString(ulong cp,const xbString &lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::SetAsString(cp,...) : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var.SetAsString(cp,lpszSrc);
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::SetAsString(cp,...) : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = lpszSrc.AllocSysString(cp);
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = lpszSrc.AllocSysString(cp);
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& operator=(LPCWSTR lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = lpszSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		xbBSTR bstr(lpszSrc);
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = bstr.Detach();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}

		Clear();
		m_var.bstrVal = bstr.Detach();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& operator=(LPCSTR lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = lpszSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		xbBSTR bstr(lpszSrc);
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = bstr.Detach();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = bstr.Detach();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& SetAsString(ulong cp,LPCSTR lpszSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::SetAsString(cp,...) : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var.SetAsString(cp,lpszSrc);
			var.Detach(m_var.pvarVal);
			return *this;
		}
		xbBSTR bstr(cp,lpszSrc);
		if (m_var.vt == (VT_BSTR|VT_BYREF))
		{
			if (!m_var.pbstrVal) xbThrowEsys("xbVariant::SetAsString(cp,...) : pointer on value is null (byref)");
			BSTR ptr = *m_var.pbstrVal;
			(*m_var.pbstrVal) = bstr.Detach();
			if (ptr) ::SysFreeString(ptr);
			return *this;
		}
		Clear();
		m_var.bstrVal = bstr.Detach();
		m_var.vt = VT_BSTR;
		return *this;
	}

	xbVariant& operator=(bool bSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = bSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
	#pragma warning(disable: 4310) // cast truncates constant value
		if (m_var.vt == (VT_BOOL|VT_BYREF))
		{
			if (!m_var.pboolVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.pboolVal) = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
			return *this;
		}
		if (m_var.vt != VT_BOOL)
		{
			Clear();
			m_var.vt = VT_BOOL;
		}
		m_var.boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
	#pragma warning(default: 4310) // cast truncates constant value
		return *this;
	}

	xbVariant& operator=(int nSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = nSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_I4|VT_BYREF))
		{
			if (!m_var.plVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.plVal) = nSrc;
			return *this;
		}
		if (m_var.vt != VT_I4)
		{
			Clear();
			m_var.vt = VT_I4;
		}
		m_var.lVal = nSrc;

		return *this;
	}

	xbVariant& operator=(uchar nSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = nSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_UI1|VT_BYREF))
		{
			if (!m_var.pbVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.pbVal) = nSrc;
			return *this;
		}
		if (m_var.vt != VT_UI1)
		{
			Clear();
			m_var.vt = VT_UI1;
		}
		m_var.bVal = nSrc;

		return *this;
	}

	xbVariant& operator=(short nSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = nSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_I2|VT_BYREF))
		{
			if (!m_var.piVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.piVal) = nSrc;
			return *this;
		}
		if (m_var.vt != VT_I2)
		{
			Clear();
			m_var.vt = VT_I2;
		}
		m_var.iVal = nSrc;

		return *this;
	}

	xbVariant& operator=(long nSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = nSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_I4|VT_BYREF))
		{
			if (!m_var.plVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.plVal) = nSrc;
			return *this;
		}
		if (m_var.vt != VT_I4)
		{
			Clear();
			m_var.vt = VT_I4;
		}
		m_var.lVal = nSrc;

		return *this;
	}

	xbVariant& operator=(float fltSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = fltSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_R4|VT_BYREF))
		{
			if (!m_var.pfltVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.pfltVal) = fltSrc;
			return *this;
		}
		if (m_var.vt != VT_R4)
		{
			Clear();
			m_var.vt = VT_R4;
		}
		m_var.fltVal = fltSrc;

		return *this;
	}

	xbVariant& operator=(double dblSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = dblSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_R8|VT_BYREF))
		{
			if (!m_var.pdblVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.pdblVal) = dblSrc;
			return *this;
		}
		if (m_var.vt != VT_R8)
		{
			Clear();
			m_var.vt = VT_R8;
		}
		m_var.dblVal = dblSrc;

		return *this;
	}

	xbVariant& operator=(const xbDateTime &dtSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = dtSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_DATE|VT_BYREF))
		{
			if (!m_var.pdblVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			(*m_var.pdate) = dtSrc;
			return *this;
		}
		if (m_var.vt != VT_DATE)
		{
			Clear();
			m_var.vt = VT_DATE;
		}
		m_var.dblVal = dtSrc;

		return *this;
	}

	xbVariant& operator=(CY cySrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = cySrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_CY|VT_BYREF))
		{
			if (!m_var.pcyVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			m_var.pcyVal->Hi = cySrc.Hi;
			m_var.pcyVal->Lo = cySrc.Lo;
			return *this;
		}
		if (m_var.vt != VT_CY)
		{
			Clear();
			m_var.vt = VT_CY;
		}
		m_var.cyVal.Hi = cySrc.Hi;
		m_var.cyVal.Lo = cySrc.Lo;

		return *this;
	}
	xbVariant& operator=(int64 nSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = nSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_I8|VT_BYREF))
		{
			if (!m_var.pcyVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			m_var.pcyVal->int64 = nSrc;
			return *this;
		}
		if (m_var.vt != VT_I8)
		{
			Clear();
			m_var.vt = VT_I8;
		}
		m_var.cyVal.int64 = nSrc;

		return *this;
	}

	xbVariant& operator=(IDispatch* pSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = pSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_DISPATCH|VT_BYREF))
		{
			if (!m_var.ppdispVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			IDispatch *ptr = *m_var.ppdispVal;
			(*m_var.ppdispVal) = pSrc;
			if (pSrc) pSrc->AddRef();
			if (ptr) ptr->Release();
			return *this;
		}
		Clear();
		m_var.vt = VT_DISPATCH;
		m_var.pdispVal = pSrc;
		if (m_var.pdispVal != NULL)
			m_var.pdispVal->AddRef();

		return *this;
	}

	xbVariant& operator=(IUnknown* pSrc)
	{
		DeRef();
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			xbVariant var;
			var.Attach(m_var.pvarVal);
			var = pSrc;
			var.Detach(m_var.pvarVal);
			return *this;
		}
		if (m_var.vt == (VT_UNKNOWN|VT_BYREF))
		{
			if (!m_var.ppunkVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)");
			IUnknown *ptr = *m_var.ppunkVal;
			(*m_var.ppunkVal) = pSrc;
			if (pSrc) pSrc->AddRef();
			if (ptr) ptr->Release();
			return *this;
		}
		Clear();
		m_var.vt = VT_UNKNOWN;
		m_var.punkVal = pSrc;
		if (m_var.punkVal != NULL)
			m_var.punkVal->AddRef();

		return *this;
	}


// Comparison Operators
	bool operator==(const xbVariant& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)==0;
	}
	bool operator!=(const xbVariant& varSrc) const
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)!=0;
	}
	bool operator<(const xbVariant& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)<0;
	}
	bool operator>(const xbVariant& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)>0;
	}
	bool operator<=(const xbVariant& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)<=0;
	}
	bool operator>=(const xbVariant& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc.m_var, false)>=0;
	}

	bool operator==(const VARIANT& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)==0;
	}
	bool operator!=(const VARIANT& varSrc) const
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)!=0;
	}
	bool operator<(const VARIANT& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)<0;
	}
	bool operator>(const VARIANT& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)>0;
	}
	bool operator<=(const VARIANT& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)<=0;
	}
	bool operator>=(const VARIANT& varSrc) const 
	{
		return ::xbVariantCmp(&m_var, &varSrc, false)>=0;
	}

	int Compare(const xbVariant& varSrc,bool can_convert = false,LCID lcid = 0) const 
	{
		return ::xbVariantCmp(&m_var,&varSrc.m_var,can_convert,lcid);
	}
	int Compare(const VARIANT& varSrc,bool can_convert = false,LCID lcid = 0) const 
	{
		return ::xbVariantCmp(&m_var,&varSrc,can_convert,lcid);
	}

	operator const VARIANT *() const
	{
		return &m_var;
	}
	VARIANT* Addr()
	{
		if (m_var.vt != VT_EMPTY) xbThrowEsys("VARIANT* xbVariant::Addr() : variant not empty !");
		return &m_var;
	}
	VARIANT* IOaddr()
	{
		DeRef();
		return &m_var;
	}

	operator const VARIANT &() const
	{
		return m_var;
	}
// Operations diverses
#define	_xbVARIANTAS(name,ret,t,vmbr) \
	ret	GetAs ## name() const\
	{ \
		return GetAs ## name(xbLCID_NEUTRAL); \
	} \
	ret	GetAs ## name(LCID lcid) const\
	{ \
		if (m_var.vt == t) return m_var.vmbr; \
		if (m_var.vt == (t|VT_BYREF)) \
		{ \
			if (!m_var.p ## vmbr) xbThrowEsys("property xbVariant::As" #name ", read access, reference to variable is NULL"); \
			return *m_var.p ## vmbr; \
		} \
		if (m_var.vt == (VT_VARIANT|VT_BYREF)) \
		{ \
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::As" #name ", read access, reference to variant is null"); \
			xbVariant var; \
			var.AttachEx(*m_var.pvarVal); \
			var.SetLCID(m_lcid); \
			return var.GetAs ## name(lcid); \
		} \
		xbVariant	var; \
		var.SetLCID(m_lcid); \
		var.SetType(t,m_var,lcid); \
		return var.m_var.vmbr; \
	} \
	xbVariant &SetAs ## name(ret nb) \
	{ \
		return operator=(nb); \
	} \
	xbPropertyRW(ret,As ## name);

#define	_xbxbVARIANTAS(ret,t,vmbr) \
	xb ## ret	GetAs ## ret() const\
	{ \
		return GetAs ## ret(xbLCID_NEUTRAL); \
	} \
	xb ## ret	GetAs ## ret(LCID lcid) const\
	{ \
		if (m_var.vt == t) return m_var.vmbr; \
		if (m_var.vt == (t|VT_BYREF)) \
		{ \
			if (!m_var.p ## vmbr) xbThrowEsys("property xbVariant::As" #ret ", read access, reference to variable is NULL"); \
			return *m_var.p ## vmbr; \
		} \
		if (m_var.vt == (VT_VARIANT|VT_BYREF)) \
		{ \
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::As" #ret ", read access, reference to variant is null"); \
			xbVariant var; \
			var.AttachEx(*m_var.pvarVal); \
			var.SetLCID(m_lcid); \
			return var.GetAs ## ret(lcid); \
		} \
		xbVariant	var; \
		var.SetLCID(m_lcid); \
		var.SetType(t,m_var,lcid); \
		return var.m_var.vmbr; \
	} \
	xbVariant &SetAs ## ret(const xb ## ret &val) \
	{ \
		return operator=(val); \
	} \
	xbPropertyRW(xb ##ret,As ## ret);

#define	_xbVARIANT2AS(name,ret,t,vmbr) \
	ret	GetAs ## name() const\
	{ \
		return GetAs ## name(xbLCID_NEUTRAL); \
	} \
	ret	GetAs ## name(LCID lcid) const\
	{ \
		if (m_var.vt == t) return m_var.vmbr; \
		if (m_var.vt == (t|VT_BYREF)) \
		{ \
			if (!m_var.p ## vmbr) xbThrowEsys("property xbVariant::As" #name ", read access, reference to variable is NULL"); \
			return *m_var.p ## vmbr; \
		} \
		if (m_var.vt == (VT_VARIANT|VT_BYREF)) \
		{ \
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::As" #name ", read access, reference to variant is null"); \
			xbVariant var; \
			var.AttachEx(*m_var.pvarVal); \
			var.SetLCID(m_lcid); \
			return var.GetAs ## name(lcid); \
		} \
		xbVariant	var; \
		var.SetLCID(m_lcid); \
		var.SetType(t,m_var,lcid); \
		return var.m_var.vmbr; \
	} \
	xbVariant &SetAs ## name(ret nb) \
	{ \
		DeRef(); \
		if (m_var.vt == (VT_VARIANT|VT_BYREF)) \
		{ \
			if (!m_var.pvarVal) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)"); \
			xbVariant var; \
			var.Attach(m_var.pvarVal); \
			var.As ## name = nb; \
			var.Detach(m_var.pvarVal); \
			return *this; \
		} \
		if (m_var.vt == (t|VT_BYREF)) \
		{ \
			if (!m_var.p ## vmbr) xbThrowEsys("xbVariant::operator=() : pointer on value is null (byref)"); \
			(*m_var.p ## vmbr) = nb; \
			return *this; \
		} \
		if (m_var.vt != t) \
		{ \
			Clear(); \
			m_var.vt = t; \
		} \
		m_var.vmbr = nb; \
		 \
		return *this; \
	} \
	xbPropertyRW(ret,As ## name);

//	_xbxbVARIANTAS(String,VT_BSTR,bstrVal);
	_xbxbVARIANTAS(BSTR,VT_BSTR,bstrVal);
	_xbxbVARIANTAS(DateTime,VT_DATE,date);
	_xbVARIANTAS(Uchar,uchar,VT_UI1,bVal);
	_xbVARIANTAS(Uint8,uchar,VT_UI1,bVal);
	_xbVARIANT2AS(Char,char,VT_I1,cVal);
	_xbVARIANT2AS(Int8,char,VT_I1,cVal);
	_xbVARIANTAS(Short,short,VT_I2,iVal);
	_xbVARIANTAS(Int16,short,VT_I2,iVal);
	_xbVARIANT2AS(Ushort,ushort,VT_UI2,uiVal);
	_xbVARIANT2AS(Uint16,ushort,VT_UI2,uiVal);
	_xbVARIANTAS(Long,long,VT_I4,lVal);
	_xbVARIANTAS(Int32,long,VT_I4,lVal);
	_xbVARIANT2AS(Ulong,ulong,VT_UI4,ulVal);
	_xbVARIANT2AS(Uint32,ulong,VT_UI4,ulVal);
	_xbVARIANTAS(Float,float,VT_R4,fltVal);
	_xbVARIANTAS(Double,double,VT_R8,dblVal);
	_xbVARIANTAS(HR,HRESULT,VT_ERROR,scode);
	int64	GetAsInt64() const
	{
		return GetAsInt64(xbLCID_NEUTRAL);
	}
	int64	GetAsInt64(LCID lcid) const
	{
		if (m_var.vt == VT_I8) return m_var.boolVal?true:false;
		if (m_var.vt == (VT_I8|VT_BYREF)) 
		{
			if (!m_var.pcyVal) xbThrowEsys("property xbVariant::AsInt64, read access, reference to variable is NULL");
			return m_var.pcyVal->int64;
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsInt64, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsInt64(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_I8,m_var,lcid);
		return var.m_var.cyVal.int64;
	}
	xbVariant &SetAsInt64(int64 val)
	{
		return operator=(val);
	}
	xbPropertyRW(int64,AsInt64);
	bool	GetAsBool() const
	{
		return GetAsBool(xbLCID_NEUTRAL);
	}
	bool	GetAsBool(LCID lcid) const
	{
		if (m_var.vt == VT_BOOL) return m_var.boolVal?true:false;
		if (m_var.vt == (VT_BOOL|VT_BYREF)) 
		{
			if (!m_var.pboolVal) xbThrowEsys("property xbVariant::AsBool, read access, reference to variable is NULL");
			return (*m_var.pboolVal)?true:false;
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsBool, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsBool(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_BOOL,m_var,lcid);
		return var.m_var.boolVal?true:false;
	}
	xbVariant &SetAsBool(bool val)
	{
		return operator=(val);
	}
	xbPropertyRW(bool,AsBool);

	IUnknown	*GetAsUnknown() const
	{
		return GetAsUnknown(xbLCID_NEUTRAL);
	}
	IUnknown	*GetAsUnknown(LCID lcid) const
	{
		if (m_var.vt == VT_UNKNOWN) return m_var.punkVal;
		if (m_var.vt == (VT_UNKNOWN|VT_BYREF)) 
		{
			if (!m_var.ppunkVal) xbThrowEsys("property xbVariant::AsUnknown, read access, reference to variable is NULL");
			return *m_var.ppunkVal;
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsUnknown, read access, reference to variant is null");
			xbVariant var;
			var.SetLCID(m_lcid);
			var.AttachEx(*m_var.pvarVal);
			return var.GetAsUnknown(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_UNKNOWN,m_var,lcid);
		return var.m_var.punkVal;
	}
	xbVariant &SetAsUnknown(IUnknown *val)
	{
		return operator=(val);
	}
	xbPropertyRW(IUnknown*,AsUnknown);
	IDispatch	*GetAsDispatch() const
	{
		return GetAsDispatch(xbLCID_NEUTRAL);
	}
	IDispatch	*GetAsDispatch(LCID lcid) const
	{
		if (m_var.vt == VT_DISPATCH) return m_var.pdispVal;
		if (m_var.vt == (VT_DISPATCH|VT_BYREF)) 
		{
			if (!m_var.ppdispVal) xbThrowEsys("property xbVariant::AsDispatch, read access, reference to variable is NULL");
			return *m_var.ppdispVal;
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsDispatch, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsDispatch(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_DISPATCH,m_var,lcid);
		return var.m_var.pdispVal;
	}
	xbVariant &SetAsDispatch(IDispatch *val)
	{
		return operator=(val);
	}
	xbPropertyRW(IDispatch*,AsDispatch);

	xbVariant &SetAsStringA(const xbStringA &val)
	{
		return operator=((LPCSTR)val);
	}
	xbStringA	GetAsStringA() const
	{
		return GetAsStringA(xbLCID_NEUTRAL);
	}
	xbStringA	GetAsStringA(LCID lcid) const
	{
		if (m_var.vt == VT_BSTR) 
			return xbStringA(m_var.bstrVal,m_var.bstrVal?::SysStringLen(m_var.bstrVal):0);
		if (m_var.vt == (VT_BSTR|VT_BYREF)) 
		{
			if (!m_var.pbstrVal) xbThrowEsys("property xbVariant::AsString, read access, reference to variable is NULL");
			return xbStringA(*m_var.pbstrVal,*m_var.pbstrVal?::SysStringLen(*m_var.pbstrVal):0);
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) 
				xbThrowEsys("property xbVariant::AsInt64, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsStringA(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_BSTR,m_var,lcid);
		return xbStringA(var.m_var.bstrVal,var.m_var.bstrVal?::SysStringLen(var.m_var.bstrVal):0);
	}
	xbPropertyRW(xbStringA,AsStringA);
	xbStringA	GetAsStringA(ulong cp,LCID lcid/* = xbLCID_NEUTRAL*/) const
	{
		if (m_var.vt == VT_BSTR) 
			return xbStringA(cp,m_var.bstrVal,m_var.bstrVal?::SysStringLen(m_var.bstrVal):0);
		if (m_var.vt == (VT_BSTR|VT_BYREF)) 
		{
			if (!m_var.pbstrVal) xbThrowEsys("property xbVariant::AsString, read access, reference to variable is NULL");
			return xbStringA(cp,*m_var.pbstrVal,*m_var.pbstrVal?::SysStringLen(*m_var.pbstrVal):0);
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsInt64, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsStringA(cp,lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_BSTR,m_var,lcid);
		return xbStringA(cp,var.m_var.bstrVal,var.m_var.bstrVal?::SysStringLen(var.m_var.bstrVal):0);
	}

	xbVariant &SetAsStringW(const xbStringW &val)
	{
		return operator=((LPCWSTR)val);
	}
	xbStringW	GetAsStringW() const
	{
		return GetAsStringW(xbLCID_NEUTRAL);
	}
	xbStringW	GetAsStringW(LCID lcid) const
	{
		if (m_var.vt == VT_BSTR) 
			return xbStringW(m_var.bstrVal,m_var.bstrVal?::SysStringLen(m_var.bstrVal):0);
		if (m_var.vt == (VT_BSTR|VT_BYREF)) 
		{
			if (!m_var.pbstrVal) xbThrowEsys("property xbVariant::AsString, read access, reference to variable is NULL");
			return xbStringW(*m_var.pbstrVal,*m_var.pbstrVal?::SysStringLen(*m_var.pbstrVal):0);
		}
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) xbThrowEsys("property xbVariant::AsInt64, read access, reference to variant is null");
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			var.SetLCID(m_lcid);
			return var.GetAsStringW(lcid);
		}
		xbVariant	var;
		var.SetLCID(m_lcid);
		var.SetType(VT_BSTR,m_var,lcid);
		return xbStringW(var.m_var.bstrVal,var.m_var.bstrVal?::SysStringLen(var.m_var.bstrVal):0);
	}
	xbPropertyRW(xbStringW,AsStringW);

	inline void Clear() 
	{
		if (m_bToFree)
			::xbVariantClear(&m_var);
		else 
		{
			m_var.vt = VT_EMPTY;
			m_bToFree = true;
		}
		m_bDeref = false;
	}

	xbVariant &CopyFrom(const xbVariant& varSrc) 
	{ 
		Clear();
		::xbVariantCopy(&m_var, (VARIANT*)&varSrc.m_var); 
		m_bDeref = IsRef();
		m_lcid = varSrc.m_lcid;
		return *this;
	}
	xbVariant &CopyFrom(const VARIANT& varSrc) 
	{ 
		::xbVariantCopy(&m_var, (VARIANT*)&varSrc); 
		m_bDeref = IsRef();
//		m_lcid = xbLCID_USER;
		return *this;
	}
	const xbVariant &CopyTo(xbVariant& varSrc) const 
	{ 
		varSrc.CopyFrom(*this); 
		return *this;
	}
	const xbVariant &CopyTo(VARIANT& varSrc) const 
	{ 
		DeRef();
		::xbVariantCopy(&varSrc, (VARIANT*)&m_var); 
		return *this;
	}

	xbVariant &Attach(VARIANT *pSrc)
	{
		// Clear out the variant
		Clear();
		// Copy the contents and give control to xbVariant
		memcpy(&m_var, pSrc, sizeof(VARIANT));
		pSrc->vt = VT_EMPTY;
		return *this;
	}

	xbVariant &AttachEx(const VARIANT &Src)
	{
		// Clear out the variant
		Clear();
		// Copy the contents and give control to xbVariant
		memcpy(&m_var, &Src, sizeof(VARIANT));
		m_bToFree = false;
		return *this;
	}

	xbVariant &AttachRef(VARIANT *pSrc)
	{
		// Clear out the variant
		Clear();
		// Point on pSrc
		m_var.vt = VT_VARIANT|VT_BYREF;
		m_var.pvarVal = pSrc;
		return *this;
	}

	xbVariant &Detach(VARIANT *pDest = NULL)
	{
		if (pDest) 
		{
			// Clear out the variant
//			::xbVariantClear(pDest);
			// Copy the contents and remove control from xbVariant
			memcpy(pDest, &m_var, sizeof(VARIANT));
		}
		m_bToFree = false;
		return *this;
	}

	VARTYPE  GetType() const {return m_var.vt;}
	xbVariant &SetType(VARTYPE vtNew,LCID lcid = xbLCID_NEUTRAL)
	{
		// Do nothing if doing in place convert and vts not different
		if (vtNew != m_var.vt)
		{
			if (m_bToFree)
			{
				xbVariantChangeType(&m_var, &m_var, vtNew,lcid == xbLCID_NEUTRAL?m_lcid:lcid);
			}
			else
			{
				VARIANT Src;
				memcpy(&Src, &m_var, sizeof(VARIANT));
				m_var.vt = VT_EMPTY;
				m_bToFree = true;
				xbVariantChangeType(&m_var, &Src, vtNew, lcid == xbLCID_NEUTRAL?m_lcid:lcid);
			}
		}
		return *this;
	}
	xbVariant &SetType(VARTYPE vtNew,const VARIANT &Src,LCID lcid = xbLCID_NEUTRAL)
	{
		if (!m_bToFree) Clear();
		xbVariantChangeType(&m_var, &Src, vtNew, lcid == xbLCID_NEUTRAL?m_lcid:lcid);
		return *this;
	}
	xbVariant &SetType(VARTYPE vtNew,const xbVariant &Src,LCID lcid = xbLCID_NEUTRAL)
	{
		if (!m_bToFree) Clear();
		xbVariantChangeType(&m_var, &Src.m_var, vtNew, lcid == xbLCID_NEUTRAL?m_lcid:lcid);
		return *this;
	}
	xbPropertyRW(VARTYPE,Type);
	xbPropertyExtRW(VARTYPE,GetType,SetType,vt);

	xbStringW GetAsXmlStringW() const;
	void SetAsXmlStringW(const xbStringW &str);
	xbPropertyRW(xbStringW,AsXmlStringW);

	bool AsXmlStringWsupported() const
	{
		return AsXmlStringWsupported(GetType());
	}
	static bool AsXmlStringWsupported(VARTYPE vtype)
	{
		return AsXmlStringWtypeToName(vtype) != NULL;
	}
	static LPCWSTR AsXmlStringWtypeToName(VARTYPE vtype);
	static bool AsXmlStringWtypeNameGet(const xbStringW &str,xbStringW *pTypeStr,xbStringW *pVal);

	void SetLCID(LCID lcid)
	{
		m_lcid = lcid;
	}
	LCID GetLCID() const
	{
		return m_lcid;
	}
	xbPropertyExtRW(LCID,GetLCID,SetLCID,Lcid);
	
	inline bool NoRef()
	{
		if (!(m_var.vt & VT_BYREF)) 
		{
			m_bDeref = false;
			return false;
		}
		if (m_var.vt != (VT_VARIANT | VT_BYREF))
		{
			SetType(m_var.vt & (~VT_BYREF));
			m_bDeref = false;
			return true;
		}
		VARIANT *pVar = m_var.pvarVal;
		while(pVar && pVar->vt == (VT_VARIANT | VT_BYREF))
		{
			pVar = pVar->pvarVal;
		}
		if (!pVar) {Clear(); return true;}
		if (pVar->vt & VT_BYREF) SetType(pVar->vt & (~VT_BYREF),*pVar);
		else CopyFrom(*pVar);
		return true;
	}
	inline void DeRef() const
	{
		if (!m_bDeref) return;
		((xbVariant*)this)->NoRef();
	}
	inline void OwnData()
	{
		NoRef();
	}
	inline VARTYPE	GetDeRefType() const 
	{
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return VT_NULL;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.GetDeRefType();
		}
		return m_var.vt & ~VT_BYREF;
	}
	inline bool	IsArray() const {return (m_var.vt & VT_ARRAY)?true:false;}
	inline bool	IsRef() const {return (m_var.vt & VT_BYREF)?true:false;}
	inline bool	IsEmpty() const 
	{
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return true;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsEmpty();
		}
		return m_var.vt == VT_EMPTY;
	}
	inline bool	IsValid() const 
	{
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsValid();
		}
		return m_var.vt != VT_EMPTY;
	}
	inline bool	IsNull() const 
	{
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return true;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsNull();
		}
		int typ = m_var.vt;
		typ &= ~VT_BYREF;
		return typ == VT_EMPTY
			|| typ == VT_NULL || (m_var.vt == VT_DISPATCH && !m_var.pdispVal)
			|| (m_var.vt == VT_UNKNOWN && !m_var.punkVal)
			|| (m_var.vt == (VT_DISPATCH|VT_BYREF) && (!m_var.ppdispVal || !*m_var.ppdispVal))
			|| (m_var.vt == (VT_UNKNOWN|VT_BYREF) && (!m_var.ppunkVal || !*m_var.ppunkVal));
	}
	inline bool	IsString() const 
	{	
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsString();
		}
		int typ = m_var.vt;
		typ &= ~VT_BYREF;
		return typ == VT_BSTR;
	}
	inline bool	IsBool() const 
	{	
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsBool();
		}
		int typ = m_var.vt;
		typ &= ~VT_BYREF;
		return typ == VT_BOOL;
	}
	inline bool	IsNum() const 
	{	
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsNum();
		}
		int typ = m_var.vt;
		typ &= ~VT_BYREF;
		return typ == VT_UI1 || typ == VT_I1 || typ == VT_UI2 || typ == VT_I2 || typ == VT_UI4 || typ == VT_I4 
			|| typ == VT_I8 || typ == VT_CY || typ == VT_DECIMAL
			|| typ == VT_R4 || typ == VT_R8;
	}
	inline bool	IsInterface() const 
	{
		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsInterface();
		}
		int typ = m_var.vt;
		typ &= ~VT_BYREF;
		return typ == VT_UNKNOWN || typ == VT_DISPATCH;
	}
	inline bool	IsData() const 
	{
/*TODO		if (m_var.vt == (VT_VARIANT|VT_BYREF))
		{
			if (!m_var.pvarVal) return false;
			xbVariant var;
			var.AttachEx(*m_var.pvarVal);
			return var.IsData();
		}*/
		int typ = m_var.vt;
//		typ &= ~VT_BYREF;
		return typ == (VT_UI1|VT_ARRAY);
	}

	inline void Empty()
	{
		Clear();
	}

	long GetData(xbData *pData) const;
	void SetData(const xbData &Data)
	{
		SetData(Data,int(Data.Length));
	}
	void SetData(const void *pData,int cByteData);

	virtual void ReadFromStream(IxbStreamMode *pMode,IxbInputStream *pStream);
	virtual void WriteToStream(IxbStreamMode *pMode,IxbOutputStream *pStream) const;
protected:
	VARIANT	m_var;
	bool	m_bToFree;
	bool	m_bDeref;
	LCID	m_lcid;
};

class xbEXPORT xbComData
{
public:
	xbComData(ulong sz);
	xbComData()
	{
		m_pMem = NULL;
		m_sz = 0;
	}
	xbComData(const char *ptr)
	{
		m_pMem = NULL;
		m_sz = 0;
		SetString(ptr);
	}
	xbComData(const wchar *ptr)
	{
		m_pMem = NULL;
		m_sz = 0;
		SetString(ptr);
	}
	~xbComData();
	wchar	*Detach();
	xbComData	&Attach(wchar *ptr,ulong sz);
	operator wchar*();
	operator uchar*();
	ulong			SetLength(ulong sz);
	ulong			GetLength() const;
	bool			IsValid() const {return m_pMem != NULL;}
	bool			IsEmpty() const {return m_pMem == NULL;}
	xbComData		&SetString(const char *ptr);
	xbComData		&SetString(const wchar *ptr);
	xbString		GetString() const;
protected:
	wchar	*m_pMem;
	ulong	m_sz;
};

#endif
