| /* |
| * Copyright (C) 2008, 2015 Apple Inc. All Rights Reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #include "COMVariantSetter.h" |
| #include <ocidl.h> |
| #include <unknwn.h> |
| #include <wtf/Noncopyable.h> |
| #include <wtf/HashMap.h> |
| |
| template<typename ValueType, typename KeyType = typename WTF::String, typename HashType = typename WTF::StringHash> |
| class COMPropertyBag final : public IPropertyBag, public IPropertyBag2 { |
| WTF_MAKE_NONCOPYABLE(COMPropertyBag); |
| public: |
| typedef HashMap<KeyType, ValueType, HashType> HashMapType; |
| |
| static COMPropertyBag* createInstance(const HashMapType&); |
| static COMPropertyBag* adopt(HashMapType&); |
| |
| // IUnknown |
| virtual HRESULT STDMETHODCALLTYPE QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject); |
| virtual ULONG STDMETHODCALLTYPE AddRef(); |
| virtual ULONG STDMETHODCALLTYPE Release(); |
| |
| // IPropertyBag |
| virtual HRESULT STDMETHODCALLTYPE Read(LPCOLESTR pszPropName, VARIANT*, IErrorLog*); |
| virtual HRESULT STDMETHODCALLTYPE Write(_In_ LPCOLESTR pszPropName, _In_ VARIANT*); |
| |
| // IPropertyBag2 |
| virtual HRESULT STDMETHODCALLTYPE Read(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, _In_opt_ IErrorLog*, __out_ecount_full(cProperties) VARIANT*, __inout_ecount_full_opt(cProperties) HRESULT*); |
| virtual HRESULT STDMETHODCALLTYPE Write(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, __inout_ecount_full(cProperties) VARIANT*); |
| virtual HRESULT STDMETHODCALLTYPE CountProperties(_Out_ ULONG* pcProperties); |
| virtual HRESULT STDMETHODCALLTYPE GetPropertyInfo(ULONG iProperty, ULONG cProperties, __out_ecount_full(cProperties) PROPBAG2*, _Out_ ULONG* pcProperties); |
| virtual HRESULT STDMETHODCALLTYPE LoadObject(_In_ LPCOLESTR pstrName, DWORD dwHint, _In_opt_ IUnknown*, _In_opt_ IErrorLog*); |
| |
| private: |
| COMPropertyBag() |
| { |
| } |
| |
| COMPropertyBag(const HashMapType& hashMap) |
| : m_hashMap(hashMap) |
| { |
| } |
| |
| ~COMPropertyBag() {} |
| |
| ULONG m_refCount { 0 }; |
| HashMapType m_hashMap; |
| }; |
| |
| // COMPropertyBag ------------------------------------------------------------------ |
| template<typename ValueType, typename KeyType, typename HashType> |
| COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<ValueType, KeyType, HashType>::createInstance(const HashMapType& hashMap) |
| { |
| COMPropertyBag* instance = new COMPropertyBag(hashMap); |
| instance->AddRef(); |
| return instance; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| COMPropertyBag<ValueType, KeyType, HashType>* COMPropertyBag<ValueType, KeyType, HashType>::adopt(HashMapType& hashMap) |
| { |
| COMPropertyBag* instance = new COMPropertyBag; |
| instance->m_hashMap.swap(hashMap); |
| instance->AddRef(); |
| return instance; |
| } |
| |
| // IUnknown ------------------------------------------------------------------------ |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::QueryInterface(_In_ REFIID riid, _COM_Outptr_ void** ppvObject) |
| { |
| if (!ppvObject) |
| return E_POINTER; |
| *ppvObject = nullptr; |
| if (IsEqualGUID(riid, IID_IUnknown)) |
| *ppvObject = static_cast<IPropertyBag*>(this); |
| else if (IsEqualGUID(riid, IID_IPropertyBag)) |
| *ppvObject = static_cast<IPropertyBag*>(this); |
| else if (IsEqualGUID(riid, IID_IPropertyBag2)) |
| *ppvObject = static_cast<IPropertyBag2*>(this); |
| else |
| return E_NOINTERFACE; |
| |
| AddRef(); |
| return S_OK; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::AddRef() |
| { |
| return ++m_refCount; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| ULONG STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Release() |
| { |
| ULONG newRef = --m_refCount; |
| if (!newRef) |
| delete this; |
| |
| return newRef; |
| } |
| |
| // IPropertyBag -------------------------------------------------------------------- |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(LPCOLESTR pszPropName, VARIANT* pVar, IErrorLog* pErrorLog) |
| { |
| if (!pszPropName) |
| return E_POINTER; |
| |
| auto it = m_hashMap.find(String(pszPropName)); |
| auto end = m_hashMap.end(); |
| if (it == end) |
| return E_INVALIDARG; |
| |
| VARTYPE requestedType = V_VT(pVar); |
| V_VT(pVar) = VT_EMPTY; |
| COMVariantSetter<ValueType>::setVariant(pVar, it->value); |
| |
| if (requestedType != COMVariantSetter<ValueType>::variantType(it->value) && requestedType != VT_EMPTY) |
| return ::VariantChangeType(pVar, pVar, VARIANT_NOUSEROVERRIDE | VARIANT_ALPHABOOL, requestedType); |
| |
| return S_OK; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(_In_ LPCOLESTR pszPropName, _In_ VARIANT* pVar) |
| { |
| return E_FAIL; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Read(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2* pPropBag, _In_opt_ IErrorLog* pErrorLog, __out_ecount_full(cProperties) VARIANT* pvarValue, __inout_ecount_full_opt(cProperties) HRESULT* phrError) |
| { |
| if (!pPropBag || !pvarValue || !phrError) |
| return E_POINTER; |
| |
| HRESULT hr = S_OK; |
| |
| for (ULONG i = 0; i < cProperties; ++i) { |
| ::VariantInit(&pvarValue[i]); |
| pvarValue[i].vt = pPropBag[i].vt; |
| phrError[i] = Read(pPropBag[i].pstrName, &pvarValue[i], pErrorLog); |
| if (FAILED(phrError[i])) |
| hr = E_FAIL; |
| } |
| |
| return hr; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::Write(ULONG cProperties, __inout_ecount_full(cProperties) PROPBAG2*, __inout_ecount_full(cProperties) VARIANT*) |
| { |
| return E_NOTIMPL; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::CountProperties(_Out_ ULONG* pcProperties) |
| { |
| if (!pcProperties) |
| return E_POINTER; |
| |
| *pcProperties = m_hashMap.size(); |
| return S_OK; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::GetPropertyInfo(ULONG iProperty, ULONG cProperties, __out_ecount_full(cProperties) PROPBAG2* pPropBag, _Out_ ULONG* pcProperties) |
| { |
| if (!pPropBag || !pcProperties) |
| return E_POINTER; |
| |
| *pcProperties = 0; |
| |
| if (m_hashMap.size() <= iProperty) |
| return E_INVALIDARG; |
| |
| *pcProperties = 0; |
| auto current = m_hashMap.begin(); |
| auto end = m_hashMap.end(); |
| for (ULONG i = 0; i < iProperty; ++i, ++current) |
| ; |
| for (ULONG j = 0; j < cProperties && current != end; ++j, ++current) { |
| // FIXME: the following fields aren't filled in |
| //pPropBag[j].cfType; // (CLIPFORMAT) Clipboard format or MIME type of the property. |
| //pPropBag[j].clsid; // (CLSID) CLSID of the object. This member is valid only if dwType is PROPBAG2_TYPE_OBJECT. |
| |
| pPropBag[j].dwType = PROPBAG2_TYPE_DATA; |
| pPropBag[j].vt = COMVariantSetter<ValueType>::variantType(current->value); |
| pPropBag[j].dwHint = iProperty + j; |
| pPropBag[j].pstrName = (LPOLESTR)CoTaskMemAlloc(sizeof(wchar_t)*(current->key.length()+1)); |
| if (!pPropBag[j].pstrName) |
| return E_OUTOFMEMORY; |
| wcscpy_s(pPropBag[j].pstrName, current->key.length()+1, current->key.wideCharacters().data()); |
| ++*pcProperties; |
| } |
| return S_OK; |
| } |
| |
| template<typename ValueType, typename KeyType, typename HashType> |
| HRESULT STDMETHODCALLTYPE COMPropertyBag<ValueType, KeyType, HashType>::LoadObject(_In_ LPCOLESTR pstrName, DWORD dwHint, _In_opt_ IUnknown*, _In_opt_ IErrorLog*) |
| { |
| return E_NOTIMPL; |
| } |