15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <ocidl.h>  // IProvideClassInfo2
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/synchronization/lock.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/scoped_comptr.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NO_VTABLE __declspec(novtable)
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace com_util {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A map from a name hash (32 bit value) to a DISPID.
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Used as a caching layer before looking the name up in a type lib.
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NameToDispIdCache {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef uint32 HashType;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool Lookup(HashType hash, DISPID* dispid) const;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Add(HashType hash, DISPID dispid);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Hashes the name by calling LHashValOfName.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The returned hash value is independent of the case of the characters
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // in |name|.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static HashType Hash(const wchar_t* name);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<HashType, DISPID> DispidMap;
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DispidMap map_;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  mutable base::Lock lock_;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Wraps an instance of ITypeInfo and builds+maintains a cache of names
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to dispids.  Also offers an Invoke method that simply forwards the call
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to ITypeInfo::Invoke.
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TypeInfoNameCache {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Loads the module's type library and fetches the ITypeInfo object for
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the specified interface ID.
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT Initialize(const IID& iid);
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Fetches the id's of the given names.  If there's a cache miss, the results
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // are fetched from the underlying ITypeInfo and then cached.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT GetIDsOfNames(OLECHAR** names, uint32 count, DISPID* dispids);
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Calls ITypeInfo::Invoke.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT Invoke(IDispatch* p, DISPID dispid, WORD flags, DISPPARAMS* params,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 VARIANT* result, EXCEPINFO* excepinfo, UINT* arg_err);
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  inline ITypeInfo* CopyTypeInfo() {
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ITypeInfo* ti = type_info_.get();
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (ti)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ti->AddRef();
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return ti;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::win::ScopedComPtr<ITypeInfo> type_info_;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  NameToDispIdCache cache_;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The root class for type lib access.
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class has only one instance that should be accessed via the
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Singleton method.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TypeInfoCache {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoCache() {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ~TypeInfoCache();
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Looks up a previously cached TypeInfoNameCache instance or creates and
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // caches a new one.
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoNameCache* Lookup(const IID* iid);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Call to get access to the singleton instance of TypeInfoCache.
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static TypeInfoCache* Singleton();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef std::map<const IID*, TypeInfoNameCache*> CacheMap;
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  base::Lock lock_;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CacheMap cache_;
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Holds a pointer to the type info of a given COM interface.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The type info is loaded once on demand and after that cached.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: This class only supports loading the first typelib from the
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// current module.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <const IID& iid>
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class TypeInfoHolder {
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoHolder() : type_info_(NULL) {
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool EnsureTI() {
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!type_info_)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      type_info_ = TypeInfoCache::Singleton()->Lookup(&iid);
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_ != NULL;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT GetTypeInfo(UINT itinfo, LCID lcid, ITypeInfo** info) {
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (EnsureTI()) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      *info = type_info_->CopyTypeInfo();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return S_OK;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return E_UNEXPECTED;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT GetIDsOfNames(REFIID riid, OLECHAR** names, UINT count, LCID lcid,
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        DISPID* dispids) {
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!EnsureTI())
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_UNEXPECTED;
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_->GetIDsOfNames(names, count, dispids);
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  HRESULT Invoke(IDispatch* p, DISPID dispid, REFIID riid, LCID lcid,
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 WORD flags, DISPPARAMS* params, VARIANT* result,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 EXCEPINFO* excepinfo, UINT* arg_err) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!EnsureTI())
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_UNEXPECTED;
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_->Invoke(p, dispid, flags, params, result, excepinfo,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              arg_err);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoNameCache* type_info_;
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Implements IDispatch part of T (where T is an IDispatch derived interface).
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The class assumes that the type info of T is available in a typelib of the
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// current module.
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <class T, const IID& iid = __uuidof(T)>
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NO_VTABLE IDispatchImpl : public T {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetTypeInfoCount)(UINT* count) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (count == NULL)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_POINTER;
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *count = 1;
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetTypeInfo)(UINT itinfo, LCID lcid, ITypeInfo** pptinfo) {
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_.GetTypeInfo(itinfo, lcid, pptinfo);
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR* names, UINT count,
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           LCID lcid, DISPID* dispids) {
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_.GetIDsOfNames(riid, names, count, lcid, dispids);
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD flags,
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    DISPPARAMS* params, VARIANT* result, EXCEPINFO* excepinfo,
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    UINT* arg_err) {
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_.Invoke(static_cast<IDispatch*>(this), dispid, riid, lcid,
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             flags, params, result, excepinfo, arg_err);
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoHolder<iid> type_info_;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Simple implementation of IProvideClassInfo[2].
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)template <const CLSID& class_id, const IID& source_iid>
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class NO_VTABLE IProvideClassInfo2Impl : public IProvideClassInfo2 {
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetClassInfo)(ITypeInfo** pptinfo) {
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return type_info_.GetTypeInfo(0, LANG_NEUTRAL, pptinfo);
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  STDMETHOD(GetGUID)(DWORD guid_kind, GUID* guid) {
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (guid == NULL || guid_kind != GUIDKIND_DEFAULT_SOURCE_DISP_IID)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return E_INVALIDARG;
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *guid = source_iid;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return S_OK;
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  TypeInfoHolder<class_id> type_info_;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace com_util
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // CHROME_FRAME_COM_TYPE_INFO_HOLDER_H_
192