summaryrefslogtreecommitdiffstats
path: root/chrome_frame/com_type_info_holder.cc
blob: 695d61e9469c7dd072312536cb02f05055317854 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
// 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.

#include "chrome_frame/com_type_info_holder.h"

#include "base/lazy_instance.h"
#include "base/logging.h"

extern "C" IMAGE_DOS_HEADER __ImageBase;

namespace com_util {

base::LazyInstance<TypeInfoCache> type_info_cache(base::LINKER_INITIALIZED);

// TypeInfoCache

TypeInfoCache::~TypeInfoCache() {
  CacheMap::iterator it = cache_.begin();
  while (it != cache_.end()) {
    delete it->second;
    it++;
  }
}

TypeInfoNameCache* TypeInfoCache::Lookup(const IID* iid) {
  DCHECK(Singleton() == this);

  TypeInfoNameCache* tih = NULL;

  base::AutoLock lock(lock_);
  CacheMap::iterator it = cache_.find(iid);
  if (it == cache_.end()) {
    tih = new TypeInfoNameCache();
    HRESULT hr = tih ? tih->Initialize(*iid) : E_OUTOFMEMORY;
    if (SUCCEEDED(hr)) {
      cache_[iid] = tih;
    } else {
      NOTREACHED();
      delete tih;
      tih = NULL;
    }
  } else {
    tih = it->second;
  }

  return tih;
}

TypeInfoCache* TypeInfoCache::Singleton() {
  return type_info_cache.Pointer();
}

HRESULT TypeInfoNameCache::Initialize(const IID& iid) {
  DCHECK(type_info_ == NULL);

  wchar_t file_path[MAX_PATH];
  DWORD path_len = ::GetModuleFileNameW(reinterpret_cast<HMODULE>(&__ImageBase),
                                        file_path, arraysize(file_path));
  if (path_len == 0 || path_len == MAX_PATH) {
    NOTREACHED();
    return E_UNEXPECTED;
  }

  ScopedComPtr<ITypeLib> type_lib;
  HRESULT hr = LoadTypeLib(file_path, type_lib.Receive());
  if (SUCCEEDED(hr)) {
    hr = type_lib->GetTypeInfoOfGuid(iid, type_info_.Receive());
  }

  return hr;
}

// TypeInfoNameCache

HRESULT TypeInfoNameCache::GetIDsOfNames(OLECHAR** names, uint32 count,
                                         DISPID* dispids) {
  DCHECK(type_info_ != NULL);

  HRESULT hr = S_OK;
  for (uint32 i = 0; i < count && SUCCEEDED(hr); ++i) {
    NameToDispIdCache::HashType hash = NameToDispIdCache::Hash(names[i]);
    if (!cache_.Lookup(hash, &dispids[i])) {
      hr = type_info_->GetIDsOfNames(&names[i], 1, &dispids[i]);
      if (SUCCEEDED(hr)) {
        cache_.Add(hash, dispids[i]);
      }
    }
  }

  return hr;
}

HRESULT TypeInfoNameCache::Invoke(IDispatch* p, DISPID dispid, WORD flags,
                                  DISPPARAMS* params, VARIANT* result,
                                  EXCEPINFO* excepinfo, UINT* arg_err) {
  DCHECK(type_info_);
  HRESULT hr = type_info_->Invoke(p, dispid, flags, params, result, excepinfo,
                                  arg_err);
  DCHECK(hr != RPC_E_WRONG_THREAD);
  return hr;
}

// NameToDispIdCache

bool NameToDispIdCache::Lookup(HashType hash, DISPID* dispid) const {
  base::AutoLock lock(lock_);
  const DispidMap::const_iterator it = map_.find(hash);
  bool found = (it != map_.end());
  if (found)
    *dispid = it->second;
  return found;
}

void NameToDispIdCache::Add(HashType hash, DISPID dispid) {
  base::AutoLock lock(lock_);
  map_[hash] = dispid;
}

NameToDispIdCache::HashType NameToDispIdCache::Hash(const wchar_t* name) {
  return LHashValOfName(LANG_NEUTRAL, name);
}

}  // namespace com_util