HRESULT CTCPropBagOnRegKey::_SaveObject(const _bstr_t& strName, IUnknown* punkObj, BOOL bClearDirty, BOOL bSaveAllProperties) { // Validate the specified parameters if (IsBadReadPtr(punkObj)) return E_POINTER; // Create a subkey with the specified name CRegKey subkey; if (!strName.length()) subkey = m_key; else { m_key.DeleteValue(strName); m_key.RecurseDeleteKey(strName); if (!subkey.Open(m_key, strName)) return HRESULT_FROM_WIN32(GetLastError()); } // QueryInterface for IPersistPropertyBag IPersistPropertyBagPtr pppb; HRESULT hr = punkObj->QueryInterface(__uuidof(pppb), (void**)&pppb); if (FAILED(hr)) return hr; // Get the object's CLSID CLSID clsid; hr = pppb->GetClassID(&clsid); if (FAILED(hr)) return hr; // Attempt first to convert the object's CLSID to a ProgID LPOLESTR pszProgID = NULL; if (SUCCEEDED(ProgIDFromCLSID(clsid, &pszProgID))) { subkey.WriteString(m_szProgID, pszProgID); CoTaskMemFree(pszProgID); } else { // Convert the object's CLSID to a string OLECHAR szClassID[64]; StringFromGUID2(clsid, szClassID, sizeofArray(szClassID)); subkey.WriteString(m_szCLSID, szClassID); } // Write the variant type value subkey.WriteDWord(m_szVariantType, DWORD(VarTypeFromUnknown(punkObj))); // Save the persistent properties of the object CComObjectStack<CTCPropBagOnRegKey> bag; bag.Init(subkey, strName, this); hr = pppb->Save(&bag, bClearDirty, bSaveAllProperties); // Return the last HRESULT return hr; }
HRESULT CTCPropBagOnRegKey::_WriteVariant(CRegKey& key, const _bstr_t& strValueName, VARIANT* pVar) { // Check for an array if (V_ISARRAY(pVar)) return WriteSafeArray(key, strValueName, pVar); // Write the value to the registry based on the VARIANT type switch (V_VT(pVar)) { // Empty variant is written as nothing case VT_EMPTY: key.DeleteValue(strValueName); key.RecurseDeleteKey(strValueName); break; // Integer types are written as a REG_DWORD value case VT_I1: case VT_I2: case VT_I4: case VT_UI1: case VT_UI2: case VT_ERROR: { // Coerce the value to a VT_UI4 VariantChangeTypeEx(pVar, pVar, GetThreadLocale(), m_wChangeTypeFlags, VT_UI4); // Fall thru to next case } case VT_UI4: { // Write the REG_DWORD value to the registry key.RecurseDeleteKey(strValueName); key.WriteDWord(strValueName, V_UI4(pVar)); break; } // BOOL's, float types and strings are written as a REG_SZ value case VT_R4: case VT_R8: case VT_CY: case VT_DATE: case VT_DECIMAL: case VT_BOOL: { // Coerce the value to a VT_BSTR VariantChangeTypeEx(pVar, pVar, GetThreadLocale(), m_wChangeTypeFlags, VT_BSTR); // Fall thru to next case } case VT_BSTR: { // Write the REG_SZ value to the registry key.RecurseDeleteKey(strValueName); key.WriteString(strValueName, V_BSTR(pVar)); break; } // Objects written as REG_BINARY, if they don't support IPersistPropertyBag case VT_UNKNOWN: case VT_DISPATCH: { // Attempt first to save the object property using IPersistPropertyBag key.DeleteValue(strValueName); key.RecurseDeleteKey(strValueName); CComObjectStack<CTCPropBagOnRegKey> bag; bag.Init(key, _bstr_t(), this); HRESULT hr = bag.SaveObject(strValueName, V_UNKNOWN(pVar), FALSE, TRUE); if (FAILED(hr)) { TRACE1("CTCPropBagOnRegKey::_WriteVariant: Saving object property \"%s\" as a binary value\n", strValueName); // Create a CArchive on a CMemFile CMemFile file; CArchive ar(&file, CArchive::store, 0); // Archive the variant to the CArchive and close it CComVariant v(pVar); ar << v; ar.Close(); // Write the REG_BINARY value to the registry int cbData = file.GetLength(); BYTE* pData = file.Detach(); key.RecurseDeleteKey(strValueName); key.WriteBinary(strValueName, pData, cbData); file.Attach(pData, cbData); } break; } default: TRACE1("CTCPropBagOnRegKey::_WriteVariant(\"%ls\"): ", strValueName); TRACE2("Unsupported variant type 0x%02X (%d)\n", UINT(V_VT(pVar)), UINT(V_VT(pVar))); return E_FAIL; } // Indicate success return S_OK; }
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; }