1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/webview_ie.cpp
3 // Purpose: wxMSW wxWebViewIE class implementation for web view component
4 // Author: Marianne Gagnon
5 // Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton
6 // Licence: wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8
9 // For compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11
12 #if defined(__BORLANDC__)
13 #pragma hdrstop
14 #endif
15
16 #include "wx/msw/webview_ie.h"
17
18 #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
19
20 #include <olectl.h>
21 #include <oleidl.h>
22 #include <exdispid.h>
23 #include <exdisp.h>
24 #include <mshtml.h>
25 #include "wx/msw/registry.h"
26 #include "wx/msw/missing.h"
27 #include "wx/filesys.h"
28 #include "wx/dynlib.h"
29 #include "wx/scopeguard.h"
30
31 #include <initguid.h>
32 #include <wininet.h>
33
34 /* These GUID definitions are our own implementation to support interfaces
35 * normally in urlmon.h. See include/wx/msw/webview_ie.h
36 */
37
38 namespace {
39
40 DEFINE_GUID(wxIID_IInternetProtocolRoot,0x79eac9e3,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
41 DEFINE_GUID(wxIID_IInternetProtocol,0x79eac9e4,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
42 DEFINE_GUID(wxIID_IDocHostUIHandler, 0xbd3f23c0, 0xd43e, 0x11cf, 0x89, 0x3b, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x1a);
43 DEFINE_GUID(wxIID_IHTMLElement2,0x3050f434,0x98b5,0x11cf,0xbb,0x82,0,0xaa,0,0xbd,0xce,0x0b);
44 DEFINE_GUID(wxIID_IMarkupServices,0x3050f4a0,0x98b5,0x11cf,0xbb,0x82,0,0xaa,0,0xbd,0xce,0x0b);
45 DEFINE_GUID(wxIID_IMarkupContainer,0x3050f5f9,0x98b5,0x11cf,0xbb,0x82,0,0xaa,0,0xbd,0xce,0x0b);
46
47 enum //Internal find flags
48 {
49 wxWEBVIEW_FIND_ADD_POINTERS = 0x0001,
50 wxWEBVIEW_FIND_REMOVE_HIGHLIGHT = 0x0002
51 };
52
53 }
54
55 //Convenience function for error conversion
56 #define WX_ERROR_CASE(error, wxerror) \
57 case error: \
58 event.SetString(#error); \
59 event.SetInt(wxerror); \
60 break;
61
62 wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewIE, wxWebView);
63
BEGIN_EVENT_TABLE(wxWebViewIE,wxControl)64 BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
65 EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
66 EVT_ERASE_BACKGROUND(wxWebViewIE::onEraseBg)
67 END_EVENT_TABLE()
68
69 bool wxWebViewIE::Create(wxWindow* parent,
70 wxWindowID id,
71 const wxString& url,
72 const wxPoint& pos,
73 const wxSize& size,
74 long style,
75 const wxString& name)
76 {
77 if (!wxControl::Create(parent, id, pos, size, style,
78 wxDefaultValidator, name))
79 {
80 return false;
81 }
82
83 m_webBrowser = NULL;
84 m_isBusy = false;
85 m_historyLoadingFromList = false;
86 m_historyEnabled = true;
87 m_historyPosition = -1;
88 m_zoomType = wxWEBVIEW_ZOOM_TYPE_TEXT;
89 FindClear();
90
91 if (::CoCreateInstance(CLSID_WebBrowser, NULL,
92 CLSCTX_INPROC_SERVER, // CLSCTX_INPROC,
93 IID_IWebBrowser2 , (void**)&m_webBrowser) != 0)
94 {
95 wxLogError("Failed to initialize IE, CoCreateInstance returned an error");
96 return false;
97 }
98
99 m_ie.SetDispatchPtr(m_webBrowser); // wxAutomationObject will release itself
100
101 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
102 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
103
104 m_uiHandler = new DocHostUIHandler(this);
105
106 m_container = new wxIEContainer(this, IID_IWebBrowser2, m_webBrowser, m_uiHandler);
107
108 EnableControlFeature(21 /* FEATURE_DISABLE_NAVIGATION_SOUNDS */);
109
110 LoadURL(url);
111 return true;
112 }
113
~wxWebViewIE()114 wxWebViewIE::~wxWebViewIE()
115 {
116 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
117 if(urlMon.HasSymbol(wxT("CoInternetGetSession")))
118 {
119 typedef HRESULT (WINAPI *CoInternetGetSession_t)(DWORD,
120 wxIInternetSession**,
121 DWORD);
122 wxDYNLIB_FUNCTION(CoInternetGetSession_t, CoInternetGetSession, urlMon);
123
124 wxIInternetSession* session;
125 HRESULT res = (*pfnCoInternetGetSession)(0, &session, 0);
126 if(FAILED(res))
127 {
128 wxFAIL_MSG("Could not retrive internet session");
129 }
130
131 for(unsigned int i = 0; i < m_factories.size(); i++)
132 {
133 session->UnregisterNameSpace(m_factories[i],
134 (m_factories[i]->GetName()).wc_str());
135 m_factories[i]->Release();
136 }
137 }
138 FindClear();
139 }
140
LoadURL(const wxString & url)141 void wxWebViewIE::LoadURL(const wxString& url)
142 {
143 m_ie.CallMethod("Navigate", wxConvertStringToOle(url));
144 }
145
146 namespace
147 {
148
149 // Simple RAII wrapper for accessing SAFEARRAY<VARIANT>. This class is not specific
150 // to wxWebView at all and could be extended to work for any type and extracted
151 // into a header later if it is ever needed elsewhere, but for now keep it here
152 // as it is only used in MakeOneElementVariantSafeArray() which, itself, is
153 // only used by DoSetPage() below.
154 class wxSafeArrayVariantAccessor
155 {
156 public:
wxSafeArrayVariantAccessor(SAFEARRAY * sa)157 explicit wxSafeArrayVariantAccessor(SAFEARRAY* sa)
158 : m_sa(sa),
159 m_data(DoAccessData(sa))
160 {
161 }
162
GetData() const163 VARIANT* GetData() const
164 {
165 return m_data;
166 }
167
~wxSafeArrayVariantAccessor()168 ~wxSafeArrayVariantAccessor()
169 {
170 if ( m_data )
171 SafeArrayUnaccessData(m_sa);
172 }
173
174 private:
DoAccessData(SAFEARRAY * sa)175 static VARIANT* DoAccessData(SAFEARRAY* sa)
176 {
177 VARIANT *param;
178 HRESULT hr = SafeArrayAccessData(sa, (LPVOID*)¶m);
179 if ( FAILED(hr) )
180 {
181 wxLogLastError(wxT("SafeArrayAccessData"));
182 return NULL;
183 }
184
185 return param;
186 }
187
188 SAFEARRAY* const m_sa;
189 VARIANT* const m_data;
190
191 wxDECLARE_NO_COPY_CLASS(wxSafeArrayVariantAccessor);
192 };
193
194 // Helper function: wrap the given string in a SAFEARRAY<VARIANT> of size 1.
MakeOneElementVariantSafeArray(const wxString & str)195 SAFEARRAY* MakeOneElementVariantSafeArray(const wxString& str)
196 {
197 SAFEARRAY* const sa = SafeArrayCreateVector(VT_VARIANT, 0, 1);
198 if ( !sa )
199 {
200 wxLogLastError(wxT("SafeArrayCreateVector"));
201 return NULL;
202 }
203
204 wxSafeArrayVariantAccessor access(sa);
205
206 VARIANT* const param = access.GetData();
207 if ( !param )
208 {
209 SafeArrayDestroy(sa);
210 return NULL;
211 }
212
213 param->vt = VT_BSTR;
214 param->bstrVal = SysAllocString(str.wc_str());
215
216 return sa;
217 }
218
219 } // anonymous namespace
220
DoSetPage(const wxString & html,const wxString & baseUrl)221 void wxWebViewIE::DoSetPage(const wxString& html, const wxString& baseUrl)
222 {
223 {
224 SAFEARRAY* const psaStrings = MakeOneElementVariantSafeArray(wxString());
225 if ( !psaStrings )
226 return;
227
228 wxON_BLOCK_EXIT1(SafeArrayDestroy, psaStrings);
229
230 wxCOMPtr<IHTMLDocument2> document(GetDocument());
231
232 if(!document)
233 return;
234
235 document->write(psaStrings);
236 document->close();
237 }
238
239 {
240 SAFEARRAY* const psaStrings = MakeOneElementVariantSafeArray(html);
241
242 if ( !psaStrings )
243 return;
244
245 wxON_BLOCK_EXIT1(SafeArrayDestroy, psaStrings);
246
247 wxCOMPtr<IHTMLDocument2> document(GetDocument());
248
249 if(!document)
250 return;
251
252 document->write(psaStrings);
253
254 //We send the events when we are done to mimic webkit
255 //Navigated event
256 wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATED,
257 GetId(), baseUrl, "");
258 event.SetEventObject(this);
259 HandleWindowEvent(event);
260
261 //Document complete event
262 event.SetEventType(wxEVT_WEBVIEW_LOADED);
263 event.SetEventObject(this);
264 HandleWindowEvent(event);
265 }
266 }
267
GetPageSource() const268 wxString wxWebViewIE::GetPageSource() const
269 {
270 wxCOMPtr<IHTMLDocument2> document(GetDocument());
271
272 if(document)
273 {
274 wxCOMPtr<IHTMLElement> bodyTag;
275 wxCOMPtr<IHTMLElement> htmlTag;
276 wxString source;
277 HRESULT hr = document->get_body(&bodyTag);
278 if(SUCCEEDED(hr))
279 {
280 hr = bodyTag->get_parentElement(&htmlTag);
281 if(SUCCEEDED(hr))
282 {
283 BSTR bstr = NULL;
284 if ( htmlTag->get_outerHTML(&bstr) == S_OK )
285 {
286 source = wxString(bstr);
287 SysFreeString(bstr);
288 }
289 }
290 }
291 return source;
292 }
293 else
294 {
295 return "";
296 }
297 }
298
GetZoom() const299 wxWebViewZoom wxWebViewIE::GetZoom() const
300 {
301 switch( m_zoomType )
302 {
303 case wxWEBVIEW_ZOOM_TYPE_LAYOUT:
304 return GetIEOpticalZoom();
305 case wxWEBVIEW_ZOOM_TYPE_TEXT:
306 return GetIETextZoom();
307 default:
308 wxFAIL;
309 }
310
311 //Dummy return to stop compiler warnings
312 return wxWEBVIEW_ZOOM_MEDIUM;
313
314 }
315
SetZoom(wxWebViewZoom zoom)316 void wxWebViewIE::SetZoom(wxWebViewZoom zoom)
317 {
318 switch( m_zoomType )
319 {
320 case wxWEBVIEW_ZOOM_TYPE_LAYOUT:
321 SetIEOpticalZoom(zoom);
322 break;
323 case wxWEBVIEW_ZOOM_TYPE_TEXT:
324 SetIETextZoom(zoom);
325 break;
326 default:
327 wxFAIL;
328 }
329 }
330
SetIETextZoom(wxWebViewZoom level)331 void wxWebViewIE::SetIETextZoom(wxWebViewZoom level)
332 {
333 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
334 //is 0 to 4 so the check is unnecessary, these match exactly with the
335 //enum values
336 VARIANT zoomVariant;
337 VariantInit (&zoomVariant);
338 V_VT(&zoomVariant) = VT_I4;
339 V_I4(&zoomVariant) = level;
340
341 #if wxDEBUG_LEVEL
342 HRESULT result =
343 #endif
344 m_webBrowser->ExecWB(OLECMDID_ZOOM,
345 OLECMDEXECOPT_DONTPROMPTUSER,
346 &zoomVariant, NULL);
347 wxASSERT(result == S_OK);
348 }
349
GetIETextZoom() const350 wxWebViewZoom wxWebViewIE::GetIETextZoom() const
351 {
352 VARIANT zoomVariant;
353 VariantInit (&zoomVariant);
354 V_VT(&zoomVariant) = VT_I4;
355
356 #if wxDEBUG_LEVEL
357 HRESULT result =
358 #endif
359 m_webBrowser->ExecWB(OLECMDID_ZOOM,
360 OLECMDEXECOPT_DONTPROMPTUSER,
361 NULL, &zoomVariant);
362 wxASSERT(result == S_OK);
363
364 //We can safely cast here as we know that the range matches our enum
365 return static_cast<wxWebViewZoom>(V_I4(&zoomVariant));
366 }
367
SetIEOpticalZoom(wxWebViewZoom level)368 void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level)
369 {
370 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
371 //is 10 to 1000 so the check is unnecessary
372 VARIANT zoomVariant;
373 VariantInit (&zoomVariant);
374 V_VT(&zoomVariant) = VT_I4;
375
376 //We make a somewhat arbitray map here, taken from values used by webkit
377 switch(level)
378 {
379 case wxWEBVIEW_ZOOM_TINY:
380 V_I4(&zoomVariant) = 60;
381 break;
382 case wxWEBVIEW_ZOOM_SMALL:
383 V_I4(&zoomVariant) = 80;
384 break;
385 case wxWEBVIEW_ZOOM_MEDIUM:
386 V_I4(&zoomVariant) = 100;
387 break;
388 case wxWEBVIEW_ZOOM_LARGE:
389 V_I4(&zoomVariant) = 130;
390 break;
391 case wxWEBVIEW_ZOOM_LARGEST:
392 V_I4(&zoomVariant) = 160;
393 break;
394 default:
395 wxFAIL;
396 }
397
398 #if wxDEBUG_LEVEL
399 HRESULT result =
400 #endif
401 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
402 OLECMDEXECOPT_DODEFAULT,
403 &zoomVariant,
404 NULL);
405 wxASSERT(result == S_OK);
406 }
407
GetIEOpticalZoom() const408 wxWebViewZoom wxWebViewIE::GetIEOpticalZoom() const
409 {
410 VARIANT zoomVariant;
411 VariantInit (&zoomVariant);
412 V_VT(&zoomVariant) = VT_I4;
413
414 #if wxDEBUG_LEVEL
415 HRESULT result =
416 #endif
417 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
418 OLECMDEXECOPT_DODEFAULT, NULL,
419 &zoomVariant);
420 wxASSERT(result == S_OK);
421
422 const int zoom = V_I4(&zoomVariant);
423
424 //We make a somewhat arbitray map here, taken from values used by webkit
425 if (zoom <= 65)
426 {
427 return wxWEBVIEW_ZOOM_TINY;
428 }
429 else if (zoom > 65 && zoom <= 90)
430 {
431 return wxWEBVIEW_ZOOM_SMALL;
432 }
433 else if (zoom > 90 && zoom <= 115)
434 {
435 return wxWEBVIEW_ZOOM_MEDIUM;
436 }
437 else if (zoom > 115 && zoom <= 145)
438 {
439 return wxWEBVIEW_ZOOM_LARGE;
440 }
441 else /*if (zoom > 145) */ //Using else removes a compiler warning
442 {
443 return wxWEBVIEW_ZOOM_LARGEST;
444 }
445 }
446
SetZoomType(wxWebViewZoomType type)447 void wxWebViewIE::SetZoomType(wxWebViewZoomType type)
448 {
449 m_zoomType = type;
450 }
451
GetZoomType() const452 wxWebViewZoomType wxWebViewIE::GetZoomType() const
453 {
454 return m_zoomType;
455 }
456
CanSetZoomType(wxWebViewZoomType type) const457 bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const
458 {
459 //IE 6 and below only support text zoom, so check the registry to see what
460 //version we actually have
461 wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer");
462 wxString value;
463 key.QueryValue("Version", value);
464
465 long version = wxAtoi(value.Left(1));
466 if(version <= 6 && type == wxWEBVIEW_ZOOM_TYPE_LAYOUT)
467 return false;
468 else
469 return true;
470 }
471
Print()472 void wxWebViewIE::Print()
473 {
474 m_webBrowser->ExecWB(OLECMDID_PRINTPREVIEW,
475 OLECMDEXECOPT_DODEFAULT, NULL, NULL);
476 }
477
CanGoBack() const478 bool wxWebViewIE::CanGoBack() const
479 {
480 if(m_historyEnabled)
481 return m_historyPosition > 0;
482 else
483 return false;
484 }
485
CanGoForward() const486 bool wxWebViewIE::CanGoForward() const
487 {
488 if(m_historyEnabled)
489 return m_historyPosition != static_cast<int>(m_historyList.size()) - 1;
490 else
491 return false;
492 }
493
LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)494 void wxWebViewIE::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
495 {
496 int pos = -1;
497 for(unsigned int i = 0; i < m_historyList.size(); i++)
498 {
499 //We compare the actual pointers to find the correct item
500 if(m_historyList[i].get() == item.get())
501 pos = i;
502 }
503 wxASSERT_MSG(pos != static_cast<int>(m_historyList.size()),
504 "invalid history item");
505 m_historyLoadingFromList = true;
506 LoadURL(item->GetUrl());
507 m_historyPosition = pos;
508 }
509
GetBackwardHistory()510 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetBackwardHistory()
511 {
512 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
513 //As we don't have std::copy or an iterator constructor in the wxwidgets
514 //native vector we construct it by hand
515 for(int i = 0; i < m_historyPosition; i++)
516 {
517 backhist.push_back(m_historyList[i]);
518 }
519 return backhist;
520 }
521
GetForwardHistory()522 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetForwardHistory()
523 {
524 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
525 //As we don't have std::copy or an iterator constructor in the wxwidgets
526 //native vector we construct it by hand
527 for(int i = m_historyPosition + 1; i < static_cast<int>(m_historyList.size()); i++)
528 {
529 forwardhist.push_back(m_historyList[i]);
530 }
531 return forwardhist;
532 }
533
GoBack()534 void wxWebViewIE::GoBack()
535 {
536 LoadHistoryItem(m_historyList[m_historyPosition - 1]);
537 }
538
GoForward()539 void wxWebViewIE::GoForward()
540 {
541 LoadHistoryItem(m_historyList[m_historyPosition + 1]);
542 }
543
Stop()544 void wxWebViewIE::Stop()
545 {
546 m_ie.CallMethod("Stop");
547 }
548
ClearHistory()549 void wxWebViewIE::ClearHistory()
550 {
551 m_historyList.clear();
552 m_historyPosition = -1;
553 }
554
EnableHistory(bool enable)555 void wxWebViewIE::EnableHistory(bool enable)
556 {
557 m_historyEnabled = enable;
558 m_historyList.clear();
559 m_historyPosition = -1;
560 }
561
Reload(wxWebViewReloadFlags flags)562 void wxWebViewIE::Reload(wxWebViewReloadFlags flags)
563 {
564 VARIANTARG level;
565 VariantInit(&level);
566 V_VT(&level) = VT_I2;
567
568 switch(flags)
569 {
570 case wxWEBVIEW_RELOAD_DEFAULT:
571 V_I2(&level) = REFRESH_NORMAL;
572 break;
573 case wxWEBVIEW_RELOAD_NO_CACHE:
574 V_I2(&level) = REFRESH_COMPLETELY;
575 break;
576 default:
577 wxFAIL_MSG("Unexpected reload type");
578 }
579
580 m_webBrowser->Refresh2(&level);
581 }
582
IsOfflineMode()583 bool wxWebViewIE::IsOfflineMode()
584 {
585 wxVariant out = m_ie.GetProperty("Offline");
586
587 wxASSERT(out.GetType() == "bool");
588
589 return out.GetBool();
590 }
591
SetOfflineMode(bool offline)592 void wxWebViewIE::SetOfflineMode(bool offline)
593 {
594 // FIXME: the wxWidgets docs do not really document what the return
595 // parameter of PutProperty is
596 #if wxDEBUG_LEVEL
597 const bool success =
598 #endif
599 m_ie.PutProperty("Offline", (offline ?
600 VARIANT_TRUE :
601 VARIANT_FALSE));
602 wxASSERT(success);
603 }
604
IsBusy() const605 bool wxWebViewIE::IsBusy() const
606 {
607 if (m_isBusy) return true;
608
609 wxVariant out = m_ie.GetProperty("Busy");
610
611 wxASSERT(out.GetType() == "bool");
612
613 return out.GetBool();
614 }
615
GetCurrentURL() const616 wxString wxWebViewIE::GetCurrentURL() const
617 {
618 wxVariant out = m_ie.GetProperty("LocationURL");
619
620 wxASSERT(out.GetType() == "string");
621 return out.GetString();
622 }
623
GetCurrentTitle() const624 wxString wxWebViewIE::GetCurrentTitle() const
625 {
626 wxCOMPtr<IHTMLDocument2> document(GetDocument());
627
628 wxString s;
629 if(document)
630 {
631 BSTR title = NULL;
632 if ( document->get_nameProp(&title) == S_OK )
633 {
634 s = title;
635 SysFreeString(title);
636 }
637 }
638
639 return s;
640 }
641
CanCut() const642 bool wxWebViewIE::CanCut() const
643 {
644 return CanExecCommand("Cut");
645 }
646
CanCopy() const647 bool wxWebViewIE::CanCopy() const
648 {
649 return CanExecCommand("Copy");
650 }
651
CanPaste() const652 bool wxWebViewIE::CanPaste() const
653 {
654 return CanExecCommand("Paste");
655 }
656
Cut()657 void wxWebViewIE::Cut()
658 {
659 ExecCommand("Cut");
660 }
661
Copy()662 void wxWebViewIE::Copy()
663 {
664 ExecCommand("Copy");
665 }
666
Paste()667 void wxWebViewIE::Paste()
668 {
669 ExecCommand("Paste");
670 }
671
CanUndo() const672 bool wxWebViewIE::CanUndo() const
673 {
674 return CanExecCommand("Undo");
675 }
676
CanRedo() const677 bool wxWebViewIE::CanRedo() const
678 {
679 return CanExecCommand("Redo");
680 }
681
Undo()682 void wxWebViewIE::Undo()
683 {
684 ExecCommand("Undo");
685 }
686
Redo()687 void wxWebViewIE::Redo()
688 {
689 ExecCommand("Redo");
690 }
691
Find(const wxString & text,int flags)692 long wxWebViewIE::Find(const wxString& text, int flags)
693 {
694 //If the text is empty then we clear.
695 if(text.IsEmpty())
696 {
697 ClearSelection();
698 if(m_findFlags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT)
699 {
700 FindInternal(m_findText, (m_findFlags &~ wxWEBVIEW_FIND_HIGHLIGHT_RESULT), wxWEBVIEW_FIND_REMOVE_HIGHLIGHT);
701 }
702 FindClear();
703 return wxNOT_FOUND;
704 }
705 //Have we done this search before?
706 if(m_findText == text)
707 {
708 //Just do a highlight?
709 if((flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT) != (m_findFlags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT))
710 {
711 m_findFlags = flags;
712 if(!m_findPointers.empty())
713 {
714 FindInternal(m_findText, m_findFlags, ((flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT) == 0 ? wxWEBVIEW_FIND_REMOVE_HIGHLIGHT : 0));
715 }
716 return m_findPosition;
717 }
718 else if(((m_findFlags & wxWEBVIEW_FIND_ENTIRE_WORD) == (flags & wxWEBVIEW_FIND_ENTIRE_WORD)) && ((m_findFlags & wxWEBVIEW_FIND_MATCH_CASE) == (flags&wxWEBVIEW_FIND_MATCH_CASE)))
719 {
720 m_findFlags = flags;
721 return FindNext(((flags & wxWEBVIEW_FIND_BACKWARDS) ? -1 : 1));
722 }
723 }
724 //Remove old highlight if any.
725 if(m_findFlags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT)
726 {
727 FindInternal(m_findText, (m_findFlags &~ wxWEBVIEW_FIND_HIGHLIGHT_RESULT), wxWEBVIEW_FIND_REMOVE_HIGHLIGHT);
728 }
729 //Reset find variables.
730 FindClear();
731 ClearSelection();
732 m_findText = text;
733 m_findFlags = flags;
734 //find the text and return wxNOT_FOUND if there are no matches.
735 FindInternal(text, flags, wxWEBVIEW_FIND_ADD_POINTERS);
736 if(m_findPointers.empty())
737 return wxNOT_FOUND;
738
739 // Or their number if there are.
740 return m_findPointers.size();
741 }
742
SetEditable(bool enable)743 void wxWebViewIE::SetEditable(bool enable)
744 {
745 wxCOMPtr<IHTMLDocument2> document(GetDocument());
746
747 if(document)
748 {
749 if( enable )
750 document->put_designMode(wxBasicString("On"));
751 else
752 document->put_designMode(wxBasicString("Off"));
753
754 }
755 }
756
IsEditable() const757 bool wxWebViewIE::IsEditable() const
758 {
759 wxCOMPtr<IHTMLDocument2> document(GetDocument());
760
761 if(document)
762 {
763 BSTR mode = NULL;
764 if ( document->get_designMode(&mode) == S_OK )
765 {
766 wxString strMode(mode);
767
768 SysFreeString(mode);
769 if ( strMode == "On" )
770 return true;
771 }
772 }
773 return false;
774 }
775
SelectAll()776 void wxWebViewIE::SelectAll()
777 {
778 ExecCommand("SelectAll");
779 }
780
HasSelection() const781 bool wxWebViewIE::HasSelection() const
782 {
783 wxCOMPtr<IHTMLDocument2> document(GetDocument());
784
785 if(document)
786 {
787 wxCOMPtr<IHTMLSelectionObject> selection;
788 wxString sel;
789 HRESULT hr = document->get_selection(&selection);
790 if(SUCCEEDED(hr))
791 {
792 BSTR type = NULL;
793 if ( selection->get_type(&type) == S_OK )
794 {
795 sel = wxString(type);
796 SysFreeString(type);
797 }
798 }
799 return sel != "None";
800 }
801 else
802 {
803 return false;
804 }
805 }
806
DeleteSelection()807 void wxWebViewIE::DeleteSelection()
808 {
809 ExecCommand("Delete");
810 }
811
GetSelectedText() const812 wxString wxWebViewIE::GetSelectedText() const
813 {
814 wxCOMPtr<IHTMLDocument2> document(GetDocument());
815
816 if(document)
817 {
818 wxCOMPtr<IHTMLSelectionObject> selection;
819 wxString selected;
820 HRESULT hr = document->get_selection(&selection);
821 if(SUCCEEDED(hr))
822 {
823 wxCOMPtr<IDispatch> disrange;
824 hr = selection->createRange(&disrange);
825 if(SUCCEEDED(hr))
826 {
827 wxCOMPtr<IHTMLTxtRange> range;
828 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
829 if(SUCCEEDED(hr))
830 {
831 BSTR text = NULL;
832 if ( range->get_text(&text) == S_OK )
833 {
834 selected = wxString(text);
835 SysFreeString(text);
836 }
837 }
838 }
839 }
840 return selected;
841 }
842 else
843 {
844 return "";
845 }
846 }
847
GetSelectedSource() const848 wxString wxWebViewIE::GetSelectedSource() const
849 {
850 wxCOMPtr<IHTMLDocument2> document(GetDocument());
851
852 if(document)
853 {
854 wxCOMPtr<IHTMLSelectionObject> selection;
855 wxString selected;
856 HRESULT hr = document->get_selection(&selection);
857 if(SUCCEEDED(hr))
858 {
859 wxCOMPtr<IDispatch> disrange;
860 hr = selection->createRange(&disrange);
861 if(SUCCEEDED(hr))
862 {
863 wxCOMPtr<IHTMLTxtRange> range;
864 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
865 if(SUCCEEDED(hr))
866 {
867 BSTR text;
868 if ( range->get_htmlText(&text) == S_OK )
869 {
870 selected = wxString(text);
871 SysFreeString(text);
872 }
873 }
874 }
875 }
876 return selected;
877 }
878 else
879 {
880 return "";
881 }
882 }
883
ClearSelection()884 void wxWebViewIE::ClearSelection()
885 {
886 wxCOMPtr<IHTMLDocument2> document(GetDocument());
887
888 if(document)
889 {
890 wxCOMPtr<IHTMLSelectionObject> selection;
891 wxString selected;
892 HRESULT hr = document->get_selection(&selection);
893 if(SUCCEEDED(hr))
894 {
895 selection->empty();
896 }
897 }
898 }
899
GetPageText() const900 wxString wxWebViewIE::GetPageText() const
901 {
902 wxCOMPtr<IHTMLDocument2> document(GetDocument());
903
904 if(document)
905 {
906 wxString text;
907 wxCOMPtr<IHTMLElement> body;
908 HRESULT hr = document->get_body(&body);
909 if(SUCCEEDED(hr))
910 {
911 BSTR out = NULL;
912 if ( body->get_innerText(&out) == S_OK )
913 {
914 text = wxString(out);
915 SysFreeString(out);
916 }
917 }
918 return text;
919 }
920 else
921 {
922 return "";
923 }
924 }
925
RunScript(const wxString & javascript)926 void wxWebViewIE::RunScript(const wxString& javascript)
927 {
928 wxCOMPtr<IHTMLDocument2> document(GetDocument());
929
930 if(document)
931 {
932 wxCOMPtr<IHTMLWindow2> window;
933 wxString language = "javascript";
934 HRESULT hr = document->get_parentWindow(&window);
935 if(SUCCEEDED(hr))
936 {
937 VARIANT level;
938 VariantInit(&level);
939 V_VT(&level) = VT_EMPTY;
940 window->execScript(wxBasicString(javascript),
941 wxBasicString(language),
942 &level);
943 }
944 }
945 }
946
RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)947 void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
948 {
949 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
950 if(urlMon.HasSymbol(wxT("CoInternetGetSession")))
951 {
952 typedef HRESULT (WINAPI *CoInternetGetSession_t)(DWORD, wxIInternetSession**, DWORD);
953 wxDYNLIB_FUNCTION(CoInternetGetSession_t, CoInternetGetSession, urlMon);
954
955 ClassFactory* cf = new ClassFactory(handler);
956 wxIInternetSession* session;
957 HRESULT res = (*pfnCoInternetGetSession)(0, &session, 0);
958 if(FAILED(res))
959 {
960 wxFAIL_MSG("Could not retrive internet session");
961 }
962
963 HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol,
964 handler->GetName().wc_str(),
965 0, NULL, 0);
966 if(FAILED(hr))
967 {
968 wxFAIL_MSG("Could not register protocol");
969 }
970 m_factories.push_back(cf);
971 }
972 else
973 {
974 wxFAIL_MSG("urlmon does not contain CoInternetGetSession");
975 }
976 }
977
CanExecCommand(wxString command) const978 bool wxWebViewIE::CanExecCommand(wxString command) const
979 {
980 wxCOMPtr<IHTMLDocument2> document(GetDocument());
981
982 if(document)
983 {
984 VARIANT_BOOL enabled;
985
986 document->queryCommandEnabled(wxBasicString(command), &enabled);
987
988 return (enabled == VARIANT_TRUE);
989 }
990 else
991 {
992 return false;
993 }
994
995 }
996
ExecCommand(wxString command)997 void wxWebViewIE::ExecCommand(wxString command)
998 {
999 wxCOMPtr<IHTMLDocument2> document(GetDocument());
1000
1001 if(document)
1002 {
1003 document->execCommand(wxBasicString(command), VARIANT_FALSE, VARIANT(), NULL);
1004 }
1005 }
1006
GetDocument() const1007 wxCOMPtr<IHTMLDocument2> wxWebViewIE::GetDocument() const
1008 {
1009 wxCOMPtr<IDispatch> dispatch;
1010 wxCOMPtr<IHTMLDocument2> document;
1011 HRESULT result = m_webBrowser->get_Document(&dispatch);
1012 if(dispatch && SUCCEEDED(result))
1013 {
1014 //document is set to null automatically if the interface isn't supported
1015 dispatch->QueryInterface(IID_IHTMLDocument2, (void**)&document);
1016 }
1017 return document;
1018 }
1019
IsElementVisible(wxCOMPtr<IHTMLElement> elm)1020 bool wxWebViewIE::IsElementVisible(wxCOMPtr<IHTMLElement> elm)
1021 {
1022 wxCOMPtr<IHTMLElement> elm1 = elm;
1023 bool is_visible = true;
1024 //This method is not perfect but it does discover most of the hidden elements.
1025 //so if a better solution is found, then please do improve.
1026 while(elm1)
1027 {
1028 wxCOMPtr<wxIHTMLElement2> elm2;
1029 if(SUCCEEDED(elm1->QueryInterface(wxIID_IHTMLElement2, (void**) &elm2)))
1030 {
1031 wxCOMPtr<wxIHTMLCurrentStyle> style;
1032 BSTR tmp_bstr = NULL;
1033
1034 if(SUCCEEDED(elm2->get_currentStyle(&style)))
1035 {
1036 //Check if the object has the style display:none.
1037 if((style->get_display(&tmp_bstr) != S_OK) ||
1038 (tmp_bstr != NULL && (wxCRT_StricmpW(tmp_bstr, L"none") == 0)))
1039 {
1040 is_visible = false;
1041 }
1042 SysFreeString(tmp_bstr);
1043 tmp_bstr = NULL;
1044 //Check if the object has the style visibility:hidden.
1045 if((is_visible && (style->get_visibility(&tmp_bstr) != S_OK)) ||
1046 (tmp_bstr != NULL && wxCRT_StricmpW(tmp_bstr, L"hidden") == 0))
1047 {
1048 is_visible = false;
1049 }
1050 SysFreeString(tmp_bstr);
1051 style->Release();
1052 }
1053 elm2->Release();
1054 }
1055
1056 //Lets check the object's parent element.
1057 IHTMLElement* parent;
1058 if(is_visible && SUCCEEDED(elm1->get_parentElement(&parent)))
1059 {
1060 elm1 = parent;
1061 }
1062 else
1063 {
1064 elm1->Release();
1065 break;
1066 }
1067 }
1068 return is_visible;
1069 }
1070
FindInternal(const wxString & text,int flags,int internal_flag)1071 void wxWebViewIE::FindInternal(const wxString& text, int flags, int internal_flag)
1072 {
1073 long find_flag = 0;
1074 wxCOMPtr<wxIMarkupServices> pIMS;
1075 wxCOMPtr<IHTMLDocument2> document = GetDocument();
1076
1077 //This function does the acutal work.
1078 if(document && SUCCEEDED(document->QueryInterface(wxIID_IMarkupServices, (void **)&pIMS)))
1079 {
1080 wxCOMPtr<wxIMarkupContainer> pIMC;
1081 if(SUCCEEDED(document->QueryInterface(wxIID_IMarkupContainer, (void **)&pIMC)))
1082 {
1083 wxCOMPtr<wxIMarkupPointer> ptrBegin, ptrEnd;
1084 BSTR attr_bstr = SysAllocString(L"style=\"background-color:#ffff00\"");
1085 BSTR text_bstr = SysAllocString(text.wc_str());
1086 pIMS->CreateMarkupPointer(&ptrBegin);
1087 pIMS->CreateMarkupPointer(&ptrEnd);
1088
1089 ptrBegin->SetGravity(wxPOINTER_GRAVITY_Right);
1090 ptrBegin->MoveToContainer(pIMC, TRUE);
1091 //Create the find flag from the wx one.
1092 if(flags & wxWEBVIEW_FIND_ENTIRE_WORD)
1093 {
1094 find_flag |= wxFINDTEXT_WHOLEWORD;
1095 }
1096 if(flags & wxWEBVIEW_FIND_MATCH_CASE)
1097 {
1098 find_flag |= wxFINDTEXT_MATCHCASE;
1099 }
1100
1101 //A little speed-up to avoid to re-alloc in the positions vector.
1102 if(text.Len() < 3 && m_findPointers.capacity() < 500)
1103 {
1104 m_findPointers.reserve(text.Len() == 1 ? 1000 : 500);
1105 }
1106
1107 while(ptrBegin->FindText(text_bstr, find_flag, ptrEnd, NULL) == S_OK)
1108 {
1109 wxCOMPtr<IHTMLElement> elm;
1110 if(ptrBegin->CurrentScope(&elm) == S_OK)
1111 {
1112 if(IsElementVisible(elm))
1113 {
1114 //Highlight the word if the flag was set.
1115 if(flags & wxWEBVIEW_FIND_HIGHLIGHT_RESULT)
1116 {
1117 IHTMLElement* pFontEl;
1118 pIMS->CreateElement(wxTAGID_FONT, attr_bstr, &pFontEl);
1119 pIMS->InsertElement(pFontEl, ptrBegin, ptrEnd);
1120 }
1121 if(internal_flag & wxWEBVIEW_FIND_REMOVE_HIGHLIGHT)
1122 {
1123 IHTMLElement* pFontEl;
1124 ptrBegin->CurrentScope(&pFontEl);
1125 pIMS->RemoveElement(pFontEl);
1126 pFontEl->Release();
1127 }
1128 if(internal_flag & wxWEBVIEW_FIND_ADD_POINTERS)
1129 {
1130 wxIMarkupPointer *cptrBegin, *cptrEnd;
1131 pIMS->CreateMarkupPointer(&cptrBegin);
1132 pIMS->CreateMarkupPointer(&cptrEnd);
1133 cptrBegin->MoveToPointer(ptrBegin);
1134 cptrEnd->MoveToPointer(ptrEnd);
1135 m_findPointers.push_back(wxFindPointers(cptrBegin,cptrEnd));
1136 }
1137 }
1138 }
1139 ptrBegin->MoveToPointer(ptrEnd);
1140 }
1141 //Clean up.
1142 SysFreeString(text_bstr);
1143 SysFreeString(attr_bstr);
1144 }
1145 }
1146 }
1147
FindNext(int direction)1148 long wxWebViewIE::FindNext(int direction)
1149 {
1150 //Don't bother if we have no pointers set.
1151 if(m_findPointers.empty())
1152 {
1153 return wxNOT_FOUND;
1154 }
1155 //Manage the find position and do some checks.
1156 if(direction > 0)
1157 {
1158 m_findPosition++;
1159 }
1160 else
1161 {
1162 m_findPosition--;
1163 }
1164
1165 if(m_findPosition >= (signed)m_findPointers.size())
1166 {
1167 if(m_findFlags & wxWEBVIEW_FIND_WRAP)
1168 {
1169 m_findPosition = 0;
1170 }
1171 else
1172 {
1173 m_findPosition--;
1174 return wxNOT_FOUND;
1175 }
1176 }
1177 else if(m_findPosition < 0)
1178 {
1179 if(m_findFlags & wxWEBVIEW_FIND_WRAP)
1180 {
1181 m_findPosition = m_findPointers.size()-1;
1182 }
1183 else
1184 {
1185 m_findPosition++;
1186 return wxNOT_FOUND;
1187 }
1188 }
1189
1190 wxCOMPtr<IHTMLDocument2> document = GetDocument();
1191 wxCOMPtr<IHTMLElement> body_element;
1192
1193 long ret = -1;
1194 //Now try to create a range from the body.
1195 if(document && SUCCEEDED(document->get_body(&body_element)))
1196 {
1197 wxCOMPtr<IHTMLBodyElement> body;
1198 if(SUCCEEDED(body_element->QueryInterface(IID_IHTMLBodyElement,(void**)&body)))
1199 {
1200 wxCOMPtr<wxIHTMLTxtRange> range;
1201 if(SUCCEEDED(body->createTextRange((IHTMLTxtRange**)(&range))))
1202 {
1203 wxCOMPtr<wxIMarkupServices> pIMS;
1204 //So far so good, now we try to position our find pointers.
1205 if(SUCCEEDED(document->QueryInterface(wxIID_IMarkupServices,(void **)&pIMS)))
1206 {
1207 wxIMarkupPointer *begin = m_findPointers[m_findPosition].begin, *end = m_findPointers[m_findPosition].end;
1208 if(pIMS->MoveRangeToPointers(begin,end,range) == S_OK && range->select() == S_OK)
1209 {
1210 ret = m_findPosition;
1211 }
1212 }
1213 }
1214 }
1215 }
1216 return ret;
1217 }
1218
FindClear()1219 void wxWebViewIE::FindClear()
1220 {
1221 //Reset find variables.
1222 m_findText.Empty();
1223 m_findFlags = wxWEBVIEW_FIND_DEFAULT;
1224 m_findPosition = -1;
1225
1226 //The m_findPointers contains pointers for the found text.
1227 //Since it uses ref counting we call release on the pointers first
1228 //before we remove them from the vector. In other words do not just
1229 //remove elements from m_findPointers without calling release first
1230 //or you will get a memory leak.
1231 size_t count = m_findPointers.size();
1232 for(size_t i = 0; i < count; i++)
1233 {
1234 m_findPointers[i].begin->Release();
1235 m_findPointers[i].end->Release();
1236 }
1237 m_findPointers.clear();
1238 }
1239
EnableControlFeature(long flag,bool enable)1240 bool wxWebViewIE::EnableControlFeature(long flag, bool enable)
1241 {
1242 #if wxUSE_DYNLIB_CLASS
1243
1244 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
1245 if( urlMon.IsLoaded() &&
1246 urlMon.HasSymbol("CoInternetSetFeatureEnabled") &&
1247 urlMon.HasSymbol("CoInternetIsFeatureEnabled"))
1248 {
1249 typedef HRESULT (WINAPI *CoInternetSetFeatureEnabled_t)(DWORD, DWORD, BOOL);
1250 typedef HRESULT (WINAPI *CoInternetIsFeatureEnabled_t)(DWORD, DWORD);
1251
1252 wxDYNLIB_FUNCTION(CoInternetSetFeatureEnabled_t, CoInternetSetFeatureEnabled, urlMon);
1253 wxDYNLIB_FUNCTION(CoInternetIsFeatureEnabled_t, CoInternetIsFeatureEnabled, urlMon);
1254
1255 HRESULT hr = (*pfnCoInternetIsFeatureEnabled)(flag,
1256 0x2 /* SET_FEATURE_ON_PROCESS */);
1257 if((hr == S_OK && enable) || (hr == S_FALSE && !enable))
1258 return true;
1259
1260 hr = (*pfnCoInternetSetFeatureEnabled)(flag,
1261 0x2/* SET_FEATURE_ON_PROCESS */,
1262 (enable ? TRUE : FALSE));
1263 if ( FAILED(hr) )
1264 {
1265 wxLogApiError(wxT("CoInternetSetFeatureEnabled"), hr);
1266 return false;
1267 }
1268 return true;
1269 }
1270 return false;
1271 #else
1272 wxUnusedVar(flag);
1273 wxUnusedVar(enable);
1274 return false;
1275 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1276 }
1277
onActiveXEvent(wxActiveXEvent & evt)1278 void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
1279 {
1280 if (m_webBrowser == NULL) return;
1281
1282 switch (evt.GetDispatchId())
1283 {
1284 case DISPID_BEFORENAVIGATE2:
1285 {
1286 m_isBusy = true;
1287
1288 wxString url = evt[1].GetString();
1289 wxString target = evt[3].GetString();
1290
1291 wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATING,
1292 GetId(), url, target);
1293
1294 //skip empty javascript events.
1295 if(url == "javascript:\"\"" && target.IsEmpty())
1296 {
1297 event.Veto();
1298 }
1299 else
1300 {
1301 event.SetEventObject(this);
1302 HandleWindowEvent(event);
1303 }
1304
1305 if (!event.IsAllowed())
1306 {
1307 wxActiveXEventNativeMSW* nativeParams =
1308 evt.GetNativeParameters();
1309 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[0]) = VARIANT_TRUE;
1310 }
1311
1312 // at this point, either the navigation event has been cancelled
1313 // and we're not busy, either it was accepted and IWebBrowser2's
1314 // Busy property will be true; so we don't need our override
1315 // flag anymore.
1316 m_isBusy = false;
1317
1318 break;
1319 }
1320
1321 case DISPID_NAVIGATECOMPLETE2:
1322 {
1323 wxString url = evt[1].GetString();
1324 // TODO: set target parameter if possible
1325 wxString target = wxEmptyString;
1326 wxWebViewEvent event(wxEVT_WEBVIEW_NAVIGATED,
1327 GetId(), url, target);
1328 event.SetEventObject(this);
1329 HandleWindowEvent(event);
1330 break;
1331 }
1332
1333 case DISPID_PROGRESSCHANGE:
1334 {
1335 // download progress
1336 break;
1337 }
1338
1339 case DISPID_DOCUMENTCOMPLETE:
1340 {
1341 //Only send a complete even if we are actually finished, this brings
1342 //the event in to line with webkit
1343 READYSTATE rs;
1344 m_webBrowser->get_ReadyState( &rs );
1345 if(rs != READYSTATE_COMPLETE)
1346 break;
1347
1348 wxString url = evt[1].GetString();
1349
1350 //As we are complete we also add to the history list, but not if the
1351 //page is not the main page, ie it is a subframe
1352 //We also have to check if we are loading a file:// url, if so we
1353 //need to change the comparison as ie passes back a different style
1354 //of url
1355 if(m_historyEnabled && !m_historyLoadingFromList &&
1356 (url == GetCurrentURL() ||
1357 (GetCurrentURL().substr(0, 4) == "file" &&
1358 wxFileSystem::URLToFileName(GetCurrentURL()).GetFullPath() == url)))
1359 {
1360 //If we are not at the end of the list, then erase everything
1361 //between us and the end before adding the new page
1362 if(m_historyPosition != static_cast<int>(m_historyList.size()) - 1)
1363 {
1364 m_historyList.erase(m_historyList.begin() + m_historyPosition + 1,
1365 m_historyList.end());
1366 }
1367 wxSharedPtr<wxWebViewHistoryItem> item(new wxWebViewHistoryItem(url, GetCurrentTitle()));
1368 m_historyList.push_back(item);
1369 m_historyPosition++;
1370 }
1371 //Reset as we are done now
1372 m_historyLoadingFromList = false;
1373 //Reset the find values.
1374 FindClear();
1375 // TODO: set target parameter if possible
1376 wxString target = wxEmptyString;
1377 wxWebViewEvent event(wxEVT_WEBVIEW_LOADED, GetId(),
1378 url, target);
1379 event.SetEventObject(this);
1380 HandleWindowEvent(event);
1381 break;
1382 }
1383
1384 case DISPID_STATUSTEXTCHANGE:
1385 {
1386 break;
1387 }
1388
1389 case DISPID_TITLECHANGE:
1390 {
1391 wxString title = evt[0].GetString();
1392
1393 wxWebViewEvent event(wxEVT_WEBVIEW_TITLE_CHANGED,
1394 GetId(), GetCurrentURL(), "");
1395 event.SetString(title);
1396 event.SetEventObject(this);
1397 HandleWindowEvent(event);
1398 break;
1399 }
1400
1401 case DISPID_NAVIGATEERROR:
1402 {
1403 wxWebViewEvent event(wxEVT_WEBVIEW_ERROR, GetId(),
1404 evt[1].GetString(), evt[2].GetString());
1405 event.SetEventObject(this);
1406
1407 switch (evt[3].GetLong())
1408 {
1409 // 400 Error codes
1410 WX_ERROR_CASE(HTTP_STATUS_BAD_REQUEST, wxWEBVIEW_NAV_ERR_REQUEST)
1411 WX_ERROR_CASE(HTTP_STATUS_DENIED, wxWEBVIEW_NAV_ERR_AUTH)
1412 WX_ERROR_CASE(HTTP_STATUS_PAYMENT_REQ, wxWEBVIEW_NAV_ERR_OTHER)
1413 WX_ERROR_CASE(HTTP_STATUS_FORBIDDEN, wxWEBVIEW_NAV_ERR_AUTH)
1414 WX_ERROR_CASE(HTTP_STATUS_NOT_FOUND, wxWEBVIEW_NAV_ERR_NOT_FOUND)
1415 WX_ERROR_CASE(HTTP_STATUS_BAD_METHOD, wxWEBVIEW_NAV_ERR_REQUEST)
1416 WX_ERROR_CASE(HTTP_STATUS_NONE_ACCEPTABLE, wxWEBVIEW_NAV_ERR_OTHER)
1417 WX_ERROR_CASE(HTTP_STATUS_PROXY_AUTH_REQ, wxWEBVIEW_NAV_ERR_AUTH)
1418 WX_ERROR_CASE(HTTP_STATUS_REQUEST_TIMEOUT, wxWEBVIEW_NAV_ERR_CONNECTION)
1419 WX_ERROR_CASE(HTTP_STATUS_CONFLICT, wxWEBVIEW_NAV_ERR_REQUEST)
1420 WX_ERROR_CASE(HTTP_STATUS_GONE, wxWEBVIEW_NAV_ERR_NOT_FOUND)
1421 WX_ERROR_CASE(HTTP_STATUS_LENGTH_REQUIRED, wxWEBVIEW_NAV_ERR_REQUEST)
1422 WX_ERROR_CASE(HTTP_STATUS_PRECOND_FAILED, wxWEBVIEW_NAV_ERR_REQUEST)
1423 WX_ERROR_CASE(HTTP_STATUS_REQUEST_TOO_LARGE, wxWEBVIEW_NAV_ERR_REQUEST)
1424 WX_ERROR_CASE(HTTP_STATUS_URI_TOO_LONG, wxWEBVIEW_NAV_ERR_REQUEST)
1425 WX_ERROR_CASE(HTTP_STATUS_UNSUPPORTED_MEDIA, wxWEBVIEW_NAV_ERR_REQUEST)
1426 WX_ERROR_CASE(HTTP_STATUS_RETRY_WITH, wxWEBVIEW_NAV_ERR_OTHER)
1427
1428 // 500 - Error codes
1429 WX_ERROR_CASE(HTTP_STATUS_SERVER_ERROR, wxWEBVIEW_NAV_ERR_CONNECTION)
1430 WX_ERROR_CASE(HTTP_STATUS_NOT_SUPPORTED, wxWEBVIEW_NAV_ERR_CONNECTION)
1431 WX_ERROR_CASE(HTTP_STATUS_BAD_GATEWAY, wxWEBVIEW_NAV_ERR_CONNECTION)
1432 WX_ERROR_CASE(HTTP_STATUS_SERVICE_UNAVAIL, wxWEBVIEW_NAV_ERR_CONNECTION)
1433 WX_ERROR_CASE(HTTP_STATUS_GATEWAY_TIMEOUT, wxWEBVIEW_NAV_ERR_CONNECTION)
1434 WX_ERROR_CASE(HTTP_STATUS_VERSION_NOT_SUP, wxWEBVIEW_NAV_ERR_REQUEST)
1435
1436 // URL Moniker error codes
1437 WX_ERROR_CASE(INET_E_INVALID_URL, wxWEBVIEW_NAV_ERR_REQUEST)
1438 WX_ERROR_CASE(INET_E_NO_SESSION, wxWEBVIEW_NAV_ERR_CONNECTION)
1439 WX_ERROR_CASE(INET_E_CANNOT_CONNECT, wxWEBVIEW_NAV_ERR_CONNECTION)
1440 WX_ERROR_CASE(INET_E_RESOURCE_NOT_FOUND, wxWEBVIEW_NAV_ERR_NOT_FOUND)
1441 WX_ERROR_CASE(INET_E_OBJECT_NOT_FOUND, wxWEBVIEW_NAV_ERR_NOT_FOUND)
1442 WX_ERROR_CASE(INET_E_DATA_NOT_AVAILABLE, wxWEBVIEW_NAV_ERR_NOT_FOUND)
1443 WX_ERROR_CASE(INET_E_DOWNLOAD_FAILURE, wxWEBVIEW_NAV_ERR_CONNECTION)
1444 WX_ERROR_CASE(INET_E_AUTHENTICATION_REQUIRED, wxWEBVIEW_NAV_ERR_AUTH)
1445 WX_ERROR_CASE(INET_E_NO_VALID_MEDIA, wxWEBVIEW_NAV_ERR_REQUEST)
1446 WX_ERROR_CASE(INET_E_CONNECTION_TIMEOUT, wxWEBVIEW_NAV_ERR_CONNECTION)
1447 WX_ERROR_CASE(INET_E_INVALID_REQUEST, wxWEBVIEW_NAV_ERR_REQUEST)
1448 WX_ERROR_CASE(INET_E_UNKNOWN_PROTOCOL, wxWEBVIEW_NAV_ERR_REQUEST)
1449 WX_ERROR_CASE(INET_E_SECURITY_PROBLEM, wxWEBVIEW_NAV_ERR_SECURITY)
1450 WX_ERROR_CASE(INET_E_CANNOT_LOAD_DATA, wxWEBVIEW_NAV_ERR_OTHER)
1451 WX_ERROR_CASE(INET_E_REDIRECT_FAILED, wxWEBVIEW_NAV_ERR_OTHER)
1452 WX_ERROR_CASE(INET_E_REDIRECT_TO_DIR, wxWEBVIEW_NAV_ERR_REQUEST)
1453 WX_ERROR_CASE(INET_E_CANNOT_LOCK_REQUEST, wxWEBVIEW_NAV_ERR_OTHER)
1454 WX_ERROR_CASE(INET_E_USE_EXTEND_BINDING, wxWEBVIEW_NAV_ERR_OTHER)
1455 WX_ERROR_CASE(INET_E_TERMINATED_BIND, wxWEBVIEW_NAV_ERR_OTHER)
1456 WX_ERROR_CASE(INET_E_INVALID_CERTIFICATE, wxWEBVIEW_NAV_ERR_CERTIFICATE)
1457 WX_ERROR_CASE(INET_E_CODE_DOWNLOAD_DECLINED, wxWEBVIEW_NAV_ERR_USER_CANCELLED)
1458 WX_ERROR_CASE(INET_E_RESULT_DISPATCHED, wxWEBVIEW_NAV_ERR_OTHER)
1459 WX_ERROR_CASE(INET_E_CANNOT_REPLACE_SFP_FILE, wxWEBVIEW_NAV_ERR_SECURITY)
1460 WX_ERROR_CASE(INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY, wxWEBVIEW_NAV_ERR_SECURITY)
1461 WX_ERROR_CASE(INET_E_CODE_INSTALL_SUPPRESSED, wxWEBVIEW_NAV_ERR_SECURITY)
1462 }
1463 HandleWindowEvent(event);
1464 break;
1465 }
1466 case DISPID_NEWWINDOW3:
1467 {
1468 wxString url = evt[4].GetString();
1469
1470 wxWebViewEvent event(wxEVT_WEBVIEW_NEWWINDOW,
1471 GetId(), url, wxEmptyString);
1472 event.SetEventObject(this);
1473 HandleWindowEvent(event);
1474
1475 //We always cancel this event otherwise an Internet Exporer window
1476 //is opened for the url
1477 wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters();
1478 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE;
1479 break;
1480 }
1481 }
1482
1483 evt.Skip();
1484 }
1485
VirtualProtocol(wxSharedPtr<wxWebViewHandler> handler)1486 VirtualProtocol::VirtualProtocol(wxSharedPtr<wxWebViewHandler> handler)
1487 {
1488 m_file = NULL;
1489 m_handler = handler;
1490 }
1491
1492 BEGIN_IID_TABLE(VirtualProtocol)
1493 ADD_IID(Unknown)
1494 ADD_RAW_IID(wxIID_IInternetProtocolRoot)
1495 ADD_RAW_IID(wxIID_IInternetProtocol)
1496 END_IID_TABLE;
1497
IMPLEMENT_IUNKNOWN_METHODS(VirtualProtocol)1498 IMPLEMENT_IUNKNOWN_METHODS(VirtualProtocol)
1499
1500 HRESULT STDMETHODCALLTYPE VirtualProtocol::Start(LPCWSTR szUrl, wxIInternetProtocolSink *pOIProtSink,
1501 wxIInternetBindInfo *pOIBindInfo, DWORD grfPI,
1502 HANDLE_PTR dwReserved)
1503 {
1504 wxUnusedVar(szUrl);
1505 wxUnusedVar(pOIBindInfo);
1506 wxUnusedVar(grfPI);
1507 wxUnusedVar(dwReserved);
1508 m_protocolSink = pOIProtSink;
1509
1510 //We get the file itself from the protocol handler
1511 m_file = m_handler->GetFile(szUrl);
1512
1513
1514 if(!m_file)
1515 return INET_E_RESOURCE_NOT_FOUND;
1516
1517 //We return the stream length for current and total size as we can always
1518 //read the whole file from the stream
1519 wxFileOffset length = m_file->GetStream()->GetLength();
1520 m_protocolSink->ReportData(wxBSCF_FIRSTDATANOTIFICATION |
1521 wxBSCF_DATAFULLYAVAILABLE |
1522 wxBSCF_LASTDATANOTIFICATION,
1523 length, length);
1524 return S_OK;
1525 }
1526
Read(void * pv,ULONG cb,ULONG * pcbRead)1527 HRESULT STDMETHODCALLTYPE VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
1528 {
1529 //If the file is null we return false to indicte it is finished
1530 if(!m_file)
1531 return S_FALSE;
1532
1533 wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
1534 *pcbRead = m_file->GetStream()->LastRead();
1535
1536 if(err == wxSTREAM_NO_ERROR)
1537 {
1538 if(*pcbRead < cb)
1539 {
1540 wxDELETE(m_file);
1541 m_protocolSink->ReportResult(S_OK, 0, NULL);
1542 }
1543 //As we are not eof there is more data
1544 return S_OK;
1545 }
1546 else if(err == wxSTREAM_EOF)
1547 {
1548 wxDELETE(m_file);
1549 m_protocolSink->ReportResult(S_OK, 0, NULL);
1550 //We are eof and so finished
1551 return S_OK;
1552 }
1553 else if(err == wxSTREAM_READ_ERROR)
1554 {
1555 wxDELETE(m_file);
1556 return INET_E_DOWNLOAD_FAILURE;
1557 }
1558 else
1559 {
1560 //Dummy return to suppress a compiler warning
1561 wxFAIL;
1562 return INET_E_DOWNLOAD_FAILURE;
1563 }
1564 }
1565
1566 BEGIN_IID_TABLE(ClassFactory)
1567 ADD_IID(Unknown)
1568 ADD_IID(ClassFactory)
1569 END_IID_TABLE;
1570
IMPLEMENT_IUNKNOWN_METHODS(ClassFactory)1571 IMPLEMENT_IUNKNOWN_METHODS(ClassFactory)
1572
1573 HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
1574 void ** ppvObject)
1575 {
1576 if (pUnkOuter)
1577 return CLASS_E_NOAGGREGATION;
1578 VirtualProtocol* vp = new VirtualProtocol(m_handler);
1579 vp->AddRef();
1580 HRESULT hr = vp->QueryInterface(riid, ppvObject);
1581 vp->Release();
1582 return hr;
1583
1584 }
1585
LockServer(BOOL fLock)1586 STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
1587 {
1588 wxUnusedVar(fLock);
1589 return S_OK;
1590 }
1591
wxIEContainer(wxWindow * parent,REFIID iid,IUnknown * pUnk,DocHostUIHandler * uiHandler)1592 wxIEContainer::wxIEContainer(wxWindow *parent, REFIID iid, IUnknown *pUnk,
1593 DocHostUIHandler* uiHandler) :
1594 wxActiveXContainer(parent,iid,pUnk)
1595 {
1596 m_uiHandler = uiHandler;
1597 }
1598
~wxIEContainer()1599 wxIEContainer::~wxIEContainer()
1600 {
1601 }
1602
QueryClientSiteInterface(REFIID iid,void ** _interface,const char * & desc)1603 bool wxIEContainer::QueryClientSiteInterface(REFIID iid, void **_interface,
1604 const char *&desc)
1605 {
1606 if (m_uiHandler && IsEqualIID(iid, wxIID_IDocHostUIHandler))
1607 {
1608 *_interface = (IUnknown *) (wxIDocHostUIHandler *) m_uiHandler;
1609 desc = "IDocHostUIHandler";
1610 return true;
1611 }
1612 return false;
1613 }
1614
ShowContextMenu(DWORD dwID,POINT * ppt,IUnknown * pcmdtReserved,IDispatch * pdispReserved)1615 HRESULT wxSTDCALL DocHostUIHandler::ShowContextMenu(DWORD dwID, POINT *ppt,
1616 IUnknown *pcmdtReserved,
1617 IDispatch *pdispReserved)
1618 {
1619 wxUnusedVar(dwID);
1620 wxUnusedVar(ppt);
1621 wxUnusedVar(pcmdtReserved);
1622 wxUnusedVar(pdispReserved);
1623 if(m_browser->IsContextMenuEnabled())
1624 return E_NOTIMPL;
1625 else
1626 return S_OK;
1627 }
1628
GetHostInfo(DOCHOSTUIINFO * pInfo)1629 HRESULT wxSTDCALL DocHostUIHandler::GetHostInfo(DOCHOSTUIINFO *pInfo)
1630 {
1631 //don't show 3d border and enable themes.
1632 pInfo->dwFlags = pInfo->dwFlags | DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_THEME;
1633 return S_OK;
1634 }
1635
ShowUI(DWORD dwID,IOleInPlaceActiveObject * pActiveObject,IOleCommandTarget * pCommandTarget,IOleInPlaceFrame * pFrame,IOleInPlaceUIWindow * pDoc)1636 HRESULT wxSTDCALL DocHostUIHandler::ShowUI(DWORD dwID,
1637 IOleInPlaceActiveObject *pActiveObject,
1638 IOleCommandTarget *pCommandTarget,
1639 IOleInPlaceFrame *pFrame,
1640 IOleInPlaceUIWindow *pDoc)
1641 {
1642 wxUnusedVar(dwID);
1643 wxUnusedVar(pActiveObject);
1644 wxUnusedVar(pCommandTarget);
1645 wxUnusedVar(pFrame);
1646 wxUnusedVar(pDoc);
1647 return S_FALSE;
1648 }
1649
HideUI(void)1650 HRESULT wxSTDCALL DocHostUIHandler::HideUI(void)
1651 {
1652 return E_NOTIMPL;
1653 }
1654
UpdateUI(void)1655 HRESULT wxSTDCALL DocHostUIHandler::UpdateUI(void)
1656 {
1657 return E_NOTIMPL;
1658 }
1659
EnableModeless(BOOL fEnable)1660 HRESULT wxSTDCALL DocHostUIHandler::EnableModeless(BOOL fEnable)
1661 {
1662 wxUnusedVar(fEnable);
1663 return E_NOTIMPL;
1664 }
1665
OnDocWindowActivate(BOOL fActivate)1666 HRESULT wxSTDCALL DocHostUIHandler::OnDocWindowActivate(BOOL fActivate)
1667 {
1668 wxUnusedVar(fActivate);
1669 return E_NOTIMPL;
1670 }
1671
OnFrameWindowActivate(BOOL fActivate)1672 HRESULT wxSTDCALL DocHostUIHandler::OnFrameWindowActivate(BOOL fActivate)
1673 {
1674 wxUnusedVar(fActivate);
1675 return E_NOTIMPL;
1676 }
1677
ResizeBorder(LPCRECT prcBorder,IOleInPlaceUIWindow * pUIWindow,BOOL fFrameWindow)1678 HRESULT wxSTDCALL DocHostUIHandler::ResizeBorder(LPCRECT prcBorder,
1679 IOleInPlaceUIWindow *pUIWindow,
1680 BOOL fFrameWindow)
1681 {
1682 wxUnusedVar(prcBorder);
1683 wxUnusedVar(pUIWindow);
1684 wxUnusedVar(fFrameWindow);
1685 return E_NOTIMPL;
1686 }
1687
TranslateAccelerator(LPMSG lpMsg,const GUID * pguidCmdGroup,DWORD nCmdID)1688 HRESULT wxSTDCALL DocHostUIHandler::TranslateAccelerator(LPMSG lpMsg,
1689 const GUID *pguidCmdGroup,
1690 DWORD nCmdID)
1691 {
1692 if(lpMsg && lpMsg->message == WM_KEYDOWN)
1693 {
1694 // check control is down but that it isn't right-alt which is mapped to
1695 // alt + ctrl
1696 if(GetKeyState(VK_CONTROL) & 0x8000 &&
1697 !(GetKeyState(VK_MENU) & 0x8000))
1698 {
1699 //skip the accelerators used by the control
1700 switch(lpMsg->wParam)
1701 {
1702 case 'F':
1703 case 'L':
1704 case 'N':
1705 case 'O':
1706 case 'P':
1707 return S_OK;
1708 }
1709 }
1710 //skip F5
1711 if(lpMsg->wParam == VK_F5)
1712 {
1713 return S_OK;
1714 }
1715 }
1716
1717 wxUnusedVar(pguidCmdGroup);
1718 wxUnusedVar(nCmdID);
1719 return E_NOTIMPL;
1720 }
1721
GetOptionKeyPath(LPOLESTR * pchKey,DWORD dw)1722 HRESULT wxSTDCALL DocHostUIHandler::GetOptionKeyPath(LPOLESTR *pchKey,DWORD dw)
1723 {
1724 wxUnusedVar(pchKey);
1725 wxUnusedVar(dw);
1726 return E_NOTIMPL;
1727 }
1728
GetDropTarget(IDropTarget * pDropTarget,IDropTarget ** ppDropTarget)1729 HRESULT wxSTDCALL DocHostUIHandler::GetDropTarget(IDropTarget *pDropTarget,
1730 IDropTarget **ppDropTarget)
1731 {
1732 wxUnusedVar(pDropTarget);
1733 wxUnusedVar(ppDropTarget);
1734 return E_NOTIMPL;
1735 }
1736
GetExternal(IDispatch ** ppDispatch)1737 HRESULT wxSTDCALL DocHostUIHandler::GetExternal(IDispatch **ppDispatch)
1738 {
1739 wxUnusedVar(ppDispatch);
1740 return E_NOTIMPL;
1741 }
1742
TranslateUrl(DWORD dwTranslate,OLECHAR * pchURLIn,OLECHAR ** ppchURLOut)1743 HRESULT wxSTDCALL DocHostUIHandler::TranslateUrl(DWORD dwTranslate,
1744 OLECHAR *pchURLIn,
1745 OLECHAR **ppchURLOut)
1746 {
1747 wxUnusedVar(dwTranslate);
1748 wxUnusedVar(pchURLIn);
1749 wxUnusedVar(ppchURLOut);
1750 return E_NOTIMPL;
1751 }
1752
FilterDataObject(IDataObject * pDO,IDataObject ** ppDORet)1753 HRESULT wxSTDCALL DocHostUIHandler::FilterDataObject(IDataObject *pDO, IDataObject **ppDORet)
1754 {
1755 wxUnusedVar(pDO);
1756 wxUnusedVar(ppDORet);
1757 return E_NOTIMPL;
1758 }
1759
1760 BEGIN_IID_TABLE(DocHostUIHandler)
1761 ADD_IID(Unknown)
1762 ADD_RAW_IID(wxIID_IDocHostUIHandler)
1763 END_IID_TABLE;
1764
1765 IMPLEMENT_IUNKNOWN_METHODS(DocHostUIHandler)
1766
1767 #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
1768