1/* 2 * Copyright (C) 2008 Apple Inc. All Rights Reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef COMPropertyBag_h 27#define COMPropertyBag_h 28 29#define NOMINMAX 30#include <ocidl.h> 31#include <unknwn.h> 32 33#include <wtf/Noncopyable.h> 34#include <wtf/HashMap.h> 35 36#include "COMVariantSetter.h" 37 38template<typename ValueType, typename KeyType = typename WTF::String, typename HashType = typename WTF::StringHash> 39class COMPropertyBag : public IPropertyBag, public IPropertyBag2 { 40 WTF_MAKE_NONCOPYABLE(COMPropertyBag); 41public: 42 typedef HashMap<KeyType, ValueType, HashType> HashMapType; 43 44 static COMPropertyBag* createInstance(const HashMapType&); 45 static COMPropertyBag* adopt(HashMapType&); 46 47 // IUnknown 48 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); 49 virtual ULONG STDMETHODCALLTYPE AddRef(); 50 virtual ULONG STDMETHODCALLTYPE Release(); 51 52 // IPropertyBag 53 virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT*, IErrorLog*); 54 virtual HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT*); 55 56 // IPropertyBag2 57 virtual HRESULT STDMETHODCALLTYPE Read(ULONG cProperties, PROPBAG2*, IErrorLog*, VARIANT* pvarValue, HRESULT* phrError); 58 virtual HRESULT STDMETHODCALLTYPE Write(ULONG cProperties, PROPBAG2*, VARIANT*); 59 virtual HRESULT STDMETHODCALLTYPE CountProperties(ULONG* pcProperties); 60 virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); 61 virtual HRESULT STDMETHODCALLTYPE LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*); 62 63private: 64 COMPropertyBag() 65 : m_refCount(0) 66 { 67 } 68 69 COMPropertyBag(const HashMapType& hashMap) 70 : m_refCount(0) 71 , m_hashMap(hashMap) 72 { 73 } 74 75 ~COMPropertyBag() {} 76 77 ULONG m_refCount; 78 HashMapType m_hashMap; 79}; 80 81// COMPropertyBag ------------------------------------------------------------------ 82template<typename ValueType, typename KeyType, typename HashType> 83COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::createInstance(const HashMapType& hashMap) 84{ 85 COMPropertyBag* instance = new COMPropertyBag(hashMap); 86 instance->AddRef(); 87 return instance; 88} 89 90template<typename ValueType, typename KeyType, typename HashType> 91COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::adopt(HashMapType& hashMap) 92{ 93 COMPropertyBag* instance = new COMPropertyBag; 94 instance->m_hashMap.swap(hashMap); 95 instance->AddRef(); 96 return instance; 97} 98 99// IUnknown ------------------------------------------------------------------------ 100template<typename ValueType, typename KeyType, typename HashType> 101HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::QueryInterface(REFIID riid, void** ppvObject) 102{ 103 *ppvObject = 0; 104 if (IsEqualGUID(riid, IID_IUnknown)) 105 *ppvObject = static_cast<IPropertyBag*>(this); 106 else if (IsEqualGUID(riid, IID_IPropertyBag)) 107 *ppvObject = static_cast<IPropertyBag*>(this); 108 else if (IsEqualGUID(riid, IID_IPropertyBag2)) 109 *ppvObject = static_cast<IPropertyBag2*>(this); 110 else 111 return E_NOINTERFACE; 112 113 AddRef(); 114 return S_OK; 115} 116 117template<typename ValueType, typename KeyType, typename HashType> 118ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::AddRef() 119{ 120 return ++m_refCount; 121} 122 123template<typename ValueType, typename KeyType, typename HashType> 124ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Release() 125{ 126 ULONG newRef = --m_refCount; 127 if (!newRef) 128 delete this; 129 130 return newRef; 131} 132 133// IPropertyBag -------------------------------------------------------------------- 134 135template<typename ValueType, typename KeyType, typename HashType> 136HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) 137{ 138 if (!pszPropName) 139 return E_POINTER; 140 141 HashMapType::const_iterator it = m_hashMap.find(String(pszPropName)); 142 HashMapType::const_iterator end = m_hashMap.end(); 143 if (it == end) 144 return E_INVALIDARG; 145 146 VARTYPE requestedType = V_VT(pVar); 147 V_VT(pVar) = VT_EMPTY; 148 COMVariantSetter<ValueType>::setVariant(pVar, it->second); 149 150 if (requestedType != COMVariantSetter<ValueType>::variantType(it->second) && requestedType != VT_EMPTY) 151 return ::VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType); 152 153 return S_OK; 154} 155 156template<typename ValueType, typename KeyType, typename HashType> 157HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(LPCOLESTR pszPropName, VARIANT* pVar) 158{ 159 return E_FAIL; 160} 161 162template<typename ValueType, typename KeyType, typename HashType> 163HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrorLog, VARIANT* pvarValue, HRESULT* phrError) 164{ 165 if (!pPropBag || !pvarValue || !phrError) 166 return E_POINTER; 167 168 HRESULT hr = S_OK; 169 170 for (ULONG i = 0; i < cProperties; ++i) { 171 VariantInit(&pvarValue[i]); 172 pvarValue[i].vt = pPropBag[i].vt; 173 phrError[i] = Read(pPropBag[i].pstrName, &pvarValue[i], pErrorLog); 174 if (FAILED(phrError[i])) 175 hr = E_FAIL; 176 } 177 178 return hr; 179} 180 181template<typename ValueType, typename KeyType, typename HashType> 182HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(ULONG cProperties, PROPBAG2*, VARIANT*) 183{ 184 return E_NOTIMPL; 185} 186 187template<typename ValueType, typename KeyType, typename HashType> 188HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::CountProperties(ULONG* pcProperties) 189{ 190 if (!pcProperties) 191 return E_POINTER; 192 193 *pcProperties = m_hashMap.size(); 194 return S_OK; 195} 196 197template<typename ValueType, typename KeyType, typename HashType> 198HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) 199{ 200 if (!pPropBag || !pcProperties) 201 return E_POINTER; 202 203 if (m_hashMap.size() <= iProperty) 204 return E_INVALIDARG; 205 206 *pcProperties = 0; 207 typedef HashMapType::const_iterator Iterator; 208 Iterator current = m_hashMap.begin(); 209 Iterator end = m_hashMap.end(); 210 for (ULONG i = 0; i < iProperty; ++i, ++current) 211 ; 212 for (ULONG j = 0; j < cProperties && current != end; ++j, ++current) { 213 // FIXME: the following fields aren't filled in 214 //pPropBag[j].cfType; // (CLIPFORMAT) Clipboard format or MIME type of the property. 215 //pPropBag[j].clsid; // (CLSID) CLSID of the object. This member is valid only if dwType is PROPBAG2_TYPE_OBJECT. 216 217 pPropBag[j].dwType = PROPBAG2_TYPE_DATA; 218 pPropBag[j].vt = COMVariantSetter<ValueType>::variantType(current->second); 219 pPropBag[j].dwHint = iProperty + j; 220 pPropBag[j].pstrName = (LPOLESTR)CoTaskMemAlloc(sizeof(wchar_t)*(current->first.length()+1)); 221 if (!pPropBag[j].pstrName) 222 return E_OUTOFMEMORY; 223 wcscpy_s(pPropBag[j].pstrName, current->first.length()+1, static_cast<String>(current->first).charactersWithNullTermination()); 224 ++*pcProperties; 225 } 226 return S_OK; 227} 228 229template<typename ValueType, typename KeyType, typename HashType> 230HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*) 231{ 232 return E_NOTIMPL; 233} 234 235#endif // COMPropertyBag_h 236