Exemple #1
0
bool Element::GetFrameDetails(LocationInfo* location, std::vector<LocationInfo>* frame_locations) {
  LOG(TRACE) << "Entering Element::GetFrameDetails";

  CComPtr<IHTMLDocument2> owner_doc;
  int status_code = this->GetContainingDocument(true, &owner_doc);
  if (status_code != WD_SUCCESS) {
    LOG(WARN) << "Unable to get containing document";
    return false;
  }

  CComPtr<IHTMLWindow2> owner_doc_window;
  HRESULT hr = owner_doc->get_parentWindow(&owner_doc_window);
  if (!owner_doc_window) {
    LOG(WARN) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed";
    return false;
  }

  // Get the parent window to the current window, where "current window" is
  // the window containing the parent document of this element. If that parent
  // window exists, and it is not the same as the current window, we assume
  // this element exists inside a frame or iframe. If it is in a frame, get
  // the parent document containing the frame, so we can get the information
  // about the frame or iframe element hosting the document of this element.
  CComPtr<IHTMLWindow2> parent_window;
  hr = owner_doc_window->get_parent(&parent_window);
  if (parent_window && !owner_doc_window.IsEqualObject(parent_window)) {
    LOG(DEBUG) << "Element is in a frame.";
    CComPtr<IHTMLDocument2> parent_doc;
    status_code = this->GetDocumentFromWindow(parent_window, &parent_doc);

    CComPtr<IHTMLFramesCollection2> frames;
    hr = parent_doc->get_frames(&frames);

    long frame_count(0);
    hr = frames->get_length(&frame_count);
    CComVariant index;
    index.vt = VT_I4;
    for (long i = 0; i < frame_count; ++i) {
      // See if the document in each frame is this element's 
      // owner document.
      index.lVal = i;
      CComVariant result;
      hr = frames->item(&index, &result);
      CComPtr<IHTMLWindow2> frame_window;
      result.pdispVal->QueryInterface<IHTMLWindow2>(&frame_window);
      if (!frame_window) {
        // Frame is not an HTML frame.
        continue;
      }

      CComPtr<IHTMLDocument2> frame_doc;
      status_code = this->GetDocumentFromWindow(frame_window, &frame_doc);

      if (frame_doc.IsEqualObject(owner_doc)) {
        // The document in this frame *is* this element's owner
        // document. Get the frameElement property of the document's
        // containing window (which is itself an HTML element, either
        // a frame or an iframe). Then get the x and y coordinates of
        // that frame element.
        // N.B. We must use JavaScript here, as directly using
        // IHTMLWindow4.get_frameElement() returns E_NOINTERFACE under
        // some circumstances.
        LOG(DEBUG) << "Located host frame. Attempting to get hosting element";
        std::wstring script_source = L"(function(){ return function() { return arguments[0].frameElement };})();";
        Script script_wrapper(frame_doc, script_source, 1);
        CComVariant window_variant(frame_window);
        script_wrapper.AddArgument(window_variant);
        status_code = script_wrapper.Execute();
        CComPtr<IHTMLFrameBase> frame_base;
        if (status_code == WD_SUCCESS) {
          hr = script_wrapper.result().pdispVal->QueryInterface<IHTMLFrameBase>(&frame_base);
          if (FAILED(hr)) {
            LOG(WARN) << "Found the frame element, but could not QueryInterface to IHTMLFrameBase.";
          }
        } else {
          // Can't get the frameElement property, likely because the frames are from different
          // domains. So start at the parent document, and use getElementsByTagName to retrieve
          // all of the iframe elements (if there are no iframe elements, get the frame elements)
          // **** BIG HUGE ASSUMPTION!!! ****
          // The index of the frame from the document.frames collection will correspond to the 
          // index into the collection of iframe/frame elements returned by getElementsByTagName.
          LOG(WARN) << "Attempting to get frameElement via JavaScript failed. "
                    << "This usually means the frame is in a different domain than the parent frame. "
                    << "Browser security against cross-site scripting attacks will not allow this. "
                    << "Attempting alternative method.";
          long collection_count = 0;
          CComPtr<IDispatch> element_dispatch;
          CComPtr<IHTMLDocument3> doc;
          parent_doc->QueryInterface<IHTMLDocument3>(&doc);
          if (doc) {
            LOG(DEBUG) << "Looking for <iframe> elements in parent document.";
            CComBSTR iframe_tag_name = L"iframe";
            CComPtr<IHTMLElementCollection> iframe_collection;
            hr = doc->getElementsByTagName(iframe_tag_name, &iframe_collection);
            hr = iframe_collection->get_length(&collection_count);
            if (collection_count != 0) {
              if (collection_count > index.lVal) {
                LOG(DEBUG) << "Found <iframe> elements in parent document, retrieving element" << index.lVal << ".";
                hr = iframe_collection->item(index, index, &element_dispatch);
                hr = element_dispatch->QueryInterface<IHTMLFrameBase>(&frame_base);
              }
            } else {
              LOG(DEBUG) << "No <iframe> elements, looking for <frame> elements in parent document.";
              CComBSTR frame_tag_name = L"frame";
              CComPtr<IHTMLElementCollection> frame_collection;
              hr = doc->getElementsByTagName(frame_tag_name, &frame_collection);
              hr = frame_collection->get_length(&collection_count);
              if (collection_count > index.lVal) {
                LOG(DEBUG) << "Found <frame> elements in parent document, retrieving element" << index.lVal << ".";
                hr = frame_collection->item(index, index, &element_dispatch);
                hr = element_dispatch->QueryInterface<IHTMLFrameBase>(&frame_base);
              }
            }
          } else {
            LOG(WARN) << "QueryInterface of parent document to IHTMLDocument3 failed.";
          }
        }

        if (frame_base) {
          LOG(DEBUG) << "Successfully found frame hosting element";
          LocationInfo frame_doc_info;
          bool doc_dimensions_success = DocumentHost::GetDocumentDimensions(
              frame_doc,
              &frame_doc_info);

          // Wrap the element so we can find its location. Note that
          // GetLocation() may recursively call into this method.
          CComPtr<IHTMLElement> frame_element;
          frame_base->QueryInterface<IHTMLElement>(&frame_element);
          Element element_wrapper(frame_element, this->containing_window_handle_);
          CComPtr<IHTMLStyle> style;
          frame_element->get_style(&style);

          LocationInfo frame_location = {};
          status_code = element_wrapper.GetLocation(&frame_location,
                                                    frame_locations);

          // Take the border of the frame element into account.
          // N.B. We don't have to do this for non-frame elements,
          // because the border is part of the hit-test region. For
          // finding offsets to get absolute position of elements 
          // within frames, the origin of the frame document is offset
          // by the border width.
          CComPtr<IHTMLElement2> border_width_element;
          frame_element->QueryInterface<IHTMLElement2>(&border_width_element);
          long left_border_width = 0;
          border_width_element->get_clientLeft(&left_border_width);
          long top_border_width = 0;
          border_width_element->get_clientTop(&top_border_width);

          if (status_code == WD_SUCCESS) {
            // Take into account the presence of scrollbars in the frame.
            long frame_element_width = frame_location.width;
            long frame_element_height = frame_location.height;
            if (doc_dimensions_success) {
              if (frame_doc_info.height > frame_element_height) {
                int horizontal_scrollbar_height = ::GetSystemMetrics(SM_CYHSCROLL);
                frame_element_height -= horizontal_scrollbar_height;
              }
              if (frame_doc_info.width > frame_element_width) {
                int vertical_scrollbar_width = ::GetSystemMetrics(SM_CXVSCROLL);
                frame_element_width -= vertical_scrollbar_width;
              }
            }
            location->x = frame_location.x + left_border_width;
            location->y = frame_location.y + top_border_width;
            location->width = frame_element_width;
            location->height = frame_element_height;
          }
          return true;
        }
      }
    }
  }

  // If we reach here, the element isn't in a frame/iframe.
  return false;
}
Exemple #2
0
int Script::Execute() {
  LOG(TRACE) << "Entering Script::Execute";

  CComVariant result = L"";
  CComBSTR error_description = L"";

  if (this->script_engine_host_ == NULL) {
    LOG(WARN) << "Script engine host is NULL";
    return ENOSUCHDOCUMENT;
  }
  CComVariant temp_function;
  if (!this->CreateAnonymousFunction(&temp_function)) {
    LOG(WARN) << "Cannot create anonymous function";
    return EUNEXPECTEDJSERROR;
  }

  if (temp_function.vt != VT_DISPATCH) {
    LOG(DEBUG) << "No return value that we care about";
    return WD_SUCCESS;
  }

  // Grab the "call" method out of the returned function
  DISPID call_member_id;
  OLECHAR FAR* call_member_name = L"call";
  HRESULT hr = temp_function.pdispVal->GetIDsOfNames(IID_NULL,
                                                     &call_member_name,
                                                     1,
                                                     LOCALE_USER_DEFAULT,
                                                     &call_member_id);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Cannot locate call method on anonymous function";
    return EUNEXPECTEDJSERROR;
  }

  CComPtr<IHTMLWindow2> win;
  hr = this->script_engine_host_->get_parentWindow(&win);
  if (FAILED(hr)) {
    LOGHR(WARN, hr) << "Cannot get parent window, IHTMLDocument2::get_parentWindow failed";
    return EUNEXPECTEDJSERROR;
  }

  // IDispatch::Invoke() expects the arguments to be passed into it
  // in reverse order. To accomplish this, we create a new variant
  // array of size n + 1 where n is the number of arguments we have.
  // we copy each element of arguments_array_ into the new array in
  // reverse order, and add an extra argument, the window object,
  // to the end of the array to use as the "this" parameter for the
  // function invocation.
  size_t arg_count = this->argument_array_.size();
  std::vector<CComVariant> argument_array_copy(arg_count + 1);
  CComVariant window_variant(win);
  argument_array_copy[arg_count].Copy(&window_variant);

  for (size_t index = 0; index < arg_count; ++index) {
    argument_array_copy[arg_count - 1 - index].Copy(&this->argument_array_[index]);
  }

  DISPPARAMS call_parameters = { 0 };
  memset(&call_parameters, 0, sizeof call_parameters);
  call_parameters.cArgs = static_cast<unsigned int>(argument_array_copy.size());
  call_parameters.rgvarg = &argument_array_copy[0];

  int return_code = WD_SUCCESS;
  EXCEPINFO exception;
  memset(&exception, 0, sizeof exception);
  hr = temp_function.pdispVal->Invoke(call_member_id,
                                      IID_NULL,
                                      LOCALE_USER_DEFAULT,
                                      DISPATCH_METHOD,
                                      &call_parameters, 
                                      &result,
                                      &exception,
                                      0);

  if (FAILED(hr)) {
    if (DISP_E_EXCEPTION == hr) {
      error_description = exception.bstrDescription ? exception.bstrDescription : L"EUNEXPECTEDJSERROR";
      CComBSTR error_source(exception.bstrSource ? exception.bstrSource : L"EUNEXPECTEDJSERROR");
      LOG(INFO) << "Exception message was: '" << error_description << "'";
      LOG(INFO) << "Exception source was: '" << error_source << "'";
    } else {
      LOGHR(DEBUG, hr) << "Failed to execute anonymous function, no exception information retrieved";
    }

    result.Clear();
    result.vt = VT_BSTR;
    result.bstrVal = error_description;
    return_code = EUNEXPECTEDJSERROR;
  }

  this->result_.Copy(&result);

  return return_code;
}
Exemple #3
0
int Element::GetFrameOffset(long* x, long* y) {
  LOG(TRACE) << "Entering Element::GetFrameOffset";

  CComPtr<IHTMLDocument2> owner_doc;
  int status_code = this->GetContainingDocument(true, &owner_doc);
  if (status_code != SUCCESS) {
    LOG(WARN) << "Unable to get containing document";
    return status_code;
  }

  CComPtr<IHTMLWindow2> owner_doc_window;
  HRESULT hr = owner_doc->get_parentWindow(&owner_doc_window);
  if (!owner_doc_window) {
    LOG(WARN) << "Unable to get parent window, call to IHTMLDocument2::get_parentWindow failed";
    return ENOSUCHDOCUMENT;
  }

  CComPtr<IHTMLWindow2> parent_window;
  hr = owner_doc_window->get_parent(&parent_window);
  if (parent_window && !owner_doc_window.IsEqualObject(parent_window)) {
    CComPtr<IHTMLDocument2> parent_doc;
    status_code = this->GetParentDocument(parent_window, &parent_doc);

    CComPtr<IHTMLFramesCollection2> frames;
    hr = parent_doc->get_frames(&frames);

    long frame_count(0);
    hr = frames->get_length(&frame_count);
    CComVariant index;
    index.vt = VT_I4;
    for (long i = 0; i < frame_count; ++i) {
      // See if the document in each frame is this element's 
      // owner document.
      index.lVal = i;
      CComVariant result;
      hr = frames->item(&index, &result);
      CComQIPtr<IHTMLWindow2> frame_window(result.pdispVal);
      if (!frame_window) {
        // Frame is not an HTML frame.
        continue;
      }

      CComPtr<IHTMLDocument2> frame_doc;
      hr = frame_window->get_document(&frame_doc);

      if (frame_doc.IsEqualObject(owner_doc)) {
        // The document in this frame *is* this element's owner
        // document. Get the frameElement property of the document's
        // containing window (which is itself an HTML element, either
        // a frame or an iframe). Then get the x and y coordinates of
        // that frame element.
        std::wstring script_source = L"(function(){ return function() { return arguments[0].frameElement };})();";
        Script script_wrapper(frame_doc, script_source, 1);
        CComVariant window_variant(frame_window);
        script_wrapper.AddArgument(window_variant);
        script_wrapper.Execute();
        CComQIPtr<IHTMLElement> frame_element(script_wrapper.result().pdispVal);

        // Wrap the element so we can find its location.
        Element element_wrapper(frame_element, this->containing_window_handle_);
        long frame_x, frame_y, frame_width, frame_height;
        status_code = element_wrapper.GetLocation(&frame_x,
                                                  &frame_y,
                                                  &frame_width,
                                                  &frame_height);
        if (status_code == SUCCESS) {
          *x = frame_x;
          *y = frame_y;
        }
        break;
      }
    }
  }

  return SUCCESS;
}