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