1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ 6 #define CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ 7 8 #include <map> 9 #include <ocidl.h> // IProvideClassInfo2 10 11 #include "base/synchronization/lock.h" 12 #include "base/win/scoped_comptr.h" 13 14 #define NO_VTABLE __declspec(novtable) 15 16 namespace com_util { 17 18 // A map from a name hash (32 bit value) to a DISPID. 19 // Used as a caching layer before looking the name up in a type lib. 20 class NameToDispIdCache { 21 public: 22 typedef uint32 HashType; 23 24 bool Lookup(HashType hash, DISPID* dispid) const; 25 void Add(HashType hash, DISPID dispid); 26 27 // Hashes the name by calling LHashValOfName. 28 // The returned hash value is independent of the case of the characters 29 // in |name|. 30 static HashType Hash(const wchar_t* name); 31 32 protected: 33 typedef std::map<HashType, DISPID> DispidMap; 34 DispidMap map_; 35 mutable base::Lock lock_; 36 }; 37 38 // Wraps an instance of ITypeInfo and builds+maintains a cache of names 39 // to dispids. Also offers an Invoke method that simply forwards the call 40 // to ITypeInfo::Invoke. 41 class TypeInfoNameCache { 42 public: 43 // Loads the module's type library and fetches the ITypeInfo object for 44 // the specified interface ID. 45 HRESULT Initialize(const IID& iid); 46 47 // Fetches the id's of the given names. If there's a cache miss, the results 48 // are fetched from the underlying ITypeInfo and then cached. 49 HRESULT GetIDsOfNames(OLECHAR** names, uint32 count, DISPID* dispids); 50 51 // Calls ITypeInfo::Invoke. 52 HRESULT Invoke(IDispatch* p, DISPID dispid, WORD flags, DISPPARAMS* params, 53 VARIANT* result, EXCEPINFO* excepinfo, UINT* arg_err); 54 55 inline ITypeInfo* CopyTypeInfo() { 56 ITypeInfo* ti = type_info_.get(); 57 if (ti) 58 ti->AddRef(); 59 return ti; 60 } 61 62 protected: 63 base::win::ScopedComPtr<ITypeInfo> type_info_; 64 NameToDispIdCache cache_; 65 }; 66 67 // The root class for type lib access. 68 // This class has only one instance that should be accessed via the 69 // Singleton method. 70 class TypeInfoCache { 71 public: 72 TypeInfoCache() { 73 } 74 75 ~TypeInfoCache(); 76 77 // Looks up a previously cached TypeInfoNameCache instance or creates and 78 // caches a new one. 79 TypeInfoNameCache* Lookup(const IID* iid); 80 81 // Call to get access to the singleton instance of TypeInfoCache. 82 static TypeInfoCache* Singleton(); 83 84 protected: 85 typedef std::map<const IID*, TypeInfoNameCache*> CacheMap; 86 base::Lock lock_; 87 CacheMap cache_; 88 }; 89 90 // Holds a pointer to the type info of a given COM interface. 91 // The type info is loaded once on demand and after that cached. 92 // NOTE: This class only supports loading the first typelib from the 93 // current module. 94 template <const IID& iid> 95 class TypeInfoHolder { 96 public: 97 TypeInfoHolder() : type_info_(NULL) { 98 } 99 100 bool EnsureTI() { 101 if (!type_info_) 102 type_info_ = TypeInfoCache::Singleton()->Lookup(&iid); 103 return type_info_ != NULL; 104 } 105 106 HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** info) { 107 if (EnsureTI()) { 108 *info = type_info_->CopyTypeInfo(); 109 return S_OK; 110 } 111 112 return E_UNEXPECTED; 113 } 114 115 HRESULT GetIDsOfNames(REFIID riid, OLECHAR** names, UINT count, LCID lcid, 116 DISPID* dispids) { 117 if (!EnsureTI()) 118 return E_UNEXPECTED; 119 return type_info_->GetIDsOfNames(names, count, dispids); 120 } 121 122 HRESULT Invoke(IDispatch* p, DISPID dispid, REFIID riid, LCID lcid, 123 WORD flags, DISPPARAMS* params, VARIANT* result, 124 EXCEPINFO* excepinfo, UINT* arg_err) { 125 if (!EnsureTI()) 126 return E_UNEXPECTED; 127 128 return type_info_->Invoke(p, dispid, flags, params, result, excepinfo, 129 arg_err); 130 } 131 132 protected: 133 TypeInfoNameCache* type_info_; 134 }; 135 136 // Implements IDispatch part of T (where T is an IDispatch derived interface). 137 // The class assumes that the type info of T is available in a typelib of the 138 // current module. 139 template <class T, const IID& iid = __uuidof(T)> 140 class NO_VTABLE IDispatchImpl : public T { 141 public: 142 STDMETHOD(GetTypeInfoCount)(UINT* count) { 143 if (count == NULL) 144 return E_POINTER; 145 *count = 1; 146 return S_OK; 147 } 148 149 STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { 150 return type_info_.GetTypeInfo(itinfo, lcid, pptinfo); 151 } 152 153 STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* names, UINT count, 154 LCID lcid, DISPID* dispids) { 155 return type_info_.GetIDsOfNames(riid, names, count, lcid, dispids); 156 } 157 STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD flags, 158 DISPPARAMS* params, VARIANT* result, EXCEPINFO* excepinfo, 159 UINT* arg_err) { 160 return type_info_.Invoke(static_cast<IDispatch*>(this), dispid, riid, lcid, 161 flags, params, result, excepinfo, arg_err); 162 } 163 164 protected: 165 TypeInfoHolder<iid> type_info_; 166 }; 167 168 // Simple implementation of IProvideClassInfo[2]. 169 template <const CLSID& class_id, const IID& source_iid> 170 class NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2 { 171 public: 172 STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo) { 173 return type_info_.GetTypeInfo(0, LANG_NEUTRAL, pptinfo); 174 } 175 176 STDMETHOD(GetGUID)(DWORD guid_kind, GUID* guid) { 177 if (guid == NULL || guid_kind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) 178 return E_INVALIDARG; 179 180 *guid = source_iid; 181 182 return S_OK; 183 } 184 185 protected: 186 TypeInfoHolder<class_id> type_info_; 187 }; 188 189 } // namespace com_util 190 191 #endif // CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ 192