Home | History | Annotate | Download | only in chrome_frame
      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_message_event.h"
      6 
      7 #include "base/logging.h"
      8 #include "base/strings/string_util.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 
     12 ComMessageEvent::ComMessageEvent() {
     13 }
     14 
     15 ComMessageEvent::~ComMessageEvent() {
     16 }
     17 
     18 bool ComMessageEvent::Initialize(IOleContainer* container,
     19                                  const std::string& message,
     20                                  const std::string& origin,
     21                                  const std::string& event_type) {
     22   DLOG_IF(WARNING, !container) << __FUNCTION__ << " no container";
     23   message_ = message;
     24   origin_ = origin;
     25   type_ = event_type;
     26 
     27   // May remain NULL if container not IE
     28   base::win::ScopedComPtr<IHTMLEventObj> basic_event;
     29   base::win::ScopedComPtr<IHTMLDocument2> doc;
     30 
     31   // Fetching doc may fail in non-IE containers
     32   // and container might be NULL in some applications.
     33   if (container)
     34     container->QueryInterface(doc.Receive());
     35   if (doc) {
     36     base::win::ScopedComPtr<IHTMLDocument4> doc4;
     37     doc4.QueryFrom(doc);
     38     DCHECK(doc4);  // supported by IE5.5 and higher
     39     if (doc4) {
     40       // IHTMLEventObj5 is only supported in IE8 and later, so we provide our
     41       // own (minimalistic) implementation of it.
     42       doc4->createEventObject(NULL, basic_event.Receive());
     43       DCHECK(basic_event);
     44     }
     45   }
     46 
     47   basic_event_ = basic_event;
     48   return true;
     49 }
     50 
     51 STDMETHODIMP ComMessageEvent::GetTypeInfoCount(UINT* info) {
     52   // Don't DCHECK as python scripts might still call this function
     53   // inadvertently.
     54   DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
     55   return E_NOTIMPL;
     56 }
     57 
     58 STDMETHODIMP ComMessageEvent::GetTypeInfo(UINT which_info, LCID lcid,
     59                                           ITypeInfo** type_info) {
     60   DLOG(WARNING) << "Not implemented: " << __FUNCTION__;
     61   return E_NOTIMPL;
     62 }
     63 
     64 STDMETHODIMP ComMessageEvent::GetIDsOfNames(REFIID iid, LPOLESTR* names,
     65                                             UINT count_names, LCID lcid,
     66                                             DISPID* dispids) {
     67   HRESULT hr = S_OK;
     68 
     69   // Note that since we're using LowerCaseEqualsASCII for string comparison,
     70   // the second argument _must_ be all lower case.  I.e. we cannot compare
     71   // against L"messagePort" since it has a capital 'P'.
     72   for (UINT i = 0; SUCCEEDED(hr) && i < count_names; ++i) {
     73     const wchar_t* name_begin = names[i];
     74     const wchar_t* name_end = name_begin + wcslen(name_begin);
     75     if (LowerCaseEqualsASCII(name_begin, name_end, "data")) {
     76       dispids[i] = DISPID_MESSAGE_EVENT_DATA;
     77     } else if (LowerCaseEqualsASCII(name_begin, name_end, "origin")) {
     78       dispids[i] = DISPID_MESSAGE_EVENT_ORIGIN;
     79     } else if (LowerCaseEqualsASCII(name_begin, name_end, "lasteventid")) {
     80       dispids[i] = DISPID_MESSAGE_EVENT_LAST_EVENT_ID;
     81     } else if (LowerCaseEqualsASCII(name_begin, name_end, "source")) {
     82       dispids[i] = DISPID_MESSAGE_EVENT_SOURCE;
     83     } else if (LowerCaseEqualsASCII(name_begin, name_end, "messageport")) {
     84       dispids[i] = DISPID_MESSAGE_EVENT_MESSAGE_PORT;
     85     } else if (LowerCaseEqualsASCII(name_begin, name_end, "type")) {
     86       dispids[i] = DISPID_MESSAGE_EVENT_TYPE;
     87     } else {
     88       if (basic_event_) {
     89         hr = basic_event_->GetIDsOfNames(IID_IDispatch, &names[i], 1, lcid,
     90                                          &dispids[i]);
     91       } else {
     92         hr = DISP_E_MEMBERNOTFOUND;
     93       }
     94 
     95       if (FAILED(hr)) {
     96         DLOG(WARNING) << "member not found: " << names[i]
     97                       << base::StringPrintf(L"0x%08X", hr);
     98       }
     99     }
    100   }
    101   return hr;
    102 }
    103 
    104 STDMETHODIMP ComMessageEvent::Invoke(DISPID dispid, REFIID iid, LCID lcid,
    105                                      WORD flags, DISPPARAMS* params,
    106                                      VARIANT* result, EXCEPINFO* excepinfo,
    107                                      UINT* arg_err) {
    108   HRESULT hr = DISP_E_MEMBERNOTFOUND;
    109   switch (dispid) {
    110     case DISPID_MESSAGE_EVENT_DATA:
    111       hr = GetStringProperty(flags, UTF8ToWide(message_).c_str(), result);
    112       break;
    113 
    114     case DISPID_MESSAGE_EVENT_ORIGIN:
    115       hr = GetStringProperty(flags, UTF8ToWide(origin_).c_str(), result);
    116       break;
    117 
    118     case DISPID_MESSAGE_EVENT_TYPE:
    119       hr = GetStringProperty(flags, UTF8ToWide(type_).c_str(), result);
    120       break;
    121 
    122     case DISPID_MESSAGE_EVENT_LAST_EVENT_ID:
    123       hr = GetStringProperty(flags, L"", result);
    124       break;
    125 
    126     case DISPID_MESSAGE_EVENT_SOURCE:
    127     case DISPID_MESSAGE_EVENT_MESSAGE_PORT:
    128       if (flags & DISPATCH_PROPERTYGET) {
    129         result->vt = VT_NULL;
    130         hr = S_OK;
    131       } else {
    132         hr = DISP_E_TYPEMISMATCH;
    133       }
    134       break;
    135 
    136     default:
    137       if (basic_event_) {
    138         hr = basic_event_->Invoke(dispid, iid, lcid, flags, params, result,
    139                                   excepinfo, arg_err);
    140       }
    141       break;
    142   }
    143 
    144   return hr;
    145 }
    146 
    147 HRESULT ComMessageEvent::GetStringProperty(WORD flags, const wchar_t* value,
    148                                            VARIANT* result) {
    149   if (!result)
    150     return E_INVALIDARG;
    151 
    152   HRESULT hr;
    153   if (flags & DISPATCH_PROPERTYGET) {
    154     result->vt = VT_BSTR;
    155     result->bstrVal = ::SysAllocString(value);
    156     hr = S_OK;
    157   } else {
    158     hr = DISP_E_TYPEMISMATCH;
    159   }
    160   return hr;
    161 }
    162