3131#include " BrowserFactory.h"
3232#include " CommandExecutor.h"
3333#include " CommandHandlerRepository.h"
34+ #include " Element.h"
3435#include " ElementFinder.h"
3536#include " ElementRepository.h"
3637#include " IECommandHandler.h"
3738#include " InputManager.h"
3839#include " HtmlDialog.h"
3940#include " ProxyManager.h"
4041#include " StringUtilities.h"
42+ #include " Script.h"
4143
4244namespace webdriver {
4345
@@ -350,6 +352,71 @@ LRESULT IECommandExecutor::OnGetQuitStatus(UINT uMsg,
350352 return this ->is_quitting_ && this ->managed_browsers_ .size () > 0 ? 1 : 0 ;
351353}
352354
355+ LRESULT IECommandExecutor::OnScriptWait (UINT uMsg,
356+ WPARAM wParam,
357+ LPARAM lParam,
358+ BOOL& bHandled) {
359+ LOG (TRACE) << " Entering IECommandExecutor::OnScriptWait" ;
360+
361+ BrowserHandle browser;
362+ int status_code = this ->GetCurrentBrowser (&browser);
363+ if (status_code == WD_SUCCESS && !browser->is_closing ()) {
364+ if (this ->async_script_timeout_ >= 0 && this ->wait_timeout_ < clock ()) {
365+ ::SendMessage (browser->script_executor_handle (), WD_ASYNC_SCRIPT_DETACH_LISTENTER, NULL, NULL);
366+ Response timeout_response;
367+ timeout_response.SetErrorResponse(ERROR_SCRIPT_TIMEOUT, " Timed out waiting for script to complete." );
368+ this ->serialized_response_ = timeout_response.Serialize ();
369+ this ->is_waiting_ = false ;
370+ browser->set_script_executor_handle (NULL );
371+ } else {
372+ HWND alert_handle;
373+ bool is_execution_finished = ::SendMessage (browser->script_executor_handle (), WD_ASYNC_SCRIPT_IS_EXECUTION_COMPLETE, NULL , NULL ) != 0 ;
374+ bool is_alert_active = this ->IsAlertActive (browser, &alert_handle);
375+ this ->is_waiting_ = !is_execution_finished && !is_alert_active;
376+ if (this ->is_waiting_ ) {
377+ // If we are still waiting, we need to wait a bit then post a message to
378+ // ourselves to run the wait again. However, we can't wait using Sleep()
379+ // on this thread. This call happens in a message loop, and we would be
380+ // unable to process the COM events in the browser if we put this thread
381+ // to sleep.
382+ unsigned int thread_id = 0 ;
383+ HANDLE thread_handle = reinterpret_cast <HANDLE>(_beginthreadex (NULL ,
384+ 0 ,
385+ &IECommandExecutor::ScriptWaitThreadProc,
386+ (void *)this ->m_hWnd ,
387+ 0 ,
388+ &thread_id));
389+ if (thread_handle != NULL ) {
390+ ::CloseHandle (thread_handle);
391+ } else {
392+ LOGERR (DEBUG) << " Unable to create waiter thread" ;
393+ }
394+ } else {
395+ Response response;
396+ ::SendMessage (browser->script_executor_handle (), WD_ASYNC_SCRIPT_DETACH_LISTENTER, NULL, NULL);
397+ int status_code = static_cast <int >(::SendMessage(browser->script_executor_handle (), WD_ASYNC_SCRIPT_GET_RESULT, NULL, NULL));
398+ if (status_code != WD_SUCCESS) {
399+ response.SetErrorResponse (status_code, " Error executing JavaScript" );
400+ } else {
401+ CComPtr<IHTMLDocument2> doc;
402+ browser->GetDocument (&doc);
403+ Script result_retrieval_script (doc,
404+ " (function() { return function(){ return window.document.__webdriver_script_result; };})();" ,
405+ 0 );
406+ status_code = result_retrieval_script.Execute ();
407+ Json::Value script_result;
408+ result_retrieval_script.ConvertResultToJsonValue (*this , &script_result);
409+ response.SetSuccessResponse (script_result);
410+ }
411+ this ->serialized_response_ = response.Serialize ();
412+ }
413+ }
414+ } else {
415+ this ->is_waiting_ = false ;
416+ }
417+ return 0 ;
418+ }
419+
353420LRESULT IECommandExecutor::OnRefreshManagedElements (UINT uMsg,
354421 WPARAM wParam,
355422 LPARAM lParam,
@@ -374,6 +441,39 @@ LRESULT IECommandExecutor::OnHandleUnexpectedAlerts(UINT uMsg,
374441 return 0 ;
375442}
376443
444+ LRESULT IECommandExecutor::OnGetManagedElement (UINT uMsg,
445+ WPARAM wParam,
446+ LPARAM lParam,
447+ BOOL& bHandled) {
448+ ElementInfo* info = reinterpret_cast <ElementInfo*>(lParam);
449+ ElementHandle element_handle;
450+ int status_code = this ->GetManagedElement (info->element_id , &element_handle);
451+ if (status_code == WD_SUCCESS) {
452+ info->element = element_handle->element ();
453+ }
454+ return status_code;
455+ }
456+
457+ LRESULT IECommandExecutor::OnAddManagedElement (UINT uMsg,
458+ WPARAM wParam,
459+ LPARAM lParam,
460+ BOOL& bHandled) {
461+ ElementInfo* info = reinterpret_cast <ElementInfo*>(lParam);
462+ ElementHandle element_handle;
463+ this ->AddManagedElement (info->element , &element_handle);
464+ info->element_id = element_handle->element_id ();
465+ return WD_SUCCESS;
466+ }
467+
468+ LRESULT IECommandExecutor::OnRemoveManagedElement (UINT uMsg,
469+ WPARAM wParam,
470+ LPARAM lParam,
471+ BOOL& bHandled) {
472+ ElementInfo* info = reinterpret_cast <ElementInfo*>(lParam);
473+ this ->RemoveManagedElement (info->element_id );
474+ return WD_SUCCESS;
475+ }
476+
377477unsigned int WINAPI IECommandExecutor::WaitThreadProc (LPVOID lpParameter) {
378478 LOG (TRACE) << " Entering IECommandExecutor::WaitThreadProc" ;
379479 HWND window_handle = reinterpret_cast <HWND>(lpParameter);
@@ -382,6 +482,13 @@ unsigned int WINAPI IECommandExecutor::WaitThreadProc(LPVOID lpParameter) {
382482 return 0 ;
383483}
384484
485+ unsigned int WINAPI IECommandExecutor::ScriptWaitThreadProc (LPVOID lpParameter) {
486+ LOG (TRACE) << " Entering IECommandExecutor::ScriptWaitThreadProc" ;
487+ HWND window_handle = reinterpret_cast <HWND>(lpParameter);
488+ ::Sleep (WAIT_TIME_IN_MILLISECONDS);
489+ ::PostMessage (window_handle, WD_SCRIPT_WAIT, NULL , NULL );
490+ return 0 ;
491+ }
385492
386493unsigned int WINAPI IECommandExecutor::ThreadProc (LPVOID lpParameter) {
387494 LOG (TRACE) << " Entering IECommandExecutor::ThreadProc" ;
@@ -522,6 +629,16 @@ void IECommandExecutor::DispatchCommand() {
522629 this ->wait_timeout_ = clock () + (static_cast <int >(this ->page_load_timeout_ ) / 1000 * CLOCKS_PER_SEC);
523630 }
524631 ::PostMessage (this ->m_hWnd, WD_WAIT, NULL , NULL );
632+ } else {
633+ HWND script_executor_handle = browser->script_executor_handle ();
634+ this ->is_waiting_ = script_executor_handle != NULL ;
635+ if (this ->is_waiting_ ) {
636+ if (this ->async_script_timeout_ >= 0 ) {
637+ this ->wait_timeout_ = clock () + (static_cast <int >(this ->async_script_timeout_ ) / 1000 * CLOCKS_PER_SEC);
638+ }
639+ ::PostMessage (this ->m_hWnd, WD_SCRIPT_WAIT, NULL , NULL );
640+ return ;
641+ }
525642 }
526643 } else {
527644 if (this ->current_command_ .command_type () != webdriver::CommandType::Quit) {
@@ -677,7 +794,37 @@ int IECommandExecutor::CreateNewBrowser(std::string* error_message) {
677794int IECommandExecutor::GetManagedElement (const std::string& element_id,
678795 ElementHandle* element_wrapper) const {
679796 LOG (TRACE) << " Entering IECommandExecutor::GetManagedElement" ;
680- return this ->managed_elements_ ->GetManagedElement (element_id, element_wrapper);
797+ ElementHandle candidate_wrapper;
798+ int result = this ->managed_elements_ ->GetManagedElement (element_id, &candidate_wrapper);
799+ if (result != WD_SUCCESS) {
800+ LOG (WARN) << " Unable to get managed element, element not found" ;
801+ return result;
802+ } else {
803+ if (!candidate_wrapper->IsAttachedToDom ()) {
804+ LOG (WARN) << " Found managed element is no longer valid" ;
805+ this ->managed_elements_ ->RemoveManagedElement (element_id);
806+ return EOBSOLETEELEMENT;
807+ } else {
808+ // If the element is attached to the DOM, validate that its document
809+ // is the currently-focused document (via frames).
810+ BrowserHandle current_browser;
811+ this ->GetCurrentBrowser (¤t_browser);
812+ CComPtr<IHTMLDocument2> focused_doc;
813+ current_browser->GetDocument (&focused_doc);
814+
815+ CComPtr<IDispatch> parent_doc_dispatch;
816+ candidate_wrapper->element ()->get_document (&parent_doc_dispatch);
817+
818+ if (focused_doc.IsEqualObject (parent_doc_dispatch)) {
819+ *element_wrapper = candidate_wrapper;
820+ return WD_SUCCESS;
821+ } else {
822+ LOG (WARN) << " Found managed element's document is not currently focused" ;
823+ }
824+ }
825+ }
826+
827+ return EOBSOLETEELEMENT;
681828}
682829
683830void IECommandExecutor::AddManagedElement (IHTMLElement* element,
0 commit comments