Skip to content

Commit

Permalink
Implementing driver implementation autodetect in IE driver server
Browse files Browse the repository at this point in the history
  • Loading branch information
jimevans committed Sep 11, 2014
1 parent 810e67a commit 03bd468
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 13 deletions.
7 changes: 4 additions & 3 deletions cpp/iedriver/BrowserFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@
namespace webdriver {

BrowserFactory::BrowserFactory(void) {
// Must be done in the constructor. Do not move to Initialize().
this->GetExecutableLocation();
this->GetIEVersion();
this->GetOSVersion();
}

BrowserFactory::~BrowserFactory(void) {
Expand All @@ -47,9 +51,6 @@ void BrowserFactory::Initialize(BrowserFactorySettings settings) {
this->browser_command_line_switches_ = StringUtilities::ToWString(settings.browser_command_line_switches);
this->initial_browser_url_ = StringUtilities::ToWString(settings.initial_browser_url);

this->GetExecutableLocation();
this->GetIEVersion();
this->GetOSVersion();
this->html_getobject_msg_ = ::RegisterWindowMessage(HTML_GETOBJECT_MSG);

// Explicitly load MSAA so we know if it's installed
Expand Down
22 changes: 21 additions & 1 deletion cpp/iedriver/IESession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
// limitations under the License.

#include "IESession.h"
#include "BrowserFactory.h"
#include "CommandExecutor.h"
#include "IECommandExecutor.h"
#include "IEWebDriverManagerCommandExecutor.h"
Expand Down Expand Up @@ -71,7 +72,26 @@ void IESession::Initialize(void* init_params) {

ThreadProcedure thread_proc = &IECommandExecutor::ThreadProc;
if (this->driver_implementation_ != LegacyImplementation) {
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
BrowserFactory factory;
int browser_version = factory.browser_version();
bool is_component_registered = IEWebDriverManagerCommandExecutor::IsComponentRegistered();
if (this->driver_implementation_ == VendorImplementation) {
LOG(DEBUG) << "Attempting to use vendor-provided driver implementation per user request";
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
} else if (this->driver_implementation_ == AutoDetectImplementation &&
browser_version >= 11 &&
is_component_registered) {
LOG(DEBUG) << "Using vendor-provided driver implementation per autodetection";
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
} else {
LOG(DEBUG) << "Falling back to legacy driver implementation per autodetection ("
<< "detected IE version: " << browser_version
<< ", vendor driver install is "
<< (is_component_registered ? "" : "not")
<< " registered).";
}
} else {
LOG(DEBUG) << "Using legacy driver implementation per user request";
}
HANDLE thread_handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL,
0,
Expand Down
42 changes: 33 additions & 9 deletions cpp/iedriver/IEWebDriverManagerCommandExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "interactions.h"
#include "json.h"
#include "logging.h"
#include "RegistryUtilities.h"
#include "StringUtilities.h"

namespace webdriver {
Expand Down Expand Up @@ -63,8 +64,11 @@ LRESULT IEWebDriverManagerCommandExecutor::OnCreate(UINT uMsg,
IID_IIEWebDriverManager,
reinterpret_cast<void**>(&this->manager_));
if (FAILED(hr)) {
// TOOD: Handle the case where the COM object is not installed.
// If the COM object isn't installed, or there is another error, mark the
// session as invalid. In theory, we should only hit this issue if we're
// forcing the
LOGHR(WARN, hr) << "Could not create instance of class IEWebDriverManager";
this->is_valid_ = false;
}

return 0;
Expand All @@ -78,6 +82,7 @@ LRESULT IEWebDriverManagerCommandExecutor::OnDestroy(UINT uMsg,

LOG(DEBUG) << "Posting quit message";
this->manager_.Release();
delete this->factory_;
::PostQuitMessage(0);
LOG(DEBUG) << "Leaving IEWebDriverManagerCommandExecutor::OnDestroy";
return 0;
Expand Down Expand Up @@ -108,7 +113,7 @@ LRESULT IEWebDriverManagerCommandExecutor::OnGetResponseLength(UINT uMsg,
WPARAM wParam,
LPARAM lParam,
BOOL& bHandled) {
// Not logging trace entering IEDevChannelCommandExecutor::OnGetResponseLength,
// Not logging trace entering IEWebDriverManagerCommandExecutor::OnGetResponseLength,
// because it is polled repeatedly for a non-zero return value.
size_t response_length = 0;
if (!this->is_waiting_) {
Expand Down Expand Up @@ -224,21 +229,40 @@ unsigned int WINAPI IEWebDriverManagerCommandExecutor::ThreadProc(LPVOID lpParam

void IEWebDriverManagerCommandExecutor::DispatchCommand() {
LOG(TRACE) << "Entering IEWebDriverManagerCommandExecutor::DispatchCommand";
std::wstring serialized_command = StringUtilities::ToWString(this->current_command_.Serialize());
Response actual_response;
if (this->current_command_.command_type() == CommandType::NewSession && !this->is_valid_) {
// Despite our best efforts, we've attempted to create a new session,
// but the IEWebDriverManager COM object could not be instantiated.
// The most common case of this would be when the user has attempted
// to force the use of the Microsoft driver implementation, but it's
// not installed, or is not installed properly. So we have to throw
// an error at this point.
actual_response.SetErrorResponse(ENOSUCHDRIVER, "Could not create IEWebDriverManager COM object. The most common cause of this is that the driver tool from Microsoft is not installed properly.");
} else {
std::wstring serialized_command = StringUtilities::ToWString(this->current_command_.Serialize());

LPWSTR pszResult = nullptr;
LPWSTR pszResult = nullptr;

HRESULT hr = this->manager_->ExecuteCommand((LPWSTR)serialized_command.c_str(), &pszResult);
std::wstring result(pszResult);
Response actual_response;
actual_response.Deserialize(StringUtilities::ToString(result));
HRESULT hr = this->manager_->ExecuteCommand((LPWSTR)serialized_command.c_str(), &pszResult);
std::wstring result(pszResult);
actual_response.Deserialize(StringUtilities::ToString(result));
::CoTaskMemFree(pszResult);
}
this->serialized_response_ = actual_response.Serialize();
::CoTaskMemFree(pszResult);

if (this->current_command_.command_type() == webdriver::CommandType::Close ||
this->current_command_.command_type() == webdriver::CommandType::Quit) {
this->is_valid_ = false;
}
}

bool IEWebDriverManagerCommandExecutor::IsComponentRegistered() {
LPOLESTR webdriver_class_id;
::StringFromCLSID(CLSID_IEWebDriverManager, &webdriver_class_id);
std::wstring subkey(L"CLSID\\");
subkey.append(webdriver_class_id);
::CoTaskMemFree(webdriver_class_id);
return RegistryUtilities::RegistryKeyExists(HKEY_CLASSES_ROOT, subkey);
}

} // namespace webdriver
1 change: 1 addition & 0 deletions cpp/iedriver/IEWebDriverManagerCommandExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class IEWebDriverManagerCommandExecutor : public CWindowImpl<IEWebDriverManagerC
std::string session_id(void) const { return this->session_id_; }

static unsigned int WINAPI ThreadProc(LPVOID lpParameter);
static bool IsComponentRegistered(void);

std::string current_browser_id(void) const {
return this->current_browser_id_;
Expand Down
15 changes: 15 additions & 0 deletions cpp/iedriver/RegistryUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,19 @@ bool RegistryUtilities::GetRegistryValue(const HKEY root_key,
return value_retrieved;
}

bool RegistryUtilities::RegistryKeyExists(HKEY root_key,
const std::wstring& subkey) {
HKEY key_handle;
long registry_call_result = ::RegOpenKeyEx(root_key,
subkey.c_str(),
0,
KEY_QUERY_VALUE,
&key_handle);
bool result = (ERROR_SUCCESS == registry_call_result);
if (result) {
::RegCloseKey(key_handle);
}
return result;
}

} // namespace webdriver
2 changes: 2 additions & 0 deletions cpp/iedriver/RegistryUtilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class RegistryUtilities {
const std::wstring& subkey,
const std::wstring& value_name,
std::wstring* value);
static bool RegistryKeyExists(const HKEY root_key,
const std::wstring& subkey);
};

} // namespace webdriver
Expand Down

0 comments on commit 03bd468

Please sign in to comment.