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::_SetServer(const _bstr_t& strName,
  const _bstr_t& strServer)
{
  // Open the subkey with the specified name
  CRegKey subkey;
  if (!strName.length())
    subkey = m_key;
  else if (!m_key.Exists(strName) || !subkey.Open(m_key, strName))
    return HRESULT_FROM_WIN32(GetLastError());

  // Write the Server of the object saved on the specified subkey
  subkey.WriteString(m_szServer, strServer);

  // Indicate success
  return S_OK;
}
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;
}