Example #1
0
BOOL AFXAPI _AfxCoerceNumber(void* pvDst, VARTYPE vtDst, void* pvSrc, VARTYPE vtSrc)
{
	// Check size of source.
	size_t cbSrc = _AfxGetSizeOfVarType(vtSrc);
	if (cbSrc == 0)
		return FALSE;

	// If source and destination are same type, just copy.
	if (vtSrc == vtDst)
	{
		memcpy(pvDst, pvSrc, cbSrc);
		return TRUE;
	}

	// Check size of destination.
	size_t cbDst = _AfxGetSizeOfVarType(vtDst);

	if (cbDst == 0)
		return FALSE;

	// Initialize variant for coercion.
	VARIANTARG var;
	V_VT(&var) = vtSrc;
	memcpy((void*)&V_NONE(&var), pvSrc, cbSrc);

	// Do the coercion.
	if (FAILED(VariantChangeType(&var, &var, 0, vtDst)))
		return FALSE;

	// Copy result to destination.
	memcpy(pvDst, (void*)&V_NONE(&var), cbDst);
	return TRUE;
}
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;
}
HRESULT CTCPropBagOnRegKey::_ReadSafeArray(CRegKey& key,
  const _bstr_t& strPropName, VARIANT* pVar, IErrorLog* pErrorLog)
{
  // Open the subkey with the specified name
  CRegKey subkey;
  VERIFY(subkey.Open(key, strPropName));

  // Read the variant type of the registry value
  VARTYPE vt = GetSubkeyVarType(key, strPropName);
  ASSERT(vt & VT_ARRAY);

  // Remove the VT_ARRAY bit flag from the variant type
  vt &= ~VT_ARRAY;

  // Check for supported variant types
  switch (vt)
  {
    case VT_BOOL:
    case VT_I1:
    case VT_I2:
    case VT_I4:
    case VT_UI1:
    case VT_UI2:
    case VT_UI4:
    case VT_ERROR:
    case VT_R4:
    case VT_R8:
    case VT_DECIMAL:
    case VT_CY:
    case VT_DATE:
    case VT_BSTR:
    case VT_UNKNOWN:
    case VT_DISPATCH:
    case VT_VARIANT:
      break;
    default:
    {
      // Use local resources
      MCLibRes res;

      // Format a description string
      _bstr_t strDesc;
      strDesc.Format(IDS_FMT_UNSUP_ARRAY_VARTYPE, strPropName, vt, vt);

      // Log the error
      USES_CONVERSION;
      return LogError("ReadSafeArray", strDesc, E_UNEXPECTED,
        T2COLE(strPropName), pErrorLog);
    }
  }

  // Read the element count of the safe array
  DWORD dwElements = 0;
  if (!subkey.GetDWord(m_szElementCount, dwElements))
  {
    // Use local resources
    MCLibRes res;

    // Format a description string
    _bstr_t strDesc;
    strDesc.Format(IDS_FMT_VALUE_NOT_EXIST, m_szElementCount, strPropName);

    // Log the error
    USES_CONVERSION;
    return LogError("ReadSafeArray", strDesc, E_UNEXPECTED,
      T2COLE(strPropName), pErrorLog);
  }

  // Read the lower bound of the safe array, defaults to zero
  LONG lLBound = 0;
  subkey.GetDWord(m_szLowerBound, (DWORD&)lLBound);

  // Read each array element into a temporary array
  _bstr_t strText;
  CComVariant var;
  CArray<CComVariant, CComVariant&> arrayTemp;
  for (DWORD i = 0; i < dwElements; i++)
  {
    // Prepare the variant
    V_VT(&var) = vt;

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

    // Read the variant
    HRESULT hr = ReadVariant(subkey, strText, var, pErrorLog);
    if (FAILED(hr))
      return hr;

    // Add the variant to the temporary array
    arrayTemp.Add(var);
  }

  // Create a safe array and copy the temporary array elements
  SAFEARRAY* psa = SafeArrayCreateVector(vt, lLBound, dwElements);
  if (NULL == psa)
  {
    // Use local resources
    MCLibRes res;

    // Format a description string
    _bstr_t strDesc(LPCSTR(IDS_FAIL_SAFEARRAY_CREATE));

    // Log the error
    USES_CONVERSION;
    return LogError("ReadSafeArray", strDesc, E_OUTOFMEMORY,
      T2COLE(strPropName), pErrorLog);
  }

  // Copy the temporary array elements into the safe array
  for (long iElement = 0; iElement < arrayTemp.GetSize(); iElement++)
  {
    CComVariant& v = arrayTemp[iElement];
    void* pvData;
    switch (vt)
    {
      case VT_VARIANT:
        pvData = &v;
        break;
      case VT_UNKNOWN:
      case VT_DISPATCH:
      case VT_BSTR:
        pvData = V_BSTR(&v);
        break;
      default:
        pvData = &V_NONE(&v);
    }

    HRESULT hr = SafeArrayPutElement(psa, &iElement, pvData);
    if (FAILED(hr))
    {
      // Use local resources
      MCLibRes res;

      // Format a description string
      _bstr_t strDesc(LPCSTR(IDS_FAIL_SAFEARRAY_PUT));

      // Log the error
      USES_CONVERSION;
      return LogError("ReadSafeArray", strDesc, hr, T2COLE(strPropName),
        pErrorLog);
    }
  }

  // Put the safe array into the specified variant
  V_VT(pVar) = vt | VT_ARRAY;
  V_ARRAY(pVar) = psa;

  // Indicate success
  return S_OK;
}