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