Home | History | Annotate | Download | only in win
      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