| // Copyright (c) 2011 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 = LAZY_INSTANCE_INITIALIZER; |
| |
| // 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; |
| } |
| |
| base::win::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 |