Index: chrome_frame/com_type_info_holder.h |
=================================================================== |
--- chrome_frame/com_type_info_holder.h (revision 0) |
+++ chrome_frame/com_type_info_holder.h (revision 0) |
@@ -0,0 +1,191 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#ifndef CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ |
+#define CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ |
+ |
+#include <map> |
+#include <ocidl.h> // IProvideClassInfo2 |
+ |
+#include "base/lock.h" |
+#include "base/scoped_comptr_win.h" |
+ |
+#define NO_VTABLE __declspec(novtable) |
+ |
+namespace com_util { |
+ |
+// A map from a name hash (32 bit value) to a DISPID. |
+// Used as a caching layer before looking the name up in a type lib. |
+class NameToDispIdCache { |
+ public: |
+ typedef uint32 HashType; |
+ |
+ bool Lookup(HashType hash, DISPID* dispid) const; |
+ void Add(HashType hash, DISPID dispid); |
+ |
+ // Hashes the name by calling LHashValOfName. |
+ // The returned hash value is independent of the case of the characters |
+ // in |name|. |
+ static HashType Hash(const wchar_t* name); |
+ |
+ protected: |
+ typedef std::map<HashType, DISPID> DispidMap; |
+ DispidMap map_; |
+ mutable Lock lock_; |
+}; |
+ |
+// Wraps an instance of ITypeInfo and builds+maintains a cache of names |
+// to dispids. Also offers an Invoke method that simply forwards the call |
+// to ITypeInfo::Invoke. |
+class TypeInfoNameCache { |
+ public: |
+ // Loads the module's type library and fetches the ITypeInfo object for |
+ // the specified interface ID. |
+ HRESULT Initialize(const IID& iid); |
+ |
+ // Fetches the id's of the given names. If there's a cache miss, the results |
+ // are fetched from the underlying ITypeInfo and then cached. |
+ HRESULT GetIDsOfNames(OLECHAR** names, uint32 count, DISPID* dispids); |
+ |
+ // Calls ITypeInfo::Invoke. |
+ HRESULT Invoke(IDispatch* p, DISPID dispid, WORD flags, DISPPARAMS* params, |
+ VARIANT* result, EXCEPINFO* excepinfo, UINT* arg_err); |
+ |
+ inline ITypeInfo* CopyTypeInfo() { |
+ ITypeInfo* ti = type_info_.get(); |
+ if (ti) |
+ ti->AddRef(); |
+ return ti; |
+ } |
+ |
+ protected: |
+ ScopedComPtr<ITypeInfo> type_info_; |
+ NameToDispIdCache cache_; |
+}; |
+ |
+// The root class for type lib access. |
+// This class has only one instance that should be accessed via the |
+// Singleton method. |
+class TypeInfoCache { |
+ public: |
+ TypeInfoCache() { |
+ } |
+ |
+ ~TypeInfoCache(); |
+ |
+ // Looks up a previously cached TypeInfoNameCache instance or creates and |
+ // caches a new one. |
+ TypeInfoNameCache* Lookup(const IID* iid); |
+ |
+ // Call to get access to the singleton instance of TypeInfoCache. |
+ static TypeInfoCache* Singleton(); |
+ |
+ protected: |
+ typedef std::map<const IID*, TypeInfoNameCache*> CacheMap; |
+ Lock lock_; |
+ CacheMap cache_; |
+}; |
+ |
+// Holds a pointer to the type info of a given COM interface. |
+// The type info is loaded once on demand and after that cached. |
+// NOTE: This class only supports loading the first typelib from the |
+// current module. |
+template <const IID& iid> |
+class TypeInfoHolder { |
+ public: |
+ TypeInfoHolder() : type_info_(NULL) { |
+ } |
+ |
+ bool EnsureTI() { |
+ if (!type_info_) |
+ type_info_ = TypeInfoCache::Singleton()->Lookup(&iid); |
+ return type_info_ != NULL; |
+ } |
+ |
+ HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** info) { |
+ if (EnsureTI()) { |
+ *info = type_info_->CopyTypeInfo(); |
+ return S_OK; |
+ } |
+ |
+ return E_UNEXPECTED; |
+ } |
+ |
+ HRESULT GetIDsOfNames(REFIID riid, OLECHAR** names, UINT count, LCID lcid, |
+ DISPID* dispids) { |
+ if (!EnsureTI()) |
+ return E_UNEXPECTED; |
+ return type_info_->GetIDsOfNames(names, count, dispids); |
+ } |
+ |
+ HRESULT Invoke(IDispatch* p, DISPID dispid, REFIID riid, LCID lcid, |
+ WORD flags, DISPPARAMS* params, VARIANT* result, |
+ EXCEPINFO* excepinfo, UINT* arg_err) { |
+ if (!EnsureTI()) |
+ return E_UNEXPECTED; |
+ |
+ return type_info_->Invoke(p, dispid, flags, params, result, excepinfo, |
+ arg_err); |
+ } |
+ |
+ protected: |
+ TypeInfoNameCache* type_info_; |
+}; |
+ |
+// Implements IDispatch part of T (where T is an IDispatch derived interface). |
+// The class assumes that the type info of T is available in a typelib of the |
+// current module. |
+template <class T, const IID& iid = __uuidof(T)> |
+class NO_VTABLE IDispatchImpl : public T { |
+ public: |
+ STDMETHOD(GetTypeInfoCount)(UINT* count) { |
+ if (count == NULL) |
+ return E_POINTER; |
+ *count = 1; |
+ return S_OK; |
+ } |
+ |
+ STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) { |
+ return type_info_.GetTypeInfo(itinfo, lcid, pptinfo); |
+ } |
+ |
+ STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* names, UINT count, |
+ LCID lcid, DISPID* dispids) { |
+ return type_info_.GetIDsOfNames(riid, names, count, lcid, dispids); |
+ } |
+ STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD flags, |
+ DISPPARAMS* params, VARIANT* result, EXCEPINFO* excepinfo, |
+ UINT* arg_err) { |
+ return type_info_.Invoke(static_cast<IDispatch*>(this), dispid, riid, lcid, |
+ flags, params, result, excepinfo, arg_err); |
+ } |
+ |
+ protected: |
+ TypeInfoHolder<iid> type_info_; |
+}; |
+ |
+// Simple implementation of IProvideClassInfo[2]. |
+template <const CLSID& class_id, const IID& source_iid> |
+class NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2 { |
+ public: |
+ STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo) { |
+ return type_info_.GetTypeInfo(0, LANG_NEUTRAL, pptinfo); |
+ } |
+ |
+ STDMETHOD(GetGUID)(DWORD guid_kind, GUID* guid) { |
+ if(guid == NULL || guid_kind != GUIDKIND_DEFAULT_SOURCE_DISP_IID) |
+ return E_INVALIDARG; |
+ |
+ *guid = source_iid; |
+ |
+ return S_OK; |
+ } |
+ |
+ protected: |
+ TypeInfoHolder<class_id> type_info_; |
+}; |
+ |
+} // namespace com_util |
+ |
+#endif // CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_ |