BSTR VARIANT SAFEARRAY

VBScript ではIDispatchインタフェースを使ってCOMサーバを呼出します。 受け渡すパラメータは、VARIANT互換のタイプを使います。
ここではわかりにくいBSTR VARIANT SAFEARRAYを親切に説明。

BSTRの使い方

BSTRは、クライアントとCOMサーバで文字列のやり取りに使います。
ヘッダファイルの定義は、
typedef OLECHAR *BSTR
typedef WCHAR OLECHAR;
typedef unsigned short WCHAR;
となっています。ようするにWCHAR(unsigned short)のポインタです。最初に文字列の長さが入ります。 次のように文字列でパラメータを受取りたいときに使います。 下の例では、UNICODEをASCII に変換しています。
STDMETHODIMP CBasp21::SendMail(BSTR server, BSTR to, BSTR from, BSTR subj, BSTR body, BSTR file, BSTR * pVal)
{
	USES_CONVERSION;
	LPCSTR szServer = OLE2T(server);
	LPCSTR szTo = OLE2T(to);
	LPCSTR szFrom = OLE2T(from);
	LPCSTR szSubject = OLE2T(subj);
//	LPCSTR szBody = OLE2T(body);   // スタック オーバフロー防止
	int bodylen = (lstrlenW(body)+1)*2;
	char *szBody = 
		ATLW2AHELPER((LPSTR) new char[bodylen], body, bodylen);

	LPCSTR szFile = OLE2T(file);

VARIANTの使い方

VARIANTは、クライアントとCOMサーバで文字列、数字、配列などのやり取りに使います。
VARIANTは、さまざまなデータを扱うことができます。 下の例は、sprintfメソッドの実装です。
STDMETHODIMP CBasp21::sprintf(BSTR format, VARIANT args, BSTR * pVal)
{
	USES_CONVERSION;
	LPSTR szFormat = OLE2T(format);
	int len = strlen(szFormat);
	if (len == 0) {
		*pVal = A2BSTR("");
		return S_OK;
	}

	char tp[4096];
	tp[0] = 0;

	VARIANT var = args;
	VARTYPE vt = V_VT(&var);
	// check VARIANT REFERENCE	
	if (vt == (VT_VARIANT | VT_BYREF)) {
		var = *args.pvarVal;
		vt = V_VT(&var);
	}

	try {

	int bArray = vt & VT_ARRAY;
	if (!bArray) {  // not array
		while(1) {
			if (vt == VT_I2) {
				::sprintf(tp,szFormat,var.iVal);
				break;
			}
			if (vt == (VT_I2 | VT_BYREF)) {
				::sprintf(tp,szFormat,*var.piVal);
				break;
			}
			if (vt == VT_I4) {
				::sprintf(tp,szFormat,var.lVal);
				break;
			}
			if (vt == (VT_I4 | VT_BYREF)) {
				::sprintf(tp,szFormat,*var.plVal);
				break;
			}
			if (vt == VT_R4) {
				::sprintf(tp,szFormat,var.fltVal);
				break;
			}
			if (vt == (VT_R4 | VT_BYREF)) {
				::sprintf(tp,szFormat,*var.pfltVal);
				break;
			}
			if (vt == VT_R8) {
				::sprintf(tp,szFormat,var.dblVal);
				break;
			}
			if (vt == (VT_R8 | VT_BYREF)) {
				::sprintf(tp,szFormat,*var.pdblVal);
				break;
			}
			if (vt == VT_BSTR) {
				::sprintf(tp,szFormat,OLE2T(var.bstrVal));
				break;
			}
			if (vt == (VT_BSTR | VT_BYREF)) {
				::sprintf(tp,szFormat,OLE2T(*var.pbstrVal));
				break;
			}
			return E_FAIL;
		}
		*pVal = A2BSTR(tp);
		return S_OK;
	}
	// array 
	return E_FAIL;


	}
	catch (...) {
		
		try {
			if (vt == VT_BSTR) {
				long num = ::atol(OLE2T(var.bstrVal));
				::sprintf(tp,szFormat,num);
				return S_OK;
			}
			if (vt == (VT_BSTR | VT_BYREF)) {
				long num = ::atol(OLE2T(*var.pbstrVal));
				::sprintf(tp,szFormat,num);
				return S_OK;
			}
		}
		catch (...) {
			return E_FAIL;
		}
		return E_FAIL;
	}

	return S_OK;
}

SAFEARRAYの使い方

SAFEARRAYは、クライアントとCOMサーバで配列のやり取りに使います。
SAFEARRAYは、VARIANTの中のVT_ARRAYタイプとして 使います。 下の例は、SAFEARRAYを使ったReadDirメソッドの実装です。
STDMETHODIMP CBasp21::ReadDir(BSTR dirname, VARIANT * pvaVariant)
{

	
	USES_CONVERSION;
	LPSTR name = OLE2T(dirname);

	int j;
	SAFEARRAYBOUND sabound[1];  
    SAFEARRAY * psa = NULL;
    BSTR bstr = NULL;     
    HRESULT hr;

	VARIANT vtemp;
	VariantInit(&vtemp);
	V_VT(&vtemp) = VT_BSTR;
    
	hr = VariantClear(pvaVariant);
	if (FAILED(hr))
		return hr;

	CReadDir fdata;	// WIN32_FIND_DATA wrrapper class
    BArray sortArray;
	//ディレクトリの中のファイルの数だけ繰り返す
	BOOL more = fdata.First(name);
	while (more) {
		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED ||
				fdata.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ||
				fdata.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY ||
				fdata.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) {
			more = fdata.Next();
			continue;
		}
		
		if (fdata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
			if (*(fdata.cFileName) != '.') {
				sortArray.Add(fdata.cFileName);
			}
		}
		else 
			sortArray.Add(fdata.cFileName);
		more = fdata.Next();
	}
	int nElem = sortArray.GetSize();
	char **pdata = sortArray.GetAddr();
	// call sort using ascii
	QuickSort(pdata, nElem,0,0,0);

    V_VT(pvaVariant) = VT_ARRAY | VT_VARIANT;
    sabound[0].cElements = nElem ;
	sabound[0].lLbound = 0;    
	psa = SafeArrayCreate(VT_VARIANT, 1, sabound);
    if (psa == NULL)
	    return ResultFromScode(E_OUTOFMEMORY);
	LPVARIANT rgElems;
	hr= SafeArrayAccessData(psa,(LPVOID*)&rgElems);
	if (FAILED(hr))
		goto error;
	// copy data to safearray
	for (j = 0;j < nElem;j++) {
		V_BSTR(&vtemp) = A2BSTR(pdata[j]);
		rgElems[j] = vtemp;

	}
	// if we do not issue below, 2nd call fails. 
    SafeArrayUnaccessData(psa);	// unlock  array

	V_ARRAY(pvaVariant) = psa;    

	return S_OK;

error:
    if (psa) SafeArrayDestroy(psa);
    return hr;
}



文書のご使用上の注意

●この文書を元にプログラムを作成して発生した損害に関しては、一切の責任を負いません。
●もし誤りがありましたら気軽にお知らせください。

Home


Copyright 1997 Tatsuo Baba,All rights reserved.