com_type_info_holder.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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#include "chrome_frame/com_type_info_holder.h"
6
7#include "base/lazy_instance.h"
8#include "base/logging.h"
9
10extern "C" IMAGE_DOS_HEADER __ImageBase;
11
12namespace com_util {
13
14base::LazyInstance<TypeInfoCache> type_info_cache = LAZY_INSTANCE_INITIALIZER;
15
16// TypeInfoCache
17
18TypeInfoCache::~TypeInfoCache() {
19  CacheMap::iterator it = cache_.begin();
20  while (it != cache_.end()) {
21    delete it->second;
22    it++;
23  }
24}
25
26TypeInfoNameCache* TypeInfoCache::Lookup(const IID* iid) {
27  DCHECK(Singleton() == this);
28
29  TypeInfoNameCache* tih = NULL;
30
31  base::AutoLock lock(lock_);
32  CacheMap::iterator it = cache_.find(iid);
33  if (it == cache_.end()) {
34    tih = new TypeInfoNameCache();
35    HRESULT hr = tih ? tih->Initialize(*iid) : E_OUTOFMEMORY;
36    if (SUCCEEDED(hr)) {
37      cache_[iid] = tih;
38    } else {
39      NOTREACHED();
40      delete tih;
41      tih = NULL;
42    }
43  } else {
44    tih = it->second;
45  }
46
47  return tih;
48}
49
50TypeInfoCache* TypeInfoCache::Singleton() {
51  return type_info_cache.Pointer();
52}
53
54HRESULT TypeInfoNameCache::Initialize(const IID& iid) {
55  DCHECK(type_info_ == NULL);
56
57  wchar_t file_path[MAX_PATH];
58  DWORD path_len = ::GetModuleFileNameW(reinterpret_cast<HMODULE>(&__ImageBase),
59                                        file_path, arraysize(file_path));
60  if (path_len == 0 || path_len == MAX_PATH) {
61    NOTREACHED();
62    return E_UNEXPECTED;
63  }
64
65  base::win::ScopedComPtr<ITypeLib> type_lib;
66  HRESULT hr = LoadTypeLib(file_path, type_lib.Receive());
67  if (SUCCEEDED(hr)) {
68    hr = type_lib->GetTypeInfoOfGuid(iid, type_info_.Receive());
69  }
70
71  return hr;
72}
73
74// TypeInfoNameCache
75
76HRESULT TypeInfoNameCache::GetIDsOfNames(OLECHAR** names, uint32 count,
77                                         DISPID* dispids) {
78  DCHECK(type_info_ != NULL);
79
80  HRESULT hr = S_OK;
81  for (uint32 i = 0; i < count && SUCCEEDED(hr); ++i) {
82    NameToDispIdCache::HashType hash = NameToDispIdCache::Hash(names[i]);
83    if (!cache_.Lookup(hash, &dispids[i])) {
84      hr = type_info_->GetIDsOfNames(&names[i], 1, &dispids[i]);
85      if (SUCCEEDED(hr)) {
86        cache_.Add(hash, dispids[i]);
87      }
88    }
89  }
90
91  return hr;
92}
93
94HRESULT TypeInfoNameCache::Invoke(IDispatch* p, DISPID dispid, WORD flags,
95                                  DISPPARAMS* params, VARIANT* result,
96                                  EXCEPINFO* excepinfo, UINT* arg_err) {
97  DCHECK(type_info_);
98  HRESULT hr = type_info_->Invoke(p, dispid, flags, params, result, excepinfo,
99                                  arg_err);
100  DCHECK(hr != RPC_E_WRONG_THREAD);
101  return hr;
102}
103
104// NameToDispIdCache
105
106bool NameToDispIdCache::Lookup(HashType hash, DISPID* dispid) const {
107  base::AutoLock lock(lock_);
108  const DispidMap::const_iterator it = map_.find(hash);
109  bool found = (it != map_.end());
110  if (found)
111    *dispid = it->second;
112  return found;
113}
114
115void NameToDispIdCache::Add(HashType hash, DISPID dispid) {
116  base::AutoLock lock(lock_);
117  map_[hash] = dispid;
118}
119
120NameToDispIdCache::HashType NameToDispIdCache::Hash(const wchar_t* name) {
121  return LHashValOfName(LANG_NEUTRAL, name);
122}
123
124}  // namespace com_util
125