2015-04-13 12:09:26 -04:00
|
|
|
// Licensed to the Software Freedom Conservancy (SFC) under one
|
|
|
|
|
// or more contributor license agreements. See the NOTICE file
|
|
|
|
|
// distributed with this work for additional information
|
|
|
|
|
// regarding copyright ownership. The SFC licenses this file
|
|
|
|
|
// to you under the Apache License, Version 2.0 (the "License");
|
2013-05-01 13:12:27 -04:00
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
//
|
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
|
|
#include "AsyncScriptExecutor.h"
|
2017-02-14 09:48:56 -08:00
|
|
|
|
2013-05-01 13:12:27 -04:00
|
|
|
#include <vector>
|
2017-02-14 09:48:56 -08:00
|
|
|
|
2013-05-01 13:12:27 -04:00
|
|
|
#include "errorcodes.h"
|
|
|
|
|
#include "logging.h"
|
2017-02-14 09:48:56 -08:00
|
|
|
|
2018-02-07 12:04:43 -08:00
|
|
|
#include "Element.h"
|
|
|
|
|
#include "ElementRepository.h"
|
2013-05-01 13:12:27 -04:00
|
|
|
#include "Script.h"
|
2018-02-07 12:04:43 -08:00
|
|
|
#include "StringUtilities.h"
|
2019-01-18 15:54:41 -08:00
|
|
|
#include "WebDriverConstants.h"
|
2013-05-01 13:12:27 -04:00
|
|
|
|
|
|
|
|
namespace webdriver {
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnInit(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnInit";
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnCreate(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnCreate";
|
|
|
|
|
|
|
|
|
|
CREATESTRUCT* create = reinterpret_cast<CREATESTRUCT*>(lParam);
|
|
|
|
|
AsyncScriptExecutorThreadContext* context = reinterpret_cast<AsyncScriptExecutorThreadContext*>(create->lpCreateParams);
|
|
|
|
|
|
|
|
|
|
this->script_source_code_ = context->script_source;
|
|
|
|
|
this->script_argument_count_ = context->script_argument_count;
|
|
|
|
|
this->script_argument_index_ = 0;
|
2018-02-07 12:04:43 -08:00
|
|
|
std::wstring serialized_args = context->serialized_script_args;
|
|
|
|
|
this->main_element_repository_handle_ = context->main_element_repository_handle;
|
|
|
|
|
if (serialized_args.size() > 0) {
|
2018-03-22 13:55:29 -07:00
|
|
|
std::string parse_errors;
|
|
|
|
|
std::stringstream json_stream;
|
|
|
|
|
json_stream.str(StringUtilities::ToString(serialized_args));
|
|
|
|
|
Json::parseFromStream(Json::CharReaderBuilder(),
|
|
|
|
|
json_stream,
|
|
|
|
|
&this->script_args_,
|
|
|
|
|
&parse_errors);
|
|
|
|
|
|
2018-02-07 12:04:43 -08:00
|
|
|
if (this->script_args_.isArray()) {
|
|
|
|
|
this->GetElementIdList(this->script_args_);
|
|
|
|
|
this->script_argument_count_ = this->script_args_.size();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this->main_element_repository_handle_ = NULL;
|
|
|
|
|
this->script_args_ = Json::Value::null;
|
|
|
|
|
}
|
2013-05-01 13:12:27 -04:00
|
|
|
// Calling vector::resize() is okay here, because the vector
|
|
|
|
|
// should be empty when Initialize() is called, and the
|
|
|
|
|
// reallocation of variants shouldn't give us too much of a
|
|
|
|
|
// negative impact.
|
|
|
|
|
this->script_arguments_.resize(this->script_argument_count_);
|
|
|
|
|
this->status_code_ = WD_SUCCESS;
|
|
|
|
|
this->is_execution_completed_ = false;
|
|
|
|
|
this->is_listener_attached_ = true;
|
2018-02-07 12:04:43 -08:00
|
|
|
this->element_repository_ = new ElementRepository();
|
|
|
|
|
this->polling_script_source_code_ = L"";
|
2013-05-01 13:12:27 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnClose(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnClose";
|
|
|
|
|
this->DestroyWindow();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnDestroy(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncAtomExecutor::OnDestroy";
|
2018-02-07 12:04:43 -08:00
|
|
|
delete this->element_repository_;
|
2013-05-01 13:12:27 -04:00
|
|
|
::PostQuitMessage(0);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnSetDocument(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnSetDocument";
|
|
|
|
|
CComPtr<IHTMLDocument2> doc;
|
|
|
|
|
LPSTREAM initializer_payload = reinterpret_cast<LPSTREAM>(lParam);
|
|
|
|
|
HRESULT hr = ::CoGetInterfaceAndReleaseStream(initializer_payload,
|
|
|
|
|
IID_IHTMLDocument2,
|
|
|
|
|
reinterpret_cast<void**>(&this->script_host_));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-07 12:04:43 -08:00
|
|
|
LRESULT AsyncScriptExecutor::OnSetElementArgument(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnSetElementArgument";
|
|
|
|
|
ElementInfo* info = reinterpret_cast<ElementInfo*>(lParam);
|
|
|
|
|
std::string element_id = info->element_id;
|
|
|
|
|
std::vector<std::string>::iterator item = std::find(this->element_id_list_.begin(),
|
|
|
|
|
this->element_id_list_.end(),
|
|
|
|
|
element_id);
|
|
|
|
|
if (item == this->element_id_list_.end()) {
|
|
|
|
|
LOG(WARN) << "Invalid element ID sent from main repository: " << element_id;
|
|
|
|
|
}
|
|
|
|
|
CComPtr<IHTMLElement> element;
|
|
|
|
|
::CoGetInterfaceAndReleaseStream(info->element_stream,
|
|
|
|
|
IID_IHTMLElement,
|
|
|
|
|
reinterpret_cast<void**>(&element));
|
|
|
|
|
delete info;
|
|
|
|
|
ElementHandle element_handle(new Element(element, NULL, element_id));
|
|
|
|
|
this->element_repository_->AddManagedElement(element_handle);
|
|
|
|
|
this->element_id_list_.erase(item);
|
|
|
|
|
return WD_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnGetRequiredElementList(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnGetRequiredElementList";
|
|
|
|
|
Json::Value element_id_list(Json::arrayValue);
|
|
|
|
|
std::vector<std::string>::const_iterator it = this->element_id_list_.begin();
|
2018-02-21 05:49:29 -08:00
|
|
|
for (; it != this->element_id_list_.end(); ++it) {
|
2018-02-07 12:04:43 -08:00
|
|
|
element_id_list.append(*it);
|
2013-05-01 13:12:27 -04:00
|
|
|
}
|
2018-03-22 13:55:29 -07:00
|
|
|
Json::StreamWriterBuilder writer;
|
|
|
|
|
std::string serialized_element_list = Json::writeString(writer, element_id_list);
|
2018-02-07 12:04:43 -08:00
|
|
|
std::string* return_string = reinterpret_cast<std::string*>(lParam);
|
|
|
|
|
*return_string = serialized_element_list.c_str();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnIsExecutionReady(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnIsExecutionReady";
|
|
|
|
|
return this->element_id_list_.size() == 0 ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnSetPollingScript(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnSetPollingScript";
|
|
|
|
|
LPCTSTR polling_script = reinterpret_cast<LPCTSTR>(lParam);
|
|
|
|
|
std::wstring script(polling_script);
|
|
|
|
|
this->polling_script_source_code_ = script;
|
2013-05-01 13:12:27 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnExecuteScript(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnExecuteScript";
|
|
|
|
|
Script script_to_execute(this->script_host_,
|
|
|
|
|
this->script_source_code_,
|
|
|
|
|
this->script_argument_count_);
|
2018-02-07 12:04:43 -08:00
|
|
|
this->status_code_ = script_to_execute.AddArguments(this,
|
|
|
|
|
this->script_args_);
|
|
|
|
|
|
|
|
|
|
if (this->status_code_ == WD_SUCCESS) {
|
|
|
|
|
this->status_code_ = script_to_execute.Execute();
|
2013-05-01 13:12:27 -04:00
|
|
|
}
|
2018-02-01 16:08:30 -08:00
|
|
|
|
2013-05-01 13:12:27 -04:00
|
|
|
if (!this->is_listener_attached_) {
|
|
|
|
|
::PostMessage(this->m_hWnd, WM_CLOSE, NULL, NULL);
|
2018-02-01 16:08:30 -08:00
|
|
|
} else {
|
2018-02-21 05:49:29 -08:00
|
|
|
if (this->status_code_ == WD_SUCCESS) {
|
|
|
|
|
if (this->polling_script_source_code_.size() > 0) {
|
|
|
|
|
bool polling_script_succeeded = this->WaitForPollingScript();
|
|
|
|
|
if (!polling_script_succeeded) {
|
|
|
|
|
// The polling script either detected a page reload, or it timed out.
|
|
|
|
|
// In either case, this script execution is completed.
|
|
|
|
|
this->is_execution_completed_ = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
this->status_code_ = script_to_execute.ConvertResultToJsonValue(this,
|
|
|
|
|
&this->script_result_);
|
|
|
|
|
}
|
|
|
|
|
if (this->element_id_list_.size() > 0) {
|
|
|
|
|
// There are newly discovered elements to be managed, and they
|
|
|
|
|
// need to be marshaled back to the main executor thread. Note
|
|
|
|
|
// that we return without setting execution complete, because
|
|
|
|
|
// execution isn't done until the marshalling is done.
|
|
|
|
|
TransferReturnedElements();
|
2018-02-07 12:04:43 -08:00
|
|
|
return 0;
|
|
|
|
|
}
|
2018-10-01 10:10:49 -07:00
|
|
|
} else {
|
|
|
|
|
if (script_to_execute.ResultIsString()) {
|
|
|
|
|
script_to_execute.ConvertResultToJsonValue(this,
|
|
|
|
|
&this->script_result_);
|
|
|
|
|
}
|
2018-02-07 12:04:43 -08:00
|
|
|
}
|
2013-05-01 13:12:27 -04:00
|
|
|
}
|
2018-02-01 16:08:30 -08:00
|
|
|
this->is_execution_completed_ = true;
|
2013-05-01 13:12:27 -04:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnDetachListener(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnDetachListener";
|
|
|
|
|
this->is_listener_attached_ = false;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnIsExecutionComplete(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
return this->is_execution_completed_ ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LRESULT AsyncScriptExecutor::OnGetResult(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnGetResult";
|
|
|
|
|
// NOTE: We need to tell this window to close itself. If and when marshaling
|
|
|
|
|
// of the actual variant result to the calling thread is implemented, posting
|
|
|
|
|
// the message to close the window will have to be moved to the method that
|
|
|
|
|
// retrieves the marshaled result.
|
2018-02-07 12:04:43 -08:00
|
|
|
if (this->main_element_repository_handle_ != NULL) {
|
|
|
|
|
Json::Value* result = reinterpret_cast<Json::Value*>(lParam);
|
|
|
|
|
*result = this->script_result_;
|
|
|
|
|
} else {
|
|
|
|
|
::PostMessage(this->m_hWnd, WM_CLOSE, NULL, NULL);
|
|
|
|
|
}
|
2013-05-01 13:12:27 -04:00
|
|
|
return this->status_code_;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-07 12:04:43 -08:00
|
|
|
LRESULT AsyncScriptExecutor::OnNotifyElementTransferred(UINT uMsg,
|
|
|
|
|
WPARAM wParam,
|
|
|
|
|
LPARAM lParam,
|
|
|
|
|
BOOL& bHandled) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::OnNotifyElementTransferred";
|
2018-02-21 05:49:29 -08:00
|
|
|
RemappedElementInfo* info = reinterpret_cast<RemappedElementInfo*>(lParam);
|
2018-02-07 12:04:43 -08:00
|
|
|
std::string element_id = info->element_id;
|
2018-02-21 05:49:29 -08:00
|
|
|
std::string original_element_id = info->original_element_id;
|
2018-02-07 12:04:43 -08:00
|
|
|
delete info;
|
2018-02-21 05:49:29 -08:00
|
|
|
this->ReplaceTransferredElementResult(original_element_id, element_id, &this->script_result_);
|
|
|
|
|
std::vector<std::string>::const_iterator item = std::find(this->element_id_list_.begin(),
|
|
|
|
|
this->element_id_list_.end(),
|
|
|
|
|
original_element_id);
|
2018-02-07 12:04:43 -08:00
|
|
|
this->element_id_list_.erase(item);
|
|
|
|
|
if (this->element_id_list_.size() == 0) {
|
|
|
|
|
this->is_execution_completed_ = true;
|
|
|
|
|
}
|
|
|
|
|
return WD_SUCCESS;
|
|
|
|
|
}
|
2018-02-21 05:49:29 -08:00
|
|
|
void AsyncScriptExecutor::ReplaceTransferredElementResult(std::string original_element_id,
|
|
|
|
|
std::string element_id,
|
|
|
|
|
Json::Value* result) {
|
|
|
|
|
if (result->isArray()) {
|
|
|
|
|
for (Json::ArrayIndex i = 0; i < result->size(); ++i) {
|
|
|
|
|
this->ReplaceTransferredElementResult(original_element_id,
|
|
|
|
|
element_id,
|
|
|
|
|
&((*result)[i]));
|
|
|
|
|
}
|
|
|
|
|
} else if (result->isObject()) {
|
|
|
|
|
if (result->isMember(JSON_ELEMENT_PROPERTY_NAME) &&
|
|
|
|
|
(*result)[JSON_ELEMENT_PROPERTY_NAME] == original_element_id) {
|
|
|
|
|
(*result)[JSON_ELEMENT_PROPERTY_NAME] = element_id;
|
|
|
|
|
} else {
|
|
|
|
|
std::vector<std::string> member_names = result->getMemberNames();
|
|
|
|
|
std::vector<std::string>::const_iterator it = member_names.begin();
|
|
|
|
|
for (; it != member_names.end(); ++it) {
|
|
|
|
|
this->ReplaceTransferredElementResult(original_element_id,
|
|
|
|
|
element_id,
|
|
|
|
|
&((*result)[*it]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-02-07 12:04:43 -08:00
|
|
|
|
|
|
|
|
int AsyncScriptExecutor::GetManagedElement(const std::string& element_id,
|
|
|
|
|
ElementHandle* element_wrapper) const {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::GetManagedElement";
|
|
|
|
|
return this->element_repository_->GetManagedElement(element_id,
|
|
|
|
|
element_wrapper);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AsyncScriptExecutor::AddManagedElement(IHTMLElement* element,
|
|
|
|
|
ElementHandle* element_wrapper) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::AddManagedElement";
|
|
|
|
|
bool is_new_element = this->element_repository_->AddManagedElement(NULL,
|
|
|
|
|
element,
|
|
|
|
|
element_wrapper);
|
|
|
|
|
if (is_new_element) {
|
|
|
|
|
this->element_id_list_.push_back((*element_wrapper)->element_id());
|
|
|
|
|
}
|
|
|
|
|
return is_new_element;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AsyncScriptExecutor::RemoveManagedElement(const std::string& element_id) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::RemoveManagedElement";
|
|
|
|
|
this->element_repository_->RemoveManagedElement(element_id);
|
|
|
|
|
|
|
|
|
|
// Simply forward on the request to remove the element from the
|
|
|
|
|
// main element repository. We shouldn't need to worry about waiting
|
|
|
|
|
// for the removal to be processed; it should be scheduled to happen
|
|
|
|
|
// before the next command can arrive.
|
|
|
|
|
ElementInfo* info = new ElementInfo;
|
|
|
|
|
info->element_id = element_id.c_str();
|
|
|
|
|
::PostMessage(this->main_element_repository_handle_,
|
|
|
|
|
WD_ASYNC_SCRIPT_SCHEDULE_REMOVE_MANAGED_ELEMENT,
|
|
|
|
|
NULL,
|
|
|
|
|
reinterpret_cast<LPARAM>(info));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AsyncScriptExecutor::GetElementIdList(const Json::Value& json_object) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::GetElementIdList";
|
|
|
|
|
if (json_object.isArray()) {
|
|
|
|
|
for (unsigned int i = 0; i < json_object.size(); ++i) {
|
|
|
|
|
GetElementIdList(json_object[i]);
|
|
|
|
|
}
|
|
|
|
|
} else if (json_object.isObject()) {
|
|
|
|
|
if (json_object.isMember(JSON_ELEMENT_PROPERTY_NAME)) {
|
|
|
|
|
// Capture the ID of any element in the arg list, and
|
|
|
|
|
std::string element_id;
|
|
|
|
|
element_id = json_object[JSON_ELEMENT_PROPERTY_NAME].asString();
|
|
|
|
|
this->element_id_list_.push_back(element_id);
|
|
|
|
|
} else {
|
|
|
|
|
std::vector<std::string> property_names = json_object.getMemberNames();
|
|
|
|
|
std::vector<std::string>::const_iterator it = property_names.begin();
|
2018-02-21 05:49:29 -08:00
|
|
|
for (; it != property_names.end(); ++it) {
|
|
|
|
|
this->GetElementIdList(json_object[*it]);
|
2018-02-07 12:04:43 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AsyncScriptExecutor::TransferReturnedElements() {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::TransferReturnedElements";
|
|
|
|
|
std::vector<std::string>::const_iterator it = this->element_id_list_.begin();
|
2018-02-21 05:49:29 -08:00
|
|
|
for (; it != this->element_id_list_.end(); ++it) {
|
2018-02-07 12:04:43 -08:00
|
|
|
std::string element_id = *it;
|
|
|
|
|
ElementHandle element_handle;
|
|
|
|
|
this->element_repository_->GetManagedElement(element_id,
|
|
|
|
|
&element_handle);
|
|
|
|
|
ElementInfo* info = new ElementInfo;
|
|
|
|
|
info->element_id = element_id.c_str();
|
|
|
|
|
::CoMarshalInterThreadInterfaceInStream(IID_IHTMLElement,
|
|
|
|
|
element_handle->element(),
|
|
|
|
|
&info->element_stream);
|
|
|
|
|
::PostMessage(this->main_element_repository_handle_,
|
|
|
|
|
WD_ASYNC_SCRIPT_TRANSFER_MANAGED_ELEMENT,
|
|
|
|
|
NULL,
|
|
|
|
|
reinterpret_cast<LPARAM>(info));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool AsyncScriptExecutor::WaitForPollingScript(void) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::WaitForPollingScript";
|
|
|
|
|
Script polling_script(this->script_host_, this->polling_script_source_code_, 0);
|
|
|
|
|
while (this->is_listener_attached_ && this->status_code_ == WD_SUCCESS) {
|
|
|
|
|
int polling_status_code = polling_script.Execute();
|
|
|
|
|
if (polling_status_code != WD_SUCCESS) {
|
|
|
|
|
this->status_code_ = EUNEXPECTEDJSERROR;
|
|
|
|
|
this->script_result_ = "Page reload detected during async script";
|
|
|
|
|
} else {
|
|
|
|
|
Json::Value polling_script_result;
|
|
|
|
|
polling_script.ConvertResultToJsonValue(this, &polling_script_result);
|
|
|
|
|
if (!polling_script_result.isObject()) {
|
|
|
|
|
this->status_code_ = EUNEXPECTEDJSERROR;
|
|
|
|
|
this->script_result_ = "Polling script did not return expected object";
|
|
|
|
|
}
|
|
|
|
|
if (!polling_script_result.isMember("status")) {
|
|
|
|
|
this->status_code_ = EUNEXPECTEDJSERROR;
|
|
|
|
|
this->script_result_ = "Polling script did not return expected object";
|
|
|
|
|
}
|
|
|
|
|
std::string polling_script_status = polling_script_result["status"].asString();
|
|
|
|
|
if (polling_script_status == "reload") {
|
|
|
|
|
this->status_code_ = EUNEXPECTEDJSERROR;
|
|
|
|
|
this->script_result_ = "Page reload detected during async script";
|
|
|
|
|
}
|
|
|
|
|
if (polling_script_status == "timeout") {
|
|
|
|
|
this->status_code_ = ESCRIPTTIMEOUT;
|
|
|
|
|
this->script_result_ = "Timeout expired waiting for async script";
|
|
|
|
|
}
|
|
|
|
|
if (polling_script_status == "complete") {
|
|
|
|
|
this->status_code_ = WD_SUCCESS;
|
|
|
|
|
this->script_result_ = polling_script_result["value"];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return this->status_code_ == WD_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-01 13:12:27 -04:00
|
|
|
unsigned int WINAPI AsyncScriptExecutor::ThreadProc(LPVOID lpParameter) {
|
|
|
|
|
LOG(TRACE) << "Entering AsyncScriptExecutor::ThreadProc";
|
|
|
|
|
|
|
|
|
|
AsyncScriptExecutorThreadContext* thread_context = reinterpret_cast<AsyncScriptExecutorThreadContext*>(lpParameter);
|
|
|
|
|
HWND window_handle = thread_context->hwnd;
|
|
|
|
|
|
|
|
|
|
DWORD error = 0;
|
|
|
|
|
HRESULT hr = ::CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
|
|
|
if (FAILED(hr)) {
|
|
|
|
|
LOGHR(DEBUG, hr) << "COM library initialization has some problem";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AsyncScriptExecutor async_executor;
|
|
|
|
|
HWND async_executor_window_handle = async_executor.Create(/*HWND*/ HWND_MESSAGE,
|
|
|
|
|
/*_U_RECT rect*/ CWindow::rcDefault,
|
|
|
|
|
/*LPCTSTR szWindowName*/ NULL,
|
|
|
|
|
/*DWORD dwStyle*/ NULL,
|
|
|
|
|
/*DWORD dwExStyle*/ NULL,
|
|
|
|
|
/*_U_MENUorID MenuOrID*/ 0U,
|
|
|
|
|
/*LPVOID lpCreateParam*/ reinterpret_cast<LPVOID*>(thread_context));
|
|
|
|
|
if (async_executor_window_handle == NULL) {
|
|
|
|
|
LOGERR(WARN) << "Unable to create new AsyncScriptExecutor";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MSG msg;
|
|
|
|
|
::PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
|
|
|
|
|
|
|
|
|
|
// Return the HWND back through lpParameter, and signal that the
|
|
|
|
|
// window is ready for messages.
|
|
|
|
|
thread_context->hwnd = async_executor_window_handle;
|
2018-02-07 12:04:43 -08:00
|
|
|
HANDLE event_handle = ::OpenEvent(EVENT_ALL_ACCESS,
|
|
|
|
|
FALSE,
|
|
|
|
|
ASYNC_SCRIPT_EVENT_NAME);
|
2013-05-01 13:12:27 -04:00
|
|
|
if (event_handle != NULL) {
|
|
|
|
|
::SetEvent(event_handle);
|
|
|
|
|
::CloseHandle(event_handle);
|
|
|
|
|
} else {
|
|
|
|
|
LOGERR(DEBUG) << "Unable to signal that window is ready";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run the message loop
|
|
|
|
|
while (::GetMessage(&msg, NULL, 0, 0) > 0) {
|
|
|
|
|
::TranslateMessage(&msg);
|
|
|
|
|
::DispatchMessage(&msg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
::CoUninitialize();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // namespace webdriver
|