Skip to content

Commit 03bd468

Browse files
committed
Implementing driver implementation autodetect in IE driver server
1 parent 810e67a commit 03bd468

6 files changed

+76
-13
lines changed

cpp/iedriver/BrowserFactory.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828
namespace webdriver {
2929

3030
BrowserFactory::BrowserFactory(void) {
31+
// Must be done in the constructor. Do not move to Initialize().
32+
this->GetExecutableLocation();
33+
this->GetIEVersion();
34+
this->GetOSVersion();
3135
}
3236

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

50-
this->GetExecutableLocation();
51-
this->GetIEVersion();
52-
this->GetOSVersion();
5354
this->html_getobject_msg_ = ::RegisterWindowMessage(HTML_GETOBJECT_MSG);
5455

5556
// Explicitly load MSAA so we know if it's installed

cpp/iedriver/IESession.cpp

+21-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
// limitations under the License.
1313

1414
#include "IESession.h"
15+
#include "BrowserFactory.h"
1516
#include "CommandExecutor.h"
1617
#include "IECommandExecutor.h"
1718
#include "IEWebDriverManagerCommandExecutor.h"
@@ -71,7 +72,26 @@ void IESession::Initialize(void* init_params) {
7172

7273
ThreadProcedure thread_proc = &IECommandExecutor::ThreadProc;
7374
if (this->driver_implementation_ != LegacyImplementation) {
74-
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
75+
BrowserFactory factory;
76+
int browser_version = factory.browser_version();
77+
bool is_component_registered = IEWebDriverManagerCommandExecutor::IsComponentRegistered();
78+
if (this->driver_implementation_ == VendorImplementation) {
79+
LOG(DEBUG) << "Attempting to use vendor-provided driver implementation per user request";
80+
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
81+
} else if (this->driver_implementation_ == AutoDetectImplementation &&
82+
browser_version >= 11 &&
83+
is_component_registered) {
84+
LOG(DEBUG) << "Using vendor-provided driver implementation per autodetection";
85+
thread_proc = &IEWebDriverManagerCommandExecutor::ThreadProc;
86+
} else {
87+
LOG(DEBUG) << "Falling back to legacy driver implementation per autodetection ("
88+
<< "detected IE version: " << browser_version
89+
<< ", vendor driver install is "
90+
<< (is_component_registered ? "" : "not")
91+
<< " registered).";
92+
}
93+
} else {
94+
LOG(DEBUG) << "Using legacy driver implementation per user request";
7595
}
7696
HANDLE thread_handle = reinterpret_cast<HANDLE>(_beginthreadex(NULL,
7797
0,

cpp/iedriver/IEWebDriverManagerCommandExecutor.cpp

+33-9
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "interactions.h"
2020
#include "json.h"
2121
#include "logging.h"
22+
#include "RegistryUtilities.h"
2223
#include "StringUtilities.h"
2324

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

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

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

225230
void IEWebDriverManagerCommandExecutor::DispatchCommand() {
226231
LOG(TRACE) << "Entering IEWebDriverManagerCommandExecutor::DispatchCommand";
227-
std::wstring serialized_command = StringUtilities::ToWString(this->current_command_.Serialize());
232+
Response actual_response;
233+
if (this->current_command_.command_type() == CommandType::NewSession && !this->is_valid_) {
234+
// Despite our best efforts, we've attempted to create a new session,
235+
// but the IEWebDriverManager COM object could not be instantiated.
236+
// The most common case of this would be when the user has attempted
237+
// to force the use of the Microsoft driver implementation, but it's
238+
// not installed, or is not installed properly. So we have to throw
239+
// an error at this point.
240+
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.");
241+
} else {
242+
std::wstring serialized_command = StringUtilities::ToWString(this->current_command_.Serialize());
228243

229-
LPWSTR pszResult = nullptr;
244+
LPWSTR pszResult = nullptr;
230245

231-
HRESULT hr = this->manager_->ExecuteCommand((LPWSTR)serialized_command.c_str(), &pszResult);
232-
std::wstring result(pszResult);
233-
Response actual_response;
234-
actual_response.Deserialize(StringUtilities::ToString(result));
246+
HRESULT hr = this->manager_->ExecuteCommand((LPWSTR)serialized_command.c_str(), &pszResult);
247+
std::wstring result(pszResult);
248+
actual_response.Deserialize(StringUtilities::ToString(result));
249+
::CoTaskMemFree(pszResult);
250+
}
235251
this->serialized_response_ = actual_response.Serialize();
236-
::CoTaskMemFree(pszResult);
237252

238253
if (this->current_command_.command_type() == webdriver::CommandType::Close ||
239254
this->current_command_.command_type() == webdriver::CommandType::Quit) {
240255
this->is_valid_ = false;
241256
}
242257
}
243258

259+
bool IEWebDriverManagerCommandExecutor::IsComponentRegistered() {
260+
LPOLESTR webdriver_class_id;
261+
::StringFromCLSID(CLSID_IEWebDriverManager, &webdriver_class_id);
262+
std::wstring subkey(L"CLSID\\");
263+
subkey.append(webdriver_class_id);
264+
::CoTaskMemFree(webdriver_class_id);
265+
return RegistryUtilities::RegistryKeyExists(HKEY_CLASSES_ROOT, subkey);
266+
}
267+
244268
} // namespace webdriver

cpp/iedriver/IEWebDriverManagerCommandExecutor.h

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class IEWebDriverManagerCommandExecutor : public CWindowImpl<IEWebDriverManagerC
5757
std::string session_id(void) const { return this->session_id_; }
5858

5959
static unsigned int WINAPI ThreadProc(LPVOID lpParameter);
60+
static bool IsComponentRegistered(void);
6061

6162
std::string current_browser_id(void) const {
6263
return this->current_browser_id_;

cpp/iedriver/RegistryUtilities.cpp

+15
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,19 @@ bool RegistryUtilities::GetRegistryValue(const HKEY root_key,
113113
return value_retrieved;
114114
}
115115

116+
bool RegistryUtilities::RegistryKeyExists(HKEY root_key,
117+
const std::wstring& subkey) {
118+
HKEY key_handle;
119+
long registry_call_result = ::RegOpenKeyEx(root_key,
120+
subkey.c_str(),
121+
0,
122+
KEY_QUERY_VALUE,
123+
&key_handle);
124+
bool result = (ERROR_SUCCESS == registry_call_result);
125+
if (result) {
126+
::RegCloseKey(key_handle);
127+
}
128+
return result;
129+
}
130+
116131
} // namespace webdriver

cpp/iedriver/RegistryUtilities.h

+2
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ class RegistryUtilities {
2727
const std::wstring& subkey,
2828
const std::wstring& value_name,
2929
std::wstring* value);
30+
static bool RegistryKeyExists(const HKEY root_key,
31+
const std::wstring& subkey);
3032
};
3133

3234
} // namespace webdriver

0 commit comments

Comments
 (0)