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 = ¶mInfo->rgvarg[0];
436 VARIANTARG* urlPtrArg = ¶mInfo->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