void IESession::ShutDown(void) { LOG(TRACE) << "Entering IESession::ShutDown"; // Kill the background thread first - otherwise the IE process crashes. stopPersistentEventFiring(); // Don't terminate the thread until the browsers have all been deallocated. int is_quitting = static_cast<int>(::SendMessage(this->executor_window_handle_, WD_GET_QUIT_STATUS, NULL, NULL)); int retry_count = 50; while (is_quitting > 0 && --retry_count > 0) { ::Sleep(100); is_quitting = static_cast<int>(::SendMessage(this->executor_window_handle_, WD_GET_QUIT_STATUS, NULL, NULL)); } DWORD process_id; DWORD thread_id = ::GetWindowThreadProcessId(this->executor_window_handle_, &process_id); HANDLE thread_handle = ::OpenThread(SYNCHRONIZE, FALSE, thread_id); ::SendMessage(this->executor_window_handle_, WM_CLOSE, NULL, NULL); if (thread_handle != NULL) { DWORD wait_result = ::WaitForSingleObject(thread_handle, 30000); if (wait_result != WAIT_OBJECT_0) { LOG(DEBUG) << "Waiting for thread to end returned " << wait_result; } ::CloseHandle(thread_handle); } }
void IESession::ShutDown(void) { LOG(TRACE) << "Entering IESession::ShutDown"; // Kill the background thread first - otherwise the IE process crashes. stopPersistentEventFiring(); // Don't terminate the thread until the browsers have all been deallocated. // Note: Loop count of 6, because the timeout is 5 seconds, giving us a nice, // round 30 seconds. int retry_count = 6; bool has_quit = this->WaitForCommandExecutorExit(EXECUTOR_EXIT_WAIT_TIMEOUT); while (!has_quit && retry_count > 0) { // ASSUMPTION! If all browsers haven't been deallocated by the timeout // specified, they're blocked from quitting by something. We'll assume // that something is an alert blocking close, and ask the executor to // attempt another close after closing the offending alert. // N.B., this could probably be made more robust by modifying // IECommandExecutor::OnGetQuitStatus(), but that would require some // fairly complex synchronization code, to make sure a browser isn't // deallocated while the "close the alert and close the browser again" // code is still running, since the deallocation happens in response // to the DWebBrowserEvents2::OnQuit event. LOG(DEBUG) << "Not all browsers have been deallocated!"; ::PostMessage(this->executor_window_handle_, WD_HANDLE_UNEXPECTED_ALERTS, NULL, NULL); has_quit = this->WaitForCommandExecutorExit(EXECUTOR_EXIT_WAIT_TIMEOUT); retry_count--; } if (has_quit) { LOG(DEBUG) << "Executor shutdown successful!"; } else { LOG(ERROR) << "Still running browsers after handling alerts! This is likely to lead to a crash."; } DWORD process_id; DWORD thread_id = ::GetWindowThreadProcessId(this->executor_window_handle_, &process_id); HANDLE thread_handle = ::OpenThread(SYNCHRONIZE, FALSE, thread_id); LOG(DEBUG) << "Posting thread shutdown message"; ::PostThreadMessage(thread_id, WD_SHUTDOWN, NULL, NULL); if (thread_handle != NULL) { LOG(DEBUG) << "Starting wait for thread completion"; DWORD wait_result = ::WaitForSingleObject(&thread_handle, 30000); if (wait_result != WAIT_OBJECT_0) { LOG(DEBUG) << "Waiting for thread to end returned " << wait_result; } else { LOG(DEBUG) << "Wait for thread handle complete"; } ::CloseHandle(thread_handle); } }
int IECommandExecutor::CreateNewBrowser(std::string* error_message) { LOG(TRACE) << "Entering IECommandExecutor::CreateNewBrowser"; vector<char> port_buffer(10); _itoa_s(this->port_, &port_buffer[0], 10, 10); std::string port(&port_buffer[0]); std::string initial_url = this->initial_browser_url_; if (this->initial_browser_url_ == "") { initial_url = "http://localhost:" + port + "/"; } DWORD process_id = this->factory_.LaunchBrowserProcess(initial_url, this->ignore_protected_mode_settings_, error_message); if (process_id == NULL) { LOG(WARN) << "Unable to launch browser, received NULL process ID"; this->is_waiting_ = false; return ENOSUCHDRIVER; } ProcessWindowInfo process_window_info; process_window_info.dwProcessId = process_id; process_window_info.hwndBrowser = NULL; process_window_info.pBrowser = NULL; bool attached = this->factory_.AttachToBrowser(&process_window_info, this->browser_attach_timeout_, this->ignore_zoom_setting_, error_message); if (!attached) { LOG(WARN) << "Unable to attach to browser COM object"; this->is_waiting_ = false; return ENOSUCHDRIVER; } // Set persistent hover functionality in the interactions implementation. setEnablePersistentHover(this->enable_persistent_hover_); LOG(INFO) << "Persistent hovering set to: " << this->enable_persistent_hover_; if (!this->enable_persistent_hover_) { LOG(INFO) << "Stopping previously-running persistent event thread."; stopPersistentEventFiring(); } BrowserHandle wrapper(new Browser(process_window_info.pBrowser, process_window_info.hwndBrowser, this->m_hWnd)); this->AddManagedBrowser(wrapper); return WD_SUCCESS; }
void IESession::ShutDown(void) { LOG(TRACE) << "Entering IESession::ShutDown"; // Kill the background thread first - otherwise the IE process crashes. stopPersistentEventFiring(); DWORD process_id; DWORD thread_id = ::GetWindowThreadProcessId(this->executor_window_handle_, &process_id); HANDLE thread_handle = ::OpenThread(SYNCHRONIZE, FALSE, thread_id); ::SendMessage(this->executor_window_handle_, WM_CLOSE, NULL, NULL); if (thread_handle != NULL) { DWORD wait_result = ::WaitForSingleObject(thread_handle, 30000); if (wait_result != WAIT_OBJECT_0) { LOG(DEBUG) << "Waiting for thread to end returned " << wait_result; } ::CloseHandle(thread_handle); } }