1 #include "win32/WebBrowser.h"
2 #include <assert.h>
3 #include <ExDispid.h>
4 #include "filesystem_def.h"
5 
6 using namespace Framework;
7 using namespace Framework::Win32;
8 
9 ULONG				CWebBrowser::g_hookCount = 0;
10 HHOOK				CWebBrowser::g_hookHandle = NULL;
11 std::set<CWindow*>	CWebBrowser::g_hookListeners;
12 
CWebBrowser()13 CWebBrowser::CWebBrowser()
14 : m_adviseCookie(0)
15 {
16 	EnsureIE9ModeIsActivated();
17 }
18 
CWebBrowser(HWND parentWnd,const RECT & rect)19 CWebBrowser::CWebBrowser(HWND parentWnd, const RECT& rect)
20 : CActiveXHost(parentWnd, rect, CLSID_WebBrowser, &WebBrowserClientSiteFactory)
21 , m_adviseCookie(0)
22 {
23 	m_eventSink = CComPtr<CEventSink>(new CEventSink(m_hWnd));
24 
25 	HRESULT result = m_oleObject->QueryInterface(IID_IWebBrowser2, reinterpret_cast<void**>(&m_webBrowser));
26 	assert(SUCCEEDED(result));
27 
28 	{
29 		CComPtr<IConnectionPointContainer> connectionPointContainer;
30 		result = m_oleObject->QueryInterface(IID_IConnectionPointContainer, reinterpret_cast<void**>(&connectionPointContainer));
31 		assert(SUCCEEDED(result));
32 
33 		result = connectionPointContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &m_eventsConnectionPoint);
34 		assert(SUCCEEDED(result));
35 	}
36 
37 	result = m_eventsConnectionPoint->Advise(m_eventSink, &m_adviseCookie);
38 	assert(SUCCEEDED(result));
39 
40 	RegisterFilterHook(this);
41 }
42 
~CWebBrowser()43 CWebBrowser::~CWebBrowser()
44 {
45 	Reset();
46 }
47 
operator =(CWebBrowser && rhs)48 CWebBrowser& CWebBrowser::operator =(CWebBrowser&& rhs)
49 {
50 	Reset();
51 	MoveFrom(std::move(rhs));
52 	return (*this);
53 }
54 
Reset()55 void CWebBrowser::Reset()
56 {
57 	UnregisterFilterHook(this);
58 	if(m_adviseCookie != 0)
59 	{
60 		m_eventsConnectionPoint->Unadvise(m_adviseCookie);
61 		m_adviseCookie = 0;
62 	}
63 	m_eventsConnectionPoint.Reset();
64 	m_webBrowser.Reset();
65 	m_eventSink.Reset();
66 	CActiveXHost::Reset();
67 }
68 
MoveFrom(CWebBrowser && rhs)69 void CWebBrowser::MoveFrom(CWebBrowser&& rhs)
70 {
71 	CActiveXHost::MoveFrom(std::move(rhs));
72 	std::swap(m_webBrowser, rhs.m_webBrowser);
73 	std::swap(m_eventsConnectionPoint, rhs.m_eventsConnectionPoint);
74 	std::swap(m_eventSink, rhs.m_eventSink);
75 	std::swap(m_adviseCookie, rhs.m_adviseCookie);
76 	ExchangeFilterHook(this, &rhs);
77 }
78 
GetDocument()79 CComPtr<IHTMLDocument2> CWebBrowser::GetDocument()
80 {
81 	CComPtr<IDispatch> documentDispatch;
82 	HRESULT result = m_webBrowser->get_Document(&documentDispatch);
83 	if(FAILED(result)) return CComPtr<IHTMLDocument2>();
84 	CComPtr<IHTMLDocument2> document;
85 	result = documentDispatch->QueryInterface(IID_IHTMLDocument2, reinterpret_cast<void**>(&document));
86 	if(FAILED(result)) return CComPtr<IHTMLDocument2>();
87 	return document;
88 }
89 
Navigate(const TCHAR * url)90 void CWebBrowser::Navigate(const TCHAR* url)
91 {
92 	auto cvtUrl = SysAllocString(url);
93 	HRESULT result = m_webBrowser->Navigate(cvtUrl, 0, 0, 0, 0);
94 	assert(SUCCEEDED(result));
95 	SysFreeString(cvtUrl);
96 }
97 
Stop()98 void CWebBrowser::Stop()
99 {
100 	HRESULT result = m_webBrowser->Stop();
101 	assert(SUCCEEDED(result));
102 }
103 
EnsureIE9ModeIsActivated()104 void CWebBrowser::EnsureIE9ModeIsActivated()
105 {
106 	HKEY emulationKey = 0;
107 	auto result = RegCreateKeyEx(HKEY_CURRENT_USER, _T("SOFTWARE\\Microsoft\\Internet Explorer\\Main\\FeatureControl\\FEATURE_BROWSER_EMULATION"),
108 		0, NULL, 0, KEY_SET_VALUE, NULL, &emulationKey, NULL);
109 	if(result != ERROR_SUCCESS)
110 	{
111 		return;
112 	}
113 	auto modulePath =
114 		[]()
115 		{
116 			TCHAR modulePath[MAX_PATH + 1];
117 			GetModuleFileName(NULL, modulePath, MAX_PATH);
118 			modulePath[MAX_PATH] = 0;
119 			return fs::path(modulePath);
120 		}();
121 	auto moduleFileName = modulePath.filename().native();
122 	DWORD emulationValue = 9000;
123 	result = RegSetValueEx(emulationKey, moduleFileName.c_str(), 0, REG_DWORD, reinterpret_cast<BYTE*>(&emulationValue), sizeof(emulationValue));
124 	assert(result == ERROR_SUCCESS);
125 	RegCloseKey(emulationKey);
126 }
127 
WebBrowserClientSiteFactory(HWND hWnd)128 CActiveXHost::UnknownPtr CWebBrowser::WebBrowserClientSiteFactory(HWND hWnd)
129 {
130 	return UnknownPtr(new CWebBrowserClientSite(hWnd));
131 }
132 
MsgFilterHook(int code,WPARAM wparam,LPARAM lparam)133 LRESULT CALLBACK CWebBrowser::MsgFilterHook(int code, WPARAM wparam, LPARAM lparam)
134 {
135 	if(code < 0)
136 	{
137 		return CallNextHookEx(NULL, code, wparam, lparam);
138 	}
139 	MSG* msg = reinterpret_cast<MSG*>(lparam);
140 	HWND candidateWnd = msg->hwnd;
141 	for(; (candidateWnd != NULL) && (GetWindowLong(candidateWnd, GWL_STYLE) & WS_CHILD); candidateWnd = ::GetParent(candidateWnd))
142 	{
143 		CWindow* windowPtr = CWindow::GetClassPtr(candidateWnd);
144 		if((windowPtr != nullptr) && (g_hookListeners.find(windowPtr) != std::end(g_hookListeners)))
145 		{
146 			CWebBrowser* browserPtr = static_cast<CWebBrowser*>(windowPtr);
147 			CComPtr<IOleInPlaceActiveObject> inPlaceActiveObject;
148 			HRESULT result = browserPtr->m_webBrowser->QueryInterface(IID_IOleInPlaceActiveObject, reinterpret_cast<void**>(&inPlaceActiveObject));
149 			if(SUCCEEDED(result))
150 			{
151 				result = inPlaceActiveObject->TranslateAccelerator(msg);
152 				if(result == S_OK) return ~0;
153 			}
154 		}
155 	}
156 	return CallNextHookEx(NULL, code, wparam, lparam);
157 }
158 
RegisterFilterHook(CWindow * listener)159 void CWebBrowser::RegisterFilterHook(CWindow* listener)
160 {
161 	assert(g_hookListeners.find(listener) == std::end(g_hookListeners));
162 	g_hookListeners.insert(listener);
163 	if(g_hookCount == 0)
164 	{
165 		g_hookHandle = SetWindowsHookEx(WH_MSGFILTER, &CWebBrowser::MsgFilterHook, NULL, GetCurrentThreadId());
166 	}
167 	g_hookCount++;
168 }
169 
UnregisterFilterHook(CWindow * listener)170 void CWebBrowser::UnregisterFilterHook(CWindow* listener)
171 {
172 	auto hookListenerIterator = g_hookListeners.find(listener);
173 	if(hookListenerIterator == std::end(g_hookListeners))
174 	{
175 		return;
176 	}
177 	g_hookListeners.erase(hookListenerIterator);
178 	assert(g_hookCount > 0);
179 	g_hookCount--;
180 	if(g_hookCount == 0)
181 	{
182 		BOOL result = UnhookWindowsHookEx(g_hookHandle);
183 		assert(result == TRUE);
184 		g_hookHandle = NULL;
185 	}
186 }
187 
ExchangeFilterHook(CWindow * listen1,CWindow * listen2)188 void CWebBrowser::ExchangeFilterHook(CWindow* listen1, CWindow* listen2)
189 {
190 	auto listen1Iterator = g_hookListeners.find(listen1);
191 	auto listen2Iterator = g_hookListeners.find(listen2);
192 
193 	if((listen1Iterator == std::end(g_hookListeners)) && (listen2Iterator == std::end(g_hookListeners)))
194 	{
195 		//Nothing to do, both are not registered
196 	}
197 	else if((listen1Iterator == std::end(g_hookListeners)) && (listen2Iterator != std::end(g_hookListeners)))
198 	{
199 		g_hookListeners.insert(listen1);
200 		g_hookListeners.erase(listen2Iterator);
201 	}
202 	else if((listen1Iterator != std::end(g_hookListeners)) && (listen2Iterator == std::end(g_hookListeners)))
203 	{
204 		g_hookListeners.insert(listen2);
205 		g_hookListeners.erase(listen1Iterator);
206 	}
207 	else
208 	{
209 		//Both are already in, no need to do anything
210 	}
211 }
212 
213 /////////////////////////////////////////////////////////////////////////////////////////////
214 //CWebBrowserClientSite
215 /////////////////////////////////////////////////////////////////////////////////////////////
216 
CWebBrowserClientSite(HWND window)217 CWebBrowser::CWebBrowserClientSite::CWebBrowserClientSite(HWND window)
218 : m_refCount(1)
219 {
220 	m_clientSite = CClientSite::Create(window, this);
221 }
222 
~CWebBrowserClientSite()223 CWebBrowser::CWebBrowserClientSite::~CWebBrowserClientSite()
224 {
225 
226 }
227 
AddRef()228 ULONG CWebBrowser::CWebBrowserClientSite::AddRef()
229 {
230 	InterlockedIncrement(&m_refCount);
231 	return m_refCount;
232 }
233 
Release()234 ULONG CWebBrowser::CWebBrowserClientSite::Release()
235 {
236 	assert(m_refCount != 0);
237 	InterlockedDecrement(&m_refCount);
238 	if(m_refCount == 0)
239 	{
240 		delete this;
241 		return 0;
242 	}
243 	else
244 	{
245 		return m_refCount;
246 	}
247 }
248 
QueryInterface(const IID & iid,void ** intrf)249 HRESULT CWebBrowser::CWebBrowserClientSite::QueryInterface(const IID& iid, void** intrf)
250 {
251 	(*intrf) = NULL;
252 	if(iid == IID_IOleClientSite)
253 	{
254 		return m_clientSite->QueryInterface(iid, intrf);
255 	}
256 	if(iid == IID_IOleInPlaceSite)
257 	{
258 		return m_clientSite->QueryInterface(iid, intrf);
259 	}
260 	if(iid == IID_IDocHostUIHandler)
261 	{
262 		(*intrf) = static_cast<IDocHostUIHandler*>(this);
263 	}
264 
265 	if(*intrf)
266 	{
267 		reinterpret_cast<IUnknown*>(*intrf)->AddRef();
268 		return S_OK;
269 	}
270 	else
271 	{
272 		return E_NOINTERFACE;
273 	}
274 }
275 
ShowContextMenu(DWORD,POINT *,IUnknown *,IDispatch *)276 HRESULT CWebBrowser::CWebBrowserClientSite::ShowContextMenu(DWORD, POINT*, IUnknown*, IDispatch*)
277 {
278 	return S_OK;
279 }
280 
GetHostInfo(DOCHOSTUIINFO * docHostUiInfo)281 HRESULT CWebBrowser::CWebBrowserClientSite::GetHostInfo(DOCHOSTUIINFO* docHostUiInfo)
282 {
283 	docHostUiInfo->dwFlags |= DOCHOSTUIFLAG_DPI_AWARE;
284 	docHostUiInfo->dwFlags |= DOCHOSTUIFLAG_THEME;
285 	return S_OK;
286 }
287 
ShowUI(DWORD,IOleInPlaceActiveObject *,IOleCommandTarget *,IOleInPlaceFrame *,IOleInPlaceUIWindow *)288 HRESULT CWebBrowser::CWebBrowserClientSite::ShowUI(DWORD, IOleInPlaceActiveObject*, IOleCommandTarget*, IOleInPlaceFrame*, IOleInPlaceUIWindow*)
289 {
290 	return S_OK;
291 }
292 
HideUI()293 HRESULT CWebBrowser::CWebBrowserClientSite::HideUI()
294 {
295 	return S_OK;
296 }
297 
UpdateUI()298 HRESULT CWebBrowser::CWebBrowserClientSite::UpdateUI()
299 {
300 	return S_OK;
301 }
302 
EnableModeless(BOOL)303 HRESULT CWebBrowser::CWebBrowserClientSite::EnableModeless(BOOL)
304 {
305 	return S_OK;
306 }
307 
OnDocWindowActivate(BOOL)308 HRESULT CWebBrowser::CWebBrowserClientSite::OnDocWindowActivate(BOOL)
309 {
310 	return S_OK;
311 }
312 
OnFrameWindowActivate(BOOL)313 HRESULT CWebBrowser::CWebBrowserClientSite::OnFrameWindowActivate(BOOL)
314 {
315 	return S_OK;
316 }
317 
ResizeBorder(LPCRECT,IOleInPlaceUIWindow *,BOOL)318 HRESULT CWebBrowser::CWebBrowserClientSite::ResizeBorder(LPCRECT, IOleInPlaceUIWindow*, BOOL)
319 {
320 	return S_OK;
321 }
322 
TranslateAccelerator(LPMSG,const GUID *,DWORD)323 HRESULT CWebBrowser::CWebBrowserClientSite::TranslateAccelerator(LPMSG, const GUID*, DWORD)
324 {
325 	return S_FALSE;
326 }
327 
GetOptionKeyPath(LPOLESTR *,DWORD)328 HRESULT CWebBrowser::CWebBrowserClientSite::GetOptionKeyPath(LPOLESTR*, DWORD)
329 {
330 	return S_OK;
331 }
332 
GetDropTarget(IDropTarget *,IDropTarget **)333 HRESULT CWebBrowser::CWebBrowserClientSite::GetDropTarget(IDropTarget*, IDropTarget**)
334 {
335 	return S_OK;
336 }
337 
GetExternal(IDispatch **)338 HRESULT CWebBrowser::CWebBrowserClientSite::GetExternal(IDispatch**)
339 {
340 	return S_OK;
341 }
342 
TranslateUrl(DWORD,LPWSTR,LPWSTR *)343 HRESULT CWebBrowser::CWebBrowserClientSite::TranslateUrl(DWORD, LPWSTR, LPWSTR*)
344 {
345 	return S_OK;
346 }
347 
FilterDataObject(IDataObject *,IDataObject **)348 HRESULT CWebBrowser::CWebBrowserClientSite::FilterDataObject(IDataObject*, IDataObject**)
349 {
350 	return S_OK;
351 }
352 
353 
354 /////////////////////////////////////////////////////////////////////////////////////////////
355 //CEventSink
356 /////////////////////////////////////////////////////////////////////////////////////////////
357 
CEventSink(HWND browserWnd)358 CWebBrowser::CEventSink::CEventSink(HWND browserWnd)
359 : m_refCount(1)
360 , m_browserWnd(browserWnd)
361 {
362 
363 }
364 
~CEventSink()365 CWebBrowser::CEventSink::~CEventSink()
366 {
367 
368 }
369 
AddRef()370 ULONG CWebBrowser::CEventSink::AddRef()
371 {
372 	InterlockedIncrement(&m_refCount);
373 	return m_refCount;
374 }
375 
Release()376 ULONG CWebBrowser::CEventSink::Release()
377 {
378 	InterlockedDecrement(&m_refCount);
379 	if(m_refCount == 0)
380 	{
381 		delete this;
382 		return 0;
383 	}
384 	else
385 	{
386 		return m_refCount;
387 	}
388 }
389 
QueryInterface(const IID & iid,void ** intrf)390 HRESULT CWebBrowser::CEventSink::QueryInterface(const IID& iid, void** intrf)
391 {
392 	(*intrf) = NULL;
393 	if(iid == DIID_DWebBrowserEvents2)
394 	{
395 		(*intrf) = static_cast<DWebBrowserEvents2*>(this);
396 	}
397 	else if(iid == IID_IDispatch)
398 	{
399 		(*intrf) = static_cast<IDispatch*>(this);
400 	}
401 
402 	if(*intrf)
403 	{
404 		AddRef();
405 		return S_OK;
406 	}
407 	else
408 	{
409 		return E_NOINTERFACE;
410 	}
411 }
412 
GetTypeInfoCount(UINT *)413 HRESULT CWebBrowser::CEventSink::GetTypeInfoCount(UINT*)
414 {
415 	return E_NOTIMPL;
416 }
417 
GetTypeInfo(UINT,LCID,ITypeInfo **)418 HRESULT CWebBrowser::CEventSink::GetTypeInfo(UINT, LCID, ITypeInfo**)
419 {
420 	return E_NOTIMPL;
421 }
422 
GetIDsOfNames(const IID &,LPOLESTR *,UINT,LCID,DISPID *)423 HRESULT CWebBrowser::CEventSink::GetIDsOfNames(const IID&, LPOLESTR*, UINT, LCID, DISPID*)
424 {
425 	return E_NOTIMPL;
426 }
427 
Invoke(DISPID dispId,const IID &,LCID,WORD,DISPPARAMS * paramInfo,VARIANT *,EXCEPINFO *,UINT *)428 HRESULT CWebBrowser::CEventSink::Invoke(DISPID dispId, const IID&, LCID, WORD, DISPPARAMS* paramInfo, VARIANT*, EXCEPINFO*, UINT*)
429 {
430 	switch(dispId)
431 	{
432 	case DISPID_BEFORENAVIGATE2:
433 		{
434 			assert(paramInfo->cArgs == 7);
435 			VARIANTARG* cancelPtrArg = &paramInfo->rgvarg[0];
436 			VARIANTARG* urlPtrArg = &paramInfo->rgvarg[5];
437 			assert(urlPtrArg->vt == (VT_BYREF | VT_VARIANT));
438 			if(urlPtrArg->vt == (VT_BYREF | VT_VARIANT))
439 			{
440 				VARIANT* urlArg = urlPtrArg->pvarVal;
441 				BEFORENAVIGATE_INFO beforeNavigateInfo;
442 				beforeNavigateInfo.code			= NOTIFICATION_BEFORENAVIGATE;
443 				beforeNavigateInfo.hwndFrom		= m_browserWnd;
444 				beforeNavigateInfo.idFrom		= 0;
445 				beforeNavigateInfo.navigateUrl	= urlArg->bstrVal;
446 				beforeNavigateInfo.cancel		= false;
447 				SendMessage(::GetParent(m_browserWnd), WM_NOTIFY, reinterpret_cast<WPARAM>(m_browserWnd), reinterpret_cast<LPARAM>(&beforeNavigateInfo));
448 				if(beforeNavigateInfo.cancel)
449 				{
450 					if(cancelPtrArg->vt == (VT_BYREF | VT_BOOL))
451 					{
452 						VARIANT* cancelArg = cancelPtrArg->pvarVal;
453 						cancelArg->vt			= VT_BOOL;
454 						cancelArg->boolVal		= false;
455 					}
456 				}
457 			}
458 			return S_OK;
459 		}
460 		break;
461 	}
462 
463 	return E_NOTIMPL;
464 }
465