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#ifndef NOMINMAX 30#define NOMINMAX 31#endif 32#include <ocidl.h> 33#include <unknwn.h> 34 35#include <wtf/Noncopyable.h> 36#include <wtf/HashMap.h> 37 38#include "COMVariantSetter.h" 39 40template<typename ValueType, typename KeyType = typename WTF::String, typename HashType = typename WTF::StringHash> 41class COMPropertyBag : public IPropertyBag, public IPropertyBag2 { 42 WTF_MAKE_NONCOPYABLE(COMPropertyBag); 43public: 44 typedef HashMap<KeyType, ValueType, HashType> HashMapType; 45 46 static COMPropertyBag* createInstance(const HashMapType&); 47 static COMPropertyBag* adopt(HashMapType&); 48 49 // IUnknown 50 virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject); 51 virtual ULONG STDMETHODCALLTYPE AddRef(); 52 virtual ULONG STDMETHODCALLTYPE Release(); 53 54 // IPropertyBag 55 virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT*, IErrorLog*); 56 virtual HRESULT STDMETHODCALLTYPE Write(LPCOLESTR pszPropName, VARIANT*); 57 58 // IPropertyBag2 59 virtual HRESULT STDMETHODCALLTYPE Read(ULONG cProperties, PROPBAG2*, IErrorLog*, VARIANT* pvarValue, HRESULT* phrError); 60 virtual HRESULT STDMETHODCALLTYPE Write(ULONG cProperties, PROPBAG2*, VARIANT*); 61 virtual HRESULT STDMETHODCALLTYPE CountProperties(ULONG* pcProperties); 62 virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties); 63 virtual HRESULT STDMETHODCALLTYPE LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*); 64 65private: 66 COMPropertyBag() 67 : m_refCount(0) 68 { 69 } 70 71 COMPropertyBag(const HashMapType& hashMap) 72 : m_refCount(0) 73 , m_hashMap(hashMap) 74 { 75 } 76 77 ~COMPropertyBag() {} 78 79 ULONG m_refCount; 80 HashMapType m_hashMap; 81}; 82 83// COMPropertyBag ------------------------------------------------------------------ 84template<typename ValueType, typename KeyType, typename HashType> 85COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::createInstance(const HashMapType& hashMap) 86{ 87 COMPropertyBag* instance = new COMPropertyBag(hashMap); 88 instance->AddRef(); 89 return instance; 90} 91 92template<typename ValueType, typename KeyType, typename HashType> 93COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<typename ValueType, typename KeyType, HashType>::adopt(HashMapType& hashMap) 94{ 95 COMPropertyBag* instance = new COMPropertyBag; 96 instance->m_hashMap.swap(hashMap); 97 instance->AddRef(); 98 return instance; 99} 100 101// IUnknown ------------------------------------------------------------------------ 102template<typename ValueType, typename KeyType, typename HashType> 103HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::QueryInterface(REFIID riid, void** ppvObject) 104{ 105 *ppvObject = 0; 106 if (IsEqualGUID(riid, IID_IUnknown)) 107 *ppvObject = static_cast<IPropertyBag*>(this); 108 else if (IsEqualGUID(riid, IID_IPropertyBag)) 109 *ppvObject = static_cast<IPropertyBag*>(this); 110 else if (IsEqualGUID(riid, IID_IPropertyBag2)) 111 *ppvObject = static_cast<IPropertyBag2*>(this); 112 else 113 return E_NOINTERFACE; 114 115 AddRef(); 116 return S_OK; 117} 118 119template<typename ValueType, typename KeyType, typename HashType> 120ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::AddRef() 121{ 122 return ++m_refCount; 123} 124 125template<typename ValueType, typename KeyType, typename HashType> 126ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Release() 127{ 128 ULONG newRef = --m_refCount; 129 if (!newRef) 130 delete this; 131 132 return newRef; 133} 134 135// IPropertyBag -------------------------------------------------------------------- 136 137template<typename ValueType, typename KeyType, typename HashType> 138HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) 139{ 140 if (!pszPropName) 141 return E_POINTER; 142 143 HashMapType::const_iterator it = m_hashMap.find(String(pszPropName)); 144 HashMapType::const_iterator end = m_hashMap.end(); 145 if (it == end) 146 return E_INVALIDARG; 147 148 VARTYPE requestedType = V_VT(pVar); 149 V_VT(pVar) = VT_EMPTY; 150 COMVariantSetter<ValueType>::setVariant(pVar, it->value); 151 152 if (requestedType != COMVariantSetter<ValueType>::variantType(it->value) && requestedType != VT_EMPTY) 153 return ::VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType); 154 155 return S_OK; 156} 157 158template<typename ValueType, typename KeyType, typename HashType> 159HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(LPCOLESTR pszPropName, VARIANT* pVar) 160{ 161 return E_FAIL; 162} 163 164template<typename ValueType, typename KeyType, typename HashType> 165HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(ULONG cProperties, PROPBAG2* pPropBag, IErrorLog* pErrorLog, VARIANT* pvarValue, HRESULT* phrError) 166{ 167 if (!pPropBag || !pvarValue || !phrError) 168 return E_POINTER; 169 170 HRESULT hr = S_OK; 171 172 for (ULONG i = 0; i < cProperties; ++i) { 173 VariantInit(&pvarValue[i]); 174 pvarValue[i].vt = pPropBag[i].vt; 175 phrError[i] = Read(pPropBag[i].pstrName, &pvarValue[i], pErrorLog); 176 if (FAILED(phrError[i])) 177 hr = E_FAIL; 178 } 179 180 return hr; 181} 182 183template<typename ValueType, typename KeyType, typename HashType> 184HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(ULONG cProperties, PROPBAG2*, VARIANT*) 185{ 186 return E_NOTIMPL; 187} 188 189template<typename ValueType, typename KeyType, typename HashType> 190HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::CountProperties(ULONG* pcProperties) 191{ 192 if (!pcProperties) 193 return E_POINTER; 194 195 *pcProperties = m_hashMap.size(); 196 return S_OK; 197} 198 199template<typename ValueType, typename KeyType, typename HashType> 200HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::GetPropertyInfo(ULONG iProperty, ULONG cProperties, PROPBAG2* pPropBag, ULONG* pcProperties) 201{ 202 if (!pPropBag || !pcProperties) 203 return E_POINTER; 204 205 if (m_hashMap.size() <= iProperty) 206 return E_INVALIDARG; 207 208 *pcProperties = 0; 209 typedef HashMapType::const_iterator Iterator; 210 Iterator current = m_hashMap.begin(); 211 Iterator end = m_hashMap.end(); 212 for (ULONG i = 0; i < iProperty; ++i, ++current) 213 ; 214 for (ULONG j = 0; j < cProperties && current != end; ++j, ++current) { 215 // FIXME: the following fields aren't filled in 216 //pPropBag[j].cfType; // (CLIPFORMAT) Clipboard format or MIME type of the property. 217 //pPropBag[j].clsid; // (CLSID) CLSID of the object. This member is valid only if dwType is PROPBAG2_TYPE_OBJECT. 218 219 pPropBag[j].dwType = PROPBAG2_TYPE_DATA; 220 pPropBag[j].vt = COMVariantSetter<ValueType>::variantType(current->value); 221 pPropBag[j].dwHint = iProperty + j; 222 pPropBag[j].pstrName = (LPOLESTR)CoTaskMemAlloc(sizeof(wchar_t)*(current->key.length()+1)); 223 if (!pPropBag[j].pstrName) 224 return E_OUTOFMEMORY; 225 wcscpy_s(pPropBag[j].pstrName, current->key.length()+1, static_cast<String>(current->key).charactersWithNullTermination()); 226 ++*pcProperties; 227 } 228 return S_OK; 229} 230 231template<typename ValueType, typename KeyType, typename HashType> 232HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::LoadObject(LPCOLESTR pstrName, DWORD dwHint, IUnknown*, IErrorLog*) 233{ 234 return E_NOTIMPL; 235} 236 237#endif // COMPropertyBag_h 238