// 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_message_event.h"
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
ComMessageEvent::ComMessageEvent() {
}
ComMessageEvent::~ComMessageEvent() {
}
bool ComMessageEvent::Initialize(IOleContainer* container,
const std::string& message,
const std::string& origin,
const std::string& event_type) {
DLOG_IF(WARNING, !container) << __FUNCTION__ << " no container";
message_ = message;
origin_ = origin;
type_ = event_type;
// May remain NULL if container not IE
base::win::ScopedComPtr<IHTMLEventObj> basic_event;
base::win::ScopedComPtr<IHTMLDocument2> doc;
// Fetching doc may fail in non-IE containers
// and container might be NULL in some applications.
if (container)
container->QueryInterface(doc.Receive());
if (doc) {
base::win::ScopedComPtr<IHTMLDocument4> doc4;
doc4.QueryFrom(doc);
DCHECK(doc4); // supported by IE5.5 and higher
if (doc4) {
// IHTMLEventObj5 is only supported in IE8 and later, so we provide our
// own (minimalistic) implementation of it.
doc4->createEventObject(NULL, basic_event.Receive());
DCHECK(basic_event);
}
}
basic_event_ = basic_event;
return true;
}
STDMETHODIMP ComMessageEvent::GetTypeInfoCount(UINT* info) {
// Don't DCHECK as python scripts might still call this function
// inadvertently.
DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
return E_NOTIMPL;
}
STDMETHODIMP ComMessageEvent::GetTypeInfo(UINT which_info, LCID lcid,
ITypeInfo** type_info) {
DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
return E_NOTIMPL;
}
STDMETHODIMP ComMessageEvent::GetIDsOfNames(REFIID iid, LPOLESTR* names,
UINT count_names, LCID lcid,
DISPID* dispids) {
HRESULT hr = S_OK;
// Note that since we're using LowerCaseEqualsASCII for string comparison,
// the second argument _must_ be all lower case. I.e. we cannot compare
// against L"messagePort" since it has a capital 'P'.
for (UINT i = 0; SUCCEEDED(hr) && i < count_names; ++i) {
const wchar_t* name_begin = names[i];
const wchar_t* name_end = name_begin + wcslen(name_begin);
if (LowerCaseEqualsASCII(name_begin, name_end, "data")) {
dispids[i] = DISPID_MESSAGE_EVENT_DATA;
} else if (LowerCaseEqualsASCII(name_begin, name_end, "origin")) {
dispids[i] = DISPID_MESSAGE_EVENT_ORIGIN;
} else if (LowerCaseEqualsASCII(name_begin, name_end, "lasteventid")) {
dispids[i] = DISPID_MESSAGE_EVENT_LAST_EVENT_ID;
} else if (LowerCaseEqualsASCII(name_begin, name_end, "source")) {
dispids[i] = DISPID_MESSAGE_EVENT_SOURCE;
} else if (LowerCaseEqualsASCII(name_begin, name_end, "messageport")) {
dispids[i] = DISPID_MESSAGE_EVENT_MESSAGE_PORT;
} else if (LowerCaseEqualsASCII(name_begin, name_end, "type")) {
dispids[i] = DISPID_MESSAGE_EVENT_TYPE;
} else {
if (basic_event_) {
hr = basic_event_->GetIDsOfNames(IID_IDispatch, &names[i], 1, lcid,
&dispids[i]);
} else {
hr = DISP_E_MEMBERNOTFOUND;
}
if (FAILED(hr)) {
DLOG(WARNING) << "member not found: " << names[i]
<< base::StringPrintf(L"0x%08X", hr);
}
}
}
return hr;
}
STDMETHODIMP ComMessageEvent::Invoke(DISPID dispid, REFIID iid, LCID lcid,
WORD flags, DISPPARAMS* params,
VARIANT* result, EXCEPINFO* excepinfo,
UINT* arg_err) {
HRESULT hr = DISP_E_MEMBERNOTFOUND;
switch (dispid) {
case DISPID_MESSAGE_EVENT_DATA:
hr = GetStringProperty(flags, UTF8ToWide(message_).c_str(), result);
break;
case DISPID_MESSAGE_EVENT_ORIGIN:
hr = GetStringProperty(flags, UTF8ToWide(origin_).c_str(), result);
break;
case DISPID_MESSAGE_EVENT_TYPE:
hr = GetStringProperty(flags, UTF8ToWide(type_).c_str(), result);
break;
case DISPID_MESSAGE_EVENT_LAST_EVENT_ID:
hr = GetStringProperty(flags, L"", result);
break;
case DISPID_MESSAGE_EVENT_SOURCE:
case DISPID_MESSAGE_EVENT_MESSAGE_PORT:
if (flags & DISPATCH_PROPERTYGET) {
result->vt = VT_NULL;
hr = S_OK;
} else {
hr = DISP_E_TYPEMISMATCH;
}
break;
default:
if (basic_event_) {
hr = basic_event_->Invoke(dispid, iid, lcid, flags, params, result,
excepinfo, arg_err);
}
break;
}
return hr;
}
HRESULT ComMessageEvent::GetStringProperty(WORD flags, const wchar_t* value,
VARIANT* result) {
if (!result)
return E_INVALIDARG;
HRESULT hr;
if (flags & DISPATCH_PROPERTYGET) {
result->vt = VT_BSTR;
result->bstrVal = ::SysAllocString(value);
hr = S_OK;
} else {
hr = DISP_E_TYPEMISMATCH;
}
return hr;
}