예제 #1
0
//------------------------------------------------------------------------//
BOOL CBCGPGlobalUtils::DecimalFromString(DECIMAL& decimal, LPCTSTR psz)
{
	USES_CONVERSION;

	if (psz == NULL || _tcslen (psz) == 0)
	{
		psz = _T("0");
	}

	VARIANTARG varBstr;
	VARIANTARG varDecimal;
	AfxVariantInit(&varBstr);
	AfxVariantInit(&varDecimal);
	V_VT(&varBstr) = VT_BSTR;
	V_BSTR(&varBstr) = SysAllocString(T2COLE(psz));
	if (FAILED(VariantChangeType(&varDecimal, &varBstr, 0, VT_DECIMAL)))
	{
		VariantClear(&varBstr);
		VariantClear(&varDecimal);
		return FALSE;
	}
	decimal = V_DECIMAL(&varDecimal);
	VariantClear(&varBstr);
	VariantClear(&varDecimal);
	return TRUE;
}
예제 #2
0
//------------------------------------------------------------------------//
BOOL CBCGPGlobalUtils::StringFromDecimal(CString& str, DECIMAL& decimal)
{
	VARIANTARG varDecimal;
	VARIANTARG varBstr;
	AfxVariantInit(&varDecimal);
	AfxVariantInit(&varBstr);
	V_VT(&varDecimal) = VT_DECIMAL;
	V_DECIMAL(&varDecimal) = decimal;
	if (FAILED(VariantChangeType(&varBstr, &varDecimal, 0, VT_BSTR)))
	{
		VariantClear(&varDecimal);
		VariantClear(&varBstr);
		return FALSE;
	}
	str = V_BSTR(&varBstr);
	VariantClear(&varDecimal);
	VariantClear(&varBstr);
	return TRUE;
}
예제 #3
0
void EventProxy::convertJavaVariant(VARIANT *java, VARIANT *com) {

	  switch (com->vt)
	  {	  
		case VT_DISPATCH:
		{
			switch (java->vt)
			{
				case VT_DISPATCH:
				{
					V_DISPATCH(com) = V_DISPATCH(java);
					break;
				}

				case VT_DISPATCH | VT_BYREF:
				{
					V_DISPATCH(com) = *V_DISPATCHREF(java);
					break;
				}
			}
			break;
		}

		case VT_DISPATCH | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_DISPATCH:
				{
					*V_DISPATCHREF(com) = V_DISPATCH(java);
					break;
				}

				case VT_DISPATCH | VT_BYREF:
				{
					*V_DISPATCHREF(com) = *V_DISPATCHREF(java);
					break;
				}
			}
			break;
		}

		case VT_BOOL:
		{
			switch (java->vt)
			{
				case VT_BOOL:
				{
					V_BOOL(com) = V_BOOL(java);
					break;
				}

				case VT_BOOL | VT_BYREF:
				{
					V_BOOL(com) = *V_BOOLREF(java);
					break;
				}
			}
			break;
		}

		case VT_BOOL | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_BOOL:
				{
					*V_BOOLREF(com) = V_BOOL(java);
					break;
				}

				case VT_BOOL | VT_BYREF:
				{
					*V_BOOLREF(com) = *V_BOOLREF(java);
					break;
				}
			}
			break;
		}

		case VT_UI1:
		{
			switch (java->vt)
			{
				case VT_UI1:
				{
					V_UI1(com) = V_UI1(java);
					break;
				}

				case VT_UI1 | VT_BYREF:
				{
					V_UI1(com) = *V_UI1REF(java);
					break;
				}
			}
			break;
		}

		case VT_UI1 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_UI1:
				{
					*V_UI1REF(com) = V_UI1(java);
					break;
				}

				case VT_UI1 | VT_BYREF:
				{
					*V_UI1REF(com) = *V_UI1REF(java);
					break;
				}
			}
			break;
		}


		case VT_I2:
		{
			switch (java->vt)
			{
				case VT_I2:
				{
					V_I2(com) = V_I2(java);
					break;
				}

				case VT_I2 | VT_BYREF:
				{
					V_I2(com) = *V_I2REF(java);
					break;
				}
			}
			break;
		}

		case VT_I2 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_I2:
				{
					*V_I2REF(com) = V_I2(java);
					break;
				}

				case VT_I2 | VT_BYREF:
				{
					*V_I2REF(com) = *V_I2REF(java);
					break;
				}
			}
			break;
		}

		case VT_I4:
		{
			switch (java->vt)
			{
				case VT_I4:
				{
					V_I4(com) = V_I4(java);
					break;
				}

				case VT_I4 | VT_BYREF:
				{
					V_I4(com) = *V_I4REF(java);
					break;
				}
			}
			break;
		}

		case VT_I4 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_I4:
				{
					*V_I4REF(com) = V_I4(java);
					break;
				}

				case VT_I4 | VT_BYREF:
				{
					*V_I4REF(com) = *V_I4REF(java);
					break;
				}
			}
			break;
		}

		case VT_R4:
		{
			switch (java->vt)
			{
				case VT_R4:
				{
					V_R4(com) = V_R4(java);
					break;
				}

				case VT_R4 | VT_BYREF:
				{
					V_R4(com) = *V_R4REF(java);
					break;
				}
			}
			break;
		}

		case VT_R4 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_R4:
				{
					*V_R4REF(com) = V_R4(java);
					break;
				}

				case VT_R4 | VT_BYREF:
				{
					*V_R4REF(com) = *V_R4REF(java);
					break;
				}
			}
			break;
		}

		case VT_R8:
		{
			switch (java->vt)
			{
				case VT_R8:
				{
					V_R8(com) = V_R8(java);
					break;
				}

				case VT_R8 | VT_BYREF:
				{
					V_R8(com) = *V_R8REF(java);
					break;
				}
			}
			break;
		}

		case VT_R8 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_R8:
				{
					*V_R8REF(com) = V_R8(java);
					break;
				}

				case VT_R8 | VT_BYREF:
				{
					*V_R8REF(com) = *V_R8REF(java);
					break;
				}
			}
			break;
		}

				case VT_I1:
		{
			switch (java->vt)
			{
				case VT_I1:
				{
					V_I1(com) = V_I1(java);
					break;
				}

				case VT_I1 | VT_BYREF:
				{
					V_I1(com) = *V_I1REF(java);
					break;
				}
			}
			break;
		}

		case VT_I1 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_I1:
				{
					*V_I1REF(com) = V_I1(java);
					break;
				}

				case VT_I1 | VT_BYREF:
				{
					*V_I1REF(com) = *V_I1REF(java);
					break;
				}
			}
			break;
		}

				case VT_UI2:
		{
			switch (java->vt)
			{
				case VT_UI2:
				{
					V_UI2(com) = V_UI2(java);
					break;
				}

				case VT_UI2 | VT_BYREF:
				{
					V_UI2(com) = *V_UI2REF(java);
					break;
				}
			}
			break;
		}

		case VT_UI2 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_UI2:
				{
					*V_UI2REF(com) = V_UI2(java);
					break;
				}

				case VT_UI2 | VT_BYREF:
				{
					*V_UI2REF(com) = *V_UI2REF(java);
					break;
				}
			}
			break;
		}

				case VT_UI4:
		{
			switch (java->vt)
			{
				case VT_UI4:
				{
					V_UI4(com) = V_UI4(java);
					break;
				}

				case VT_UI4 | VT_BYREF:
				{
					V_UI4(com) = *V_UI4REF(java);
					break;
				}
			}
			break;
		}

		case VT_UI4 | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_UI4:
				{
					*V_UI4REF(com) = V_UI4(java);
					break;
				}

				case VT_UI4 | VT_BYREF:
				{
					*V_UI4REF(com) = *V_UI4REF(java);
					break;
				}
			}
			break;
		}

				case VT_INT:
		{
			switch (java->vt)
			{
				case VT_INT:
				{
					V_INT(com) = V_INT(java);
					break;
				}

				case VT_INT | VT_BYREF:
				{
					V_INT(com) = *V_INTREF(java);
					break;
				}
			}
			break;
		}

		case VT_INT | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_INT:
				{
					*V_INTREF(com) = V_INT(java);
					break;
				}

				case VT_INT | VT_BYREF:
				{
					*V_INTREF(com) = *V_INTREF(java);
					break;
				}
			}
			break;
		}

				case VT_UINT:
		{
			switch (java->vt)
			{
				case VT_UINT:
				{
					V_UINT(com) = V_UINT(java);
					break;
				}

				case VT_UINT | VT_BYREF:
				{
					V_UINT(com) = *V_UINTREF(java);
					break;
				}
			}
			break;
		}

		case VT_UINT | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_UINT:
				{
					*V_UINTREF(com) = V_UINT(java);
					break;
				}

				case VT_UINT | VT_BYREF:
				{
					*V_UINTREF(com) = *V_UINTREF(java);
					break;
				}
			}
			break;
		}

				case VT_CY:
		{
			switch (java->vt)
			{
				case VT_CY:
				{
					V_CY(com) = V_CY(java);
					break;
				}

				case VT_CY | VT_BYREF:
				{
					V_CY(com) = *V_CYREF(java);
					break;
				}
			}
			break;
		}

		case VT_CY | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_CY:
				{
					*V_CYREF(com) = V_CY(java);
					break;
				}

				case VT_CY | VT_BYREF:
				{
					*V_CYREF(com) = *V_CYREF(java);
					break;
				}
			}
			break;
		}

				case VT_DATE:
		{
			switch (java->vt)
			{
				case VT_DATE:
				{
					V_DATE(com) = V_DATE(java);
					break;
				}

				case VT_DATE | VT_BYREF:
				{
					V_DATE(com) = *V_DATEREF(java);
					break;
				}
			}
			break;
		}

		case VT_DATE | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_DATE:
				{
					*V_DATEREF(com) = V_DATE(java);
					break;
				}

				case VT_DATE | VT_BYREF:
				{
					*V_DATEREF(com) = *V_DATEREF(java);
					break;
				}
			}
			break;
		}

				case VT_BSTR:
		{
			switch (java->vt)
			{
				case VT_BSTR:
				{
					V_BSTR(com) = V_BSTR(java);
					break;
				}

				case VT_BSTR | VT_BYREF:
				{
					V_BSTR(com) = *V_BSTRREF(java);
					break;
				}
			}
			break;
		}

		case VT_BSTR | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_BSTR:
				{
					*V_BSTRREF(com) = V_BSTR(java);
					break;
				}

				case VT_BSTR | VT_BYREF:
				{
					*V_BSTRREF(com) = *V_BSTRREF(java);
					break;
				}
			}
			break;
		}

				case VT_DECIMAL:
		{
			switch (java->vt)
			{
				case VT_DECIMAL:
				{
					V_DECIMAL(com) = V_DECIMAL(java);
					break;
				}

				case VT_DECIMAL | VT_BYREF:
				{
					V_DECIMAL(com) = *V_DECIMALREF(java);
					break;
				}
			}
			break;
		}

		case VT_DECIMAL | VT_BYREF:
		{
			switch (java->vt)
			{
				case VT_DECIMAL:
				{
					*V_DECIMALREF(com) = V_DECIMAL(java);
					break;
				}

				case VT_DECIMAL | VT_BYREF:
				{
					*V_DECIMALREF(com) = *V_DECIMALREF(java);
					break;
				}
			}
			break;
		}


    }
}
HRESULT CContextPlugin::WriteContextInformation( HANDLE hFile, IWMSContext *pContext )
{
    HRESULT hr = S_OK;
    ContextNameHint *pContextHintValues = NULL;
    DWORD nValue = 0;
    WMS_CONTEXT_TYPE wmsContextType = WMS_UNKNOWN_CONTEXT_TYPE;
    WCHAR wstrBuffer[MAX_PATH];
    DWORD cbWritten = 0;
    DWORD dwRet = 0;


    if( NULL == pContext )
    {
        // There is no Context, nothing to write
        return( hr );
    }

    hr = pContext->GetContextType( &wmsContextType );

    if( FAILED( hr ) )
    {
        return( hr );
    }

    ZeroMemory( wstrBuffer, MAX_PATH * sizeof( WCHAR ) );

    switch( wmsContextType )
    {
        case WMS_USER_CONTEXT_TYPE:
            // Create a header for this context type
            wcsncpy_s( wstrBuffer,MAX_PATH, CONTEXT_SAMPLE_USER_CONTEXT_HEADER, MAX_PATH );
            pContextHintValues = const_cast<ContextNameHint *>(CContextPlugin::s_UserContextHintValues);
            break;
        case WMS_PRESENTATION_CONTEXT_TYPE:
            // Create a header for this context type
            wcsncpy_s( wstrBuffer, MAX_PATH,CONTEXT_SAMPLE_PRESENTATION_CONTEXT_HEADER, MAX_PATH );
            pContextHintValues = const_cast<ContextNameHint *>(CContextPlugin::s_PresentationContextHintValues);
            break;
        case WMS_COMMAND_REQUEST_CONTEXT_TYPE:
            // Create a header for this context type
            wcsncpy_s( wstrBuffer,MAX_PATH, CONTEXT_SAMPLE_COMMAND_REQUEST_CONTEXT_HEADER, MAX_PATH );
            pContextHintValues = const_cast<ContextNameHint *>(CContextPlugin::s_CommandContextHintValues);
            break;
        case WMS_COMMAND_RESPONSE_CONTEXT_TYPE:
            // Create a header for this context type
            wcsncpy_s( wstrBuffer,MAX_PATH, CONTEXT_SAMPLE_COMMAND_RESPONSE_CONTEXT_HEADER, MAX_PATH );
            pContextHintValues = const_cast<ContextNameHint *>(CContextPlugin::s_CommandContextHintValues);
            break;
    }

    if( !::WriteFile( hFile, (LPVOID) wstrBuffer, DWORD(wcslen( wstrBuffer ) * sizeof( WCHAR )), &cbWritten, NULL ) )
    {
        dwRet = GetLastError();
        hr = HRESULT_FROM_WIN32( dwRet );
        // Failed to write the header should we still continue
        // No!
        return( hr );
    }

    if( NULL == pContextHintValues )
    {
        return( E_UNEXPECTED );
    }

    // Now we loop until -1 and Write the data
    while( ( NULL != pContextHintValues[nValue].wstrContextName ) && ( -1 != pContextHintValues[nValue].lContextHint ) )
    {
        VARIANT varValue;
        VariantInit( &varValue );
        ZeroMemory( wstrBuffer, MAX_PATH * sizeof( WCHAR ) );

        hr = pContext->GetValue( pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, &varValue, 0 );

        if( SUCCEEDED( hr ) )
        {
            // Write string with data information
            switch( V_VT( &varValue ) )
            {
                case VT_BSTR:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_BSTR_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_BSTR( &varValue ) );
                    break;
                case VT_I4:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_I4_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_I4( &varValue ), V_I4( &varValue ) );
                    break;
                case VT_UI8:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_UI8_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_UI8( &varValue ) );
                    break;
                case VT_CY:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_CY_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_CY( &varValue ) );
                    break;
                case VT_DATE:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_DATE_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_DATE( &varValue ) );
                    break;
                case VT_DECIMAL:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_DECIMAL_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_DECIMAL( &varValue ) );
                    break;
                case VT_UNKNOWN:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_UNKNOWN_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_UNKNOWN( &varValue ) );
                    break;
                case VT_DISPATCH:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_DISPATCH_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_DISPATCH( &varValue ) );
                    break;
                default:
                    _snwprintf_s( wstrBuffer,MAX_PATH, MAX_PATH, CONTEXT_SAMPLE_ARRAY_TYPE_STRING, pContextHintValues[nValue].wstrContextName, pContextHintValues[nValue].lContextHint, V_ARRAY( &varValue ) );
                    break;
            }

            if( !::WriteFile( hFile, (LPVOID) wstrBuffer, DWORD(wcslen( wstrBuffer ) * sizeof( WCHAR )), &cbWritten, NULL ) )
            {
                dwRet = GetLastError();
                hr = HRESULT_FROM_WIN32( dwRet );
            }
        }
        else
        {
            // Value probably didn't exist for this event, don't worry about it
            // good place to put breakpoint
            hr = S_OK;
        }

        // It doesn't hurt to do a VariantClear on an Empty Variant, this way we won't leak anything.
        VariantClear( &varValue );

        nValue ++;
    }

    return( hr );
}
HRESULT CTCPropBagOnRegKey::_WriteSafeArray(CRegKey& key,
  const _bstr_t& strPropName, VARIANT* pVar)
{
  ASSERT(V_ISARRAY(pVar));
  ASSERT(lstrlen(strPropName));

  // Get the SAFEARRAY pointer from the variant
  SAFEARRAY* psa = V_ARRAY(pVar);
  if (IsBadReadPtr(psa))
    return E_POINTER;

  // Only support 1-dimensional arrays (currently)
  if (1 != SafeArrayGetDim(psa))
    return E_INVALIDARG;

  // Get the element size of the safe array
  UINT cbElement = SafeArrayGetElemsize(psa);

  // Get the safe array type from the variant
  VARTYPE vt = V_VT(pVar) & ~VT_ARRAY;

  // Check for supported types and validate the element size
  switch (vt)
  {
    case VT_BOOL:
      if (sizeof(V_BOOL(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_I1:
      if (sizeof(V_I1(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_I2:
      if (sizeof(V_I2(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_I4:
      if (sizeof(V_I4(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_UI1:
      if (sizeof(V_UI1(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_UI2:
      if (sizeof(V_UI2(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_UI4:
      if (sizeof(V_UI4(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_ERROR:
      if (sizeof(V_ERROR(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_R4:
      if (sizeof(V_R4(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_R8:
      if (sizeof(V_R8(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_DECIMAL:
      if (sizeof(V_DECIMAL(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_CY:
      if (sizeof(V_CY(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_DATE:
      if (sizeof(V_DATE(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_BSTR:
      if (sizeof(V_BSTR(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_UNKNOWN:
      if (sizeof(V_UNKNOWN(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_DISPATCH:
      if (sizeof(V_DISPATCH(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    case VT_VARIANT:
      if (sizeof(V_VARIANTREF(pVar)) != cbElement)
        return E_UNEXPECTED;
      break;
    default:
      return E_UNEXPECTED;
  }

  // Get the upper and lower bounds of the safe array
  HRESULT hr;
  LONG lUBound = 0, lLBound = 0;
  if (FAILED(hr = SafeArrayGetUBound(psa, 1, &lUBound)))
    return hr;
  if (FAILED(hr = SafeArrayGetLBound(psa, 1, &lLBound)))
    return hr;
  UINT nElements = lUBound - lLBound + 1;

  // Create a subkey with the specified name
  key.DeleteValue(strPropName);
  key.RecurseDeleteKey(strPropName);
  CRegKey subkey;
  if (!subkey.Open(key, strPropName))
    return HRESULT_FROM_WIN32(GetLastError());

  // Get access to the safe array data
  BYTE* pElement = NULL;
  if (FAILED(hr = SafeArrayAccessData(psa, (void**)&pElement)))
    return hr;

  // Write the variant type value
  subkey.WriteDWord(m_szVariantType, DWORD(V_VT(pVar)));

  // Write the element count value
  subkey.WriteDWord(m_szElementCount, DWORD(nElements));

  // Write the lower bound value, if not 0
  if (lLBound)
    subkey.WriteDWord(m_szLowerBound, DWORD(lLBound));

  // Special handling for arrays of variants 
  _bstr_t strText;
  if (VT_VARIANT == vt)
  {
    // Write each variant array element to the registry
    for (UINT i = 0; i < nElements; i++, pElement += cbElement)
    {
      // Format the value name
      strText.Format(m_szElementFmt, i);

      // Write the variant array element to the registry subkey
      if (FAILED(hr = WriteVariant(subkey, strText, (VARIANT*)pElement)))
      {
        TRACE1("CTCPropBagOnRegKey::_WriteSafeArray(\"%s\", pVar): ",
          strPropName);
        TRACE2("WriteVariant(subkey, \"%s\", &var) returned 0x%08X\n",
          strText, hr);
      }
    }
  }
  else
  {
    // Write each array element to the registry
    VARIANT var;
    V_VT(&var) = vt;
    for (UINT i = 0; i < nElements; i++, pElement += cbElement)
    {
      // Copy the array element to the data portion of the VARIANT
      memcpy(&V_NONE(&var), pElement, cbElement);

      // Format the value name
      strText.Format(m_szElementFmt, i);

      // Write the variant to the registry subkey
      if (FAILED(hr = WriteVariant(subkey, strText, &var)))
      {
        TRACE1("CTCPropBagOnRegKey::_WriteSafeArray(\"%s\", pVar): ",
          strPropName);
        TRACE2("WriteVariant(subkey, \"%s\", &var) returned 0x%08X\n",
          strText, hr);
      }
    }
  }

  // Release access to the safe array data
  VERIFY(SUCCEEDED(SafeArrayUnaccessData(psa)));

  // Indicate success
  return S_OK;
}