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; }