普通文本  |  162行  |  5.26 KB

// 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;
}