/************************************************************************//**
 *	@file	ArrayVariant.h
 *
 *	CArrayVariantクラスヘッダ
 ***************************************************************************/
#pragma once
#include <vector>
#include <limits>
#include <cassert>

using namespace std;


/************************************************************************//**
 *	@class	CArrayVariant
 *
 *	VARIANT(SAFEARRAY(Type[])) 型 ラッパークラス。
 *	Type としてサポートしている型は、CHAR, UCHAR, SHORT, USHORT, LONG(INT),
 *	ULONG(UINT), FLOAT, DOUBLE。
 ***************************************************************************/
template <typename Type>
class CArrayVariant
{
	VARIANT m_var;

public:
	/************************************************************************//**
	 *	@brief	デフォルトコンストラクタ
	 *
	 ***************************************************************************/
	CArrayVariant(void)
	{
		::VariantInit(&m_var);
		V_ARRAY(&m_var) = NULL;
	}

	/************************************************************************//**
	 *	@brief	コンストラクタ
	 *
	 *	@param	[in]	pbuf	Type型配列へのポインタ
	 *	@param	[in]	size	配列の要素数
	 ***************************************************************************/
	CArrayVariant(const Type* pbuf, DWORD size)
	{
		int err = 0;
		SAFEARRAYBOUND bound;

		do {
			::VariantInit(&m_var);
			// エラーハンドリングのため、いきなりSetDataをせずにここでCreateする
			V_VT(&m_var) = VT_ARRAY | GetVarType();
			bound.cElements = size;
			bound.lLbound = 0;
			V_ARRAY(&m_var) = ::SafeArrayCreate(GetVarType(), 1, &bound);
			if (V_ARRAY(&m_var) == NULL) {
				err = 1;
				break;
			}
			if (SetData(pbuf, size) == FALSE) {
				err = 2;
				break;
			}
		} while (0);

		if (err) {
			if (err >= 2) {
				::SafeArrayDestroy(V_ARRAY(&m_var));
			}
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
	}

	/************************************************************************//**
	 *	@brief	コンストラクタ
	 *
	 *	@param	[in]	vec		Type型ベクタへの参照
	 ***************************************************************************/
	CArrayVariant(const vector<Type>& vec)
	{
		int err = 0;
		SAFEARRAYBOUND bound;

		do {
			::VariantInit(&m_var);
			// エラーハンドリングのため、いきなりSetDataをせずにここでCreateする
			V_VT(&m_var) = VT_ARRAY | GetVarType();
			bound.cElements = (ULONG)vec.size();
			bound.lLbound = 0;
			V_ARRAY(&m_var) = ::SafeArrayCreate(GetVarType(), 1, &bound);
			if (V_ARRAY(&m_var) == NULL) {
				err = 1;
				break;
			}
			if (SetData(vec) == FALSE) {
				err = 2;
				break;
			}
		} while (0);

		if (err) {
			if (err >= 2) {
				::SafeArrayDestroy(V_ARRAY(&m_var));
			}
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
	}

	/************************************************************************//**
	 *	@brief	コンストラクタ
	 *
	 *	@param	[in]	arg_var		VARIANT型オブジェクトへの参照
	 *
	 *	@attention	arg_varはType型配列のSAFEARRAYを入れたVARIANTでないとならない。
	 ***************************************************************************/
	CArrayVariant(const VARIANT& arg_var)
	{
		int err = 0;
		SAFEARRAYBOUND bound = {0};

		do {
			::VariantInit(&m_var);
			V_VT(&m_var) = VT_ARRAY | GetVarType();
			// エラーハンドリングのため、いきなりAssignをせずにここでCreateする
			// Assignの中でResizeするので、サイズ0のSAFEARRAYを確保
			V_ARRAY(&m_var) = ::SafeArrayCreate(GetVarType(), 1, &bound);
			if (V_ARRAY(&m_var) == NULL) {
				err = 1;
				break;
			}
			if (Assign(arg_var) == FALSE) {
				err = 2;
				break;
			}
		} while (0);

		if (err) {
			if (err >= 2) {
				::SafeArrayDestroy(V_ARRAY(&m_var));
			}
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
	}

	/************************************************************************//**
	 *	@brief	デストラクタ
	 *
	 ***************************************************************************/
	virtual ~CArrayVariant(void)
	{
		if (V_ARRAY(&m_var) != NULL) {
			if (FAILED(::SafeArrayDestroy(V_ARRAY(&m_var)))) {
				// error
				::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
			}
		}
	}


	/************************************************************************//**
	 *	@brief	SetData
	 *			Type型配列からの設定
	 *
	 *	@param	[in]	pbuf	Type型配列
	 *	@param	[in]	size	配列の要素数
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL SetData(const Type* pbuf, DWORD size)
	{
		BOOL ret = FALSE;
		Type *p;

		do {
			if (Resize(size) == FALSE) {
				break;
			}
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			for (UINT i=0; i<size; i++) {
				*p++ = *pbuf++;
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	SetData
	 *			Type型ベクタからの設定
	 *
	 *	@param	[in]	vec		Type型ベクタへの参照
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL SetData(const vector<Type>& vec)
	{
		BOOL ret = FALSE;
		Type *p;

		do {
			if (Resize((DWORD)vec.size()) == FALSE) {
				break;
			}
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			for (UINT i=0; i<vec.size(); i++) {
				*p++ = vec.at(i);
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	GetData
	 *			Type型配列の取得
	 *
	 *	@param	[out]	pbuf	Type型配列
	 *	@param	[in]	size	配列の要素数
	 *	@return	出力した要素数（エラーの場合は-1）
	 ***************************************************************************/
	LONG GetData(Type* pbuf, DWORD size)
	{
		LONG ret = -1;
		DWORD i, this_size = Size();
		Type *p;

		assert(V_ARRAY(&m_var) != NULL);
		do {
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			for (i=0; i<this_size && i<size; i++) {
				*pbuf++ = *p++;
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			ret = (LONG)i;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	GetData
	 *			Type型ベクタの取得
	 *
	 *	@param	[out]	pvec	Type型ベクタへのポインタ
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL GetData(vector<Type>* pvec)
	{
		BOOL ret = FALSE;
		ULONG this_size = Size();
		Type *p;

		assert(V_ARRAY(&m_var) != NULL);
		do {
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			pvec->clear();
			for (UINT i=0; i<this_size; i++) {
				pvec->push_back(*p++);
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	Assign
	 *			VARIANT型オブジェクトからの設定
	 *
	 *	@param	[in]	arg_var		VARIANT型オブジェクトへの参照
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 *	@attention	arg_varはType型配列のSAFEARRAYを入れたVARIANTでないとならない。
	 ***************************************************************************/
	BOOL Assign(const VARIANT& arg_var)
	{
		BOOL ret = FALSE;
		SAFEARRAY *arg_psa;
		VARTYPE arg_type;

		do {
			// vt フィールドチェック
			if ((V_VT(&arg_var) & (VT_ARRAY | GetVarType())) != (VT_ARRAY | GetVarType())) {
				break;
			}

			if (V_VT(&arg_var) & VT_BYREF) {
				// VB対応
				arg_psa = *V_ARRAYREF(&arg_var);
			} else {
				arg_psa = V_ARRAY(&arg_var);
			}
			if (arg_psa == NULL) {
				break;
			}

			// SAFEARRAY のタイプチェック
			if (FAILED(::SafeArrayGetVartype(arg_psa, &arg_type))) {
				break;
			}
			if (arg_type != GetVarType()) {
				break;
			}

			if (Resize(arg_psa->rgsabound->cElements) == FALSE) {
				break;
			}
			// データコピー arg_psa → V_ARRAY(&m_var)
			if (FAILED(::SafeArrayCopyData(arg_psa, V_ARRAY(&m_var)))) {
				break;
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	Resize
	 *			現在保持してる配列の要素数の変更
	 *
	 *	@param	[in]	size	要素数
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL Resize(DWORD size)
	{
		HRESULT redim_ret, unlock_ret, lock_ret = S_OK;
		SAFEARRAYBOUND bound;

		if (size == Size()) {
			return TRUE;
		}

		bound.cElements = size;
		bound.lLbound = 0;

		if (V_ARRAY(&m_var) == NULL) {
			// SAFEARRAY未確保
			V_VT(&m_var) = VT_ARRAY | GetVarType();
			V_ARRAY(&m_var) = ::SafeArrayCreate(GetVarType(), 1, &bound);
			if (V_ARRAY(&m_var) == NULL) {
				return FALSE;
			}
		}
		else {
			// Unlock しないと Redim が DISP_E_ARRAYISLOCKED（ロックされている）を返すが、
			// Unlock は E_UNEXPECTED（ロックされてない）を返す。(VC2005)
			unlock_ret = ::SafeArrayUnlock(V_ARRAY(&m_var));
			redim_ret = ::SafeArrayRedim(V_ARRAY(&m_var), &bound);
			if (SUCCEEDED(unlock_ret)) {
				// もし Unlock が S_OK を返した場合は、ロックしてあげる。
				lock_ret = ::SafeArrayLock(V_ARRAY(&m_var));
			}
			if (FAILED(redim_ret) || FAILED(lock_ret)) {
				return FALSE;
			}
		}
		return TRUE;
	}

	/************************************************************************//**
	 *	@brief	Size
	 *			現在保持してる配列の要素数の取得
	 *
	 *	@return	要素数
	 ***************************************************************************/
	DWORD Size(void)
	{
		DWORD ret;

		if (V_ARRAY(&m_var) == NULL) {
			ret = 0;
		} else {
			ret = (DWORD)V_ARRAY(&m_var)->rgsabound->cElements;
		}
		return ret;
	}

	/************************************************************************//**
	 *	@brief	GetVariantPtr
	 *			m_var へのポインタの取得
	 *
	 *	@return	m_var へのポインタ
	 ***************************************************************************/
	VARIANT* GetVariantPtr()
	{
		return &m_var;
	}

	/************************************************************************//**
	 *	@brief	GetVariantRef
	 *			m_var への参照の取得
	 *
	 *	@return	m_var への参照
	 ***************************************************************************/
	VARIANT& GetVariantRef()
	{
		return m_var;
	}

	/************************************************************************//**
	 *	@brief	Compare
	 *			配列データの比較
	 *
	 *	サイズ0のSAFEARRAYオブジェクトと、SAFEARRAYが未確保の場合は、同義としている。
	 *
	 *	@param	[in]	arg_var		CArrayVariant型オブジェクトへの参照
	 *	@retval	0		同じ
	 *	@retval	1		異なる
	 ***************************************************************************/
	int Compare(const CArrayVariant<Type>& arg_var)
	{
		BOOL differ = FALSE;
		CArrayVariant<Type>& arg_rvar = const_cast<CArrayVariant<Type>&>(arg_var);
		Type *p_this, *p_arg;

		// Type の相違がある場合にはビルドエラーになるはずなのでチェックしない
		if (Size() != arg_rvar.Size()) {
			return 1;
		}
		if (Size() == 0) {
			return 0;
		}

		if (FAILED(::SafeArrayAccessData(V_ARRAY(arg_rvar.GetVariantPtr()), (void**)&p_arg))
			|| FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p_this)))
		{
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		for (UINT i=0; i<Size(); i++) {
			if (*p_this++ != *p_arg++) {
				differ = TRUE;
				break;
			}
		}
		if (FAILED(::SafeArrayUnaccessData(V_ARRAY(arg_rvar.GetVariantPtr())))
			|| FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var))))
		{
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		return (int)differ;
	}

	/************************************************************************//**
	 *	@brief	CopyTo
	 *			指定されたVARIANT型オブジェクトにSAFEARRAYデータをコピーする
	 *
	 *	@param	[in]	arg_pvar	VARIANT型オブジェクトへのポインタ
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 *	@attention	arg_pvarは初期化済みVARIANT、またはType型配列のSAFEARRAYを入れた
	 *				VARIANTへのポインタでないとならない。
	 ***************************************************************************/
	BOOL CopyTo(VARIANT* arg_pvar)
	{
		BOOL ret = FALSE;
		SAFEARRAY *arg_psa;
		VARTYPE arg_type;
		HRESULT redim_ret, unlock_ret, lock_ret = S_OK;
		SAFEARRAYBOUND bound;

		assert(V_ARRAY(&m_var) != NULL);
		do {
			// vt フィールドチェック
			if (V_VT(arg_pvar) == 0) {
				// 初期化済み VARIANT（アウトプロセスサーバの[out]パラメータには、初期化済み VARIANT を渡される）
				bound.cElements = 0;	// 後で Resize する
				bound.lLbound = 0;
				arg_psa = ::SafeArrayCreate(GetVarType(), 1, &bound);
				if (arg_psa == NULL) {
					break;
				}
				V_VT(arg_pvar) = VT_ARRAY | GetVarType();
				V_ARRAY(arg_pvar) = arg_psa;
			}
			else if ((V_VT(arg_pvar) & (VT_ARRAY | GetVarType())) == (VT_ARRAY | GetVarType())) {
				// SAFEARRAY 付き
				if (V_VT(arg_pvar) & VT_BYREF) {
					// VB対応
					arg_psa = *V_ARRAYREF(arg_pvar);
				} else {
					arg_psa = V_ARRAY(arg_pvar);
				}
				if (arg_psa == NULL) {
					break;
				}

				// SAFEARRAY のタイプチェック
				if (FAILED(::SafeArrayGetVartype(arg_psa, &arg_type))) {
					break;
				}
				if (arg_type != GetVarType()) {
					break;
				}
			}
			else {
				// error
				break;
			}

			// コピー
			// SafeArrayCopy() でコピーするとメモリリークが起きる。(VC2005)
			// 使い方が間違ってるのかもしれないが。。
			// safearray resize
			bound.cElements = Size();
			bound.lLbound = 0;
			// Unlock しないと Redim が DISP_E_ARRAYISLOCKED（ロックされている）を返すが、
			// Unlock は E_UNEXPECTED（ロックされてない）を返す。(VC2005)
			unlock_ret = ::SafeArrayUnlock(arg_psa);
			redim_ret = ::SafeArrayRedim(arg_psa, &bound);
			if (SUCCEEDED(unlock_ret)) {
				// もし Unlock が S_OK を返した場合は、ロックしてあげる。
				lock_ret = ::SafeArrayLock(arg_psa);
			}
			if (FAILED(redim_ret) || FAILED(lock_ret)) {
				break;
			}
			// データコピー V_ARRAY(&m_var) → arg_psa
			if (FAILED(::SafeArrayCopyData(V_ARRAY(&m_var), arg_psa))) {
				break;
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	GetAt
	 *			指定されたインデックスの要素の値を返す
	 *
	 *	@param	[in]	pos		要素インデックス
	 *	@return	指定要素の値
	 ***************************************************************************/
	Type GetAt(LONG pos)
	{
		Type val, *p;
		int err = 0;

		assert(V_ARRAY(&m_var) != NULL && pos < (LONG)Size());
		do {
			// SafeArrayGetElement() を使うよりも速いらしい
			// http://msdn.microsoft.com/en-us/library/ms221620(v=VS.85).aspx
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				err = 1;
				break;
			}
			val = *(p + pos);
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				err = 2;
				break;
			}
		} while (0);

		if (err >= 1) {
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		return val;
	}

	/************************************************************************//**
	 *	@brief	SetAt
	 *			指定されたインデックスの要素に値を設定する
	 *
	 *	@param	[in]	pos		要素インデックス
	 *	@param	[in]	val		値
	 *	@return	なし
	 ***************************************************************************/
	void SetAt(LONG pos, Type val)
	{
		Type *p;
		int err = 0;

		assert(V_ARRAY(&m_var) != NULL && pos < (LONG)Size());
		do {
			// SafeArrayPutElement() を使うよりも速いらしい
			// http://msdn.microsoft.com/en-us/library/ms221620(v=VS.85).aspx
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				err = 1;
				break;
			}
			*(p + pos) = val;
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				err = 2;
				break;
			}
		} while (0);

		if (err >= 1) {
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		return;
	}

	/************************************************************************//**
	 *	@brief	Clear
	 *			現在保持してる配列を消去する
	 *
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL Clear()
	{
		return Resize(0);
	}

	/************************************************************************//**
	 *	@brief	Insert
	 *			Type型配列の挿入
	 *
	 *	@param	[in]	pos		挿入位置のインデックス（要素数(Size())が指定された
	 *							ときは最後尾に結合する)
	 *	@param	[in]	pbuf	Type型配列
	 *	@param	[in]	size	配列の要素数
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL Insert(LONG pos, const Type* pbuf, DWORD size)
	{
		BOOL ret = FALSE;
		Type *p, *tmp;
		DWORD tmpsize;

		assert((DWORD)pos <= Size());	// pos が負数でも assert する
		do {
			if ((DWORD)pos < Size()) {
				tmpsize = Size() - pos;
				tmp = (Type*)::CoTaskMemAlloc((SIZE_T)tmpsize);
				if (tmp == NULL) {
					break;
				}
			} else {
				// pos == Size()
				tmpsize = 0;
			}
			if (Resize(Size()+size) == FALSE) {	// V_ARRAY(&m_var) が NULL の場合、Resize で Create する
				break;
			}
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			// pos より後ろを tmp に退避
			for (UINT i=0; i<tmpsize; i++) {
				*(tmp+i) = *(p+pos+i);
			}
			// 入力データの書き込み
			for (UINT i=0; i<size; i++) {
				*(p+pos+i) = *(pbuf+i);
			}
			// 退避データの書き戻し
			for (UINT i=0; i<tmpsize; i++) {
				*(p+size+i) = *(tmp+i);
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			if (tmpsize) {
				::CoTaskMemFree(tmp);
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	Insert
	 *			Type型ベクタからの挿入
	 *
	 *	@param	[in]	pos		挿入位置のインデックス（要素数(Size())が指定された
	 *							ときは最後尾に結合する)
	 *	@param	[in]	vec		Type型ベクタへの参照
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL Insert(LONG pos, const vector<Type>& vec)
	{
		BOOL ret = FALSE;
		Type *p, *tmp;
		DWORD tmpsize, vecsize = (DWORD)vec.size();

		assert((DWORD)pos <= Size());	// pos が負数でも assert する
		do {
			if ((DWORD)pos < Size()) {
				tmpsize = Size() - pos;
				tmp = (Type*)::CoTaskMemAlloc((SIZE_T)tmpsize);
				if (tmp == NULL) {
					break;
				}
			} else {
				// pos == Size()
				tmpsize = 0;
			}
			if (Resize(Size()+vecsize) == FALSE) {	// V_ARRAY(&m_var) が NULL の場合、Resize で Create する
				break;
			}
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				break;
			}
			// pos より後ろを tmp に退避
			for (UINT i=0; i<tmpsize; i++) {
				*(tmp+i) = *(p+pos+i);
			}
			// 入力データの書き込み
			for (UINT i=0; i<vecsize; i++) {
				*(p+pos+i) = vec.at(i);
			}
			// 退避データの書き戻し
			for (UINT i=0; i<tmpsize; i++) {
				*(p+vecsize+i) = *(tmp+i);
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				break;
			}
			if (tmpsize) {
				::CoTaskMemFree(tmp);
			}
			ret = TRUE;
		} while (0);

		return ret;
	}

	/************************************************************************//**
	 *	@brief	Erase
	 *			指定要素の削除
	 *
	 *	@param	[in]	pos		消去開始位置のインデックス
	 *	@param	[in]	size	消去する要素数
	 *	@retval	TRUE	成功
	 *	@retval	FALSE	失敗
	 ***************************************************************************/
	BOOL Erase(LONG pos, DWORD size = 1)
	{
		BOOL ret = FALSE;
		int err = 0;
		Type *p, *tmp = NULL;
		DWORD tmpsize;

		assert((DWORD)pos<Size() && (DWORD)pos+size<=Size() && size>0);
		do {
			tmpsize = Size() - (pos + size);
			if (tmpsize != 0) {
				tmp = (Type*)::CoTaskMemAlloc((SIZE_T)tmpsize);
				if (tmp == NULL) {
					err = 1;
					break;
				}
			}
			if (FAILED(::SafeArrayAccessData(V_ARRAY(&m_var), (void**)&p))) {
				err = 2;
				break;
			}
			// (pos + size) より後ろを tmp に退避
			for (UINT i=0; i<tmpsize; i++) {
				*(tmp+i) = *(p+pos+size+i);
			}
			// Resize
			if (Resize(Size()-size) == FALSE) {
				err = 3;
				break;
			}
			// 退避データの書き戻し
			for (UINT i=0; i<tmpsize; i++) {
				*(p+pos+i) = *(tmp+i);
			}
			if (FAILED(::SafeArrayUnaccessData(V_ARRAY(&m_var)))) {
				err = 4;
				break;
			}
			if (tmpsize) {
				::CoTaskMemFree(tmp);
			}
			ret = TRUE;
		} while (0);

		if (err >= 2) {
			if (tmp != NULL) ::CoTaskMemFree(tmp);
		}
		if (err >= 3) {
			::SafeArrayUnaccessData(V_ARRAY(&m_var));
		}

		return ret;
	}


	/************************************************************************//**
	 *	@brief	operator =
	 *			= 演算子のオーバーロード（CArrayVariant = CArrayVariant;）
	 *
	 *	@param	[in]	var		CArrayVariant型オブジェクトへの参照
	 *	@return	*this
	 ***************************************************************************/
	CArrayVariant<Type>& operator =(const CArrayVariant<Type>& arg_var)
	{
		VARIANT &arg_rvar = (const_cast<CArrayVariant<Type>&>(arg_var)).GetVariantRef();

		do {
			if (V_ARRAY(&arg_rvar) == NULL) {
				// 引数のVARIANTのSAFEARRAYが未確保の場合、
				// このインスタンスのSAFEARRAYも破棄する
				if (V_ARRAY(&m_var) != NULL) {
					if (FAILED(::SafeArrayDestroy(V_ARRAY(&m_var)))) {
						::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
					}
					V_ARRAY(&m_var) = NULL;
					V_VT(&m_var) = V_VT(&arg_rvar);
				}
				break;
			}
			if (Assign(arg_rvar) == FALSE) {
				::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
			}
		} while (0);

		return *this;
	}

	/************************************************************************//**
	 *	@brief	operator =
	 *			= 演算子のオーバーロード（CArrayVariant = vector;）
	 *
	 *	@param	[in]	var		Type型ベクタへの参照
	 *	@return	*this
	 ***************************************************************************/
	CArrayVariant<Type>& operator =(const vector<Type>& vec)
	{
		if (SetData(vec) == FALSE) {
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		return *this;
	}

	/************************************************************************//**
	 *	@brief	operator vector<Type>
	 *			vector<Type>型への変換演算子（vector = CArrayVariant;）
	 *
	 *	@return	Type型ベクタ
	 ***************************************************************************/
	operator vector<Type>()
	{
		vector<Type> vec;
		if (GetData(&vec) == FALSE) {
			::RaiseException(0x100000, EXCEPTION_NONCONTINUABLE, NULL, NULL);
		}
		return vec;
	}

	/************************************************************************//**
	 *	@brief	operator ==
	 *			== 演算子のオーバーロード（比較）
	 *
	 *	@param	[in]	var		CArrayVariant型オブジェクトへの参照
	 *	@retval	TRUE	同じ
	 *	@retval	FALSE	異なる
	 ***************************************************************************/
	BOOL operator ==(const CArrayVariant<Type>& var)
	{
		if (Compare(var) == 0) {
			return TRUE;
		} else {
			return FALSE;
		}
	}

	/************************************************************************//**
	 *	@brief	operator !=
	 *			!= 演算子のオーバーロード（比較）
	 *
	 *	@param	[in]	var		CArrayVariant型オブジェクトへの参照
	 *	@retval	TRUE	異なる
	 *	@retval	FALSE	同じ
	 ***************************************************************************/
	BOOL operator !=(const CArrayVariant<Type>& var)
	{
		if (Compare(var) != 0) {
			return TRUE;
		} else {
			return FALSE;
		}
	}


private:
	/************************************************************************//**
	 *	@brief	GetVarType
	 *			Type型の判定関数
	 *
	 *	@return	enum VARENUM 値
	 ***************************************************************************/
	USHORT GetVarType()
	{
		USHORT type = 0;
		if ((numeric_limits<Type>::max)() == CHAR_MAX) {
			type = VT_I1;
		} else if ((numeric_limits<Type>::max)() == UCHAR_MAX) {
			type = VT_UI1;
		} else if ((numeric_limits<Type>::max)() == SHRT_MAX) {
			type = VT_I2;
		} else if ((numeric_limits<Type>::max)() == USHRT_MAX) {
			type = VT_UI2;
		} else if ((numeric_limits<Type>::max)() == LONG_MAX) {
			type = VT_I4;
		} else if ((numeric_limits<Type>::max)() == ULONG_MAX) {
			type = VT_UI4;
		} else if ((numeric_limits<Type>::max)() == FLT_MAX) {
			type = VT_R4;
		} else if ((numeric_limits<Type>::max)() == DBL_MAX) {
			type = VT_R8;
		} else {
			assert(0);
		}
		return type;
	}

};
