Remove double buffering from wxWebViewIE as this is handled by the web browser contro...
[wxWidgets.git] / src / msw / webview_ie.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/webview_ie.cpp
3 // Purpose: wxMSW wxWebViewIE class implementation for web view component
4 // Author: Marianne Gagnon
5 // Id: $Id$
6 // Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if defined(__BORLANDC__)
14 #pragma hdrstop
15 #endif
16
17 #include "wx/msw/webview_ie.h"
18
19 #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
20
21 #include <olectl.h>
22 #include <oleidl.h>
23 #include <exdispid.h>
24 #include <exdisp.h>
25 #include <mshtml.h>
26 #include "wx/msw/registry.h"
27 #include "wx/msw/missing.h"
28 #include "wx/filesys.h"
29 #include "wx/dynlib.h"
30 #include <initguid.h>
31
32 /* These GUID definitions are our own implementation to support interfaces
33 * normally in urlmon.h. See include/wx/msw/webview_ie.h
34 */
35
36 namespace {
37
38 DEFINE_GUID(wxIID_IInternetProtocolRoot,0x79eac9e3,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
39 DEFINE_GUID(wxIID_IInternetProtocol,0x79eac9e4,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
40
41 }
42
43 wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewIE, wxWebView);
44
45 BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
46 EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
47 EVT_ERASE_BACKGROUND(wxWebViewIE::onEraseBg)
48 END_EVENT_TABLE()
49
50 bool wxWebViewIE::Create(wxWindow* parent,
51 wxWindowID id,
52 const wxString& url,
53 const wxPoint& pos,
54 const wxSize& size,
55 long style,
56 const wxString& name)
57 {
58 if (!wxControl::Create(parent, id, pos, size, style,
59 wxDefaultValidator, name))
60 {
61 return false;
62 }
63
64 m_webBrowser = NULL;
65 m_isBusy = false;
66 m_historyLoadingFromList = false;
67 m_historyEnabled = true;
68 m_historyPosition = -1;
69 m_zoomType = wxWEB_VIEW_ZOOM_TYPE_TEXT;
70
71 if (::CoCreateInstance(CLSID_WebBrowser, NULL,
72 CLSCTX_INPROC_SERVER, // CLSCTX_INPROC,
73 IID_IWebBrowser2 , (void**)&m_webBrowser) != 0)
74 {
75 wxLogError("Failed to initialize IE, CoCreateInstance returned an error");
76 return false;
77 }
78
79 m_ie.SetDispatchPtr(m_webBrowser); // wxAutomationObject will release itself
80
81 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
82 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
83
84 m_container = new wxActiveXContainer(this, IID_IWebBrowser2, m_webBrowser);
85
86 LoadURL(url);
87 return true;
88 }
89
90 wxWebViewIE::~wxWebViewIE()
91 {
92 for(unsigned int i = 0; i < m_factories.size(); i++)
93 {
94 m_factories[i]->Release();
95 }
96 }
97
98 void wxWebViewIE::LoadURL(const wxString& url)
99 {
100 m_ie.CallMethod("Navigate", wxConvertStringToOle(url));
101 }
102
103 void wxWebViewIE::SetPage(const wxString& html, const wxString& baseUrl)
104 {
105 BSTR bstr = SysAllocString(html.wc_str());
106
107 // Creates a new one-dimensional array
108 SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
109 if (psaStrings != NULL)
110 {
111 VARIANT *param;
112
113 HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
114 param->vt = VT_BSTR;
115 param->bstrVal = bstr;
116 hr = SafeArrayUnaccessData(psaStrings);
117
118 IHTMLDocument2* document = GetDocument();
119 document->write(psaStrings);
120 document->Release();
121
122 // SafeArrayDestroy calls SysFreeString for each BSTR
123 SafeArrayDestroy(psaStrings);
124
125 //We send the events when we are done to mimic webkit
126 //Navigated event
127 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
128 GetId(), baseUrl, "");
129 event.SetEventObject(this);
130 HandleWindowEvent(event);
131
132 //Document complete event
133 event.SetEventType(wxEVT_COMMAND_WEB_VIEW_LOADED);
134 event.SetEventObject(this);
135 HandleWindowEvent(event);
136 }
137 else
138 {
139 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL");
140 }
141
142 }
143
144 wxString wxWebViewIE::GetPageSource() const
145 {
146 IHTMLDocument2* document = GetDocument();
147 IHTMLElement *bodyTag = NULL;
148 IHTMLElement *htmlTag = NULL;
149 wxString source;
150 HRESULT hr = document->get_body(&bodyTag);
151 if(SUCCEEDED(hr))
152 {
153 hr = bodyTag->get_parentElement(&htmlTag);
154 if(SUCCEEDED(hr))
155 {
156 BSTR bstr;
157 htmlTag->get_outerHTML(&bstr);
158 source = wxString(bstr);
159 htmlTag->Release();
160 }
161 bodyTag->Release();
162 }
163
164 document->Release();
165 return source;
166 }
167
168 wxWebViewZoom wxWebViewIE::GetZoom() const
169 {
170 switch( m_zoomType )
171 {
172 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
173 return GetIEOpticalZoom();
174 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
175 return GetIETextZoom();
176 default:
177 wxFAIL;
178 }
179
180 //Dummy return to stop compiler warnings
181 return wxWEB_VIEW_ZOOM_MEDIUM;
182
183 }
184
185 void wxWebViewIE::SetZoom(wxWebViewZoom zoom)
186 {
187 switch( m_zoomType )
188 {
189 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
190 SetIEOpticalZoom(zoom);
191 break;
192 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
193 SetIETextZoom(zoom);
194 break;
195 default:
196 wxFAIL;
197 }
198 }
199
200 void wxWebViewIE::SetIETextZoom(wxWebViewZoom level)
201 {
202 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
203 //is 0 to 4 so the check is unnecessary, these match exactly with the
204 //enum values
205 VARIANT zoomVariant;
206 VariantInit (&zoomVariant);
207 V_VT(&zoomVariant) = VT_I4;
208 V_I4(&zoomVariant) = level;
209
210 #if wxDEBUG_LEVEL
211 HRESULT result =
212 #endif
213 m_webBrowser->ExecWB(OLECMDID_ZOOM,
214 OLECMDEXECOPT_DONTPROMPTUSER,
215 &zoomVariant, NULL);
216 wxASSERT(result == S_OK);
217 }
218
219 wxWebViewZoom wxWebViewIE::GetIETextZoom() const
220 {
221 VARIANT zoomVariant;
222 VariantInit (&zoomVariant);
223 V_VT(&zoomVariant) = VT_I4;
224
225 #if wxDEBUG_LEVEL
226 HRESULT result =
227 #endif
228 m_webBrowser->ExecWB(OLECMDID_ZOOM,
229 OLECMDEXECOPT_DONTPROMPTUSER,
230 NULL, &zoomVariant);
231 wxASSERT(result == S_OK);
232
233 //We can safely cast here as we know that the range matches our enum
234 return static_cast<wxWebViewZoom>(V_I4(&zoomVariant));
235 }
236
237 void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level)
238 {
239 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
240 //is 10 to 1000 so the check is unnecessary
241 VARIANT zoomVariant;
242 VariantInit (&zoomVariant);
243 V_VT(&zoomVariant) = VT_I4;
244
245 //We make a somewhat arbitray map here, taken from values used by webkit
246 switch(level)
247 {
248 case wxWEB_VIEW_ZOOM_TINY:
249 V_I4(&zoomVariant) = 60;
250 break;
251 case wxWEB_VIEW_ZOOM_SMALL:
252 V_I4(&zoomVariant) = 80;
253 break;
254 case wxWEB_VIEW_ZOOM_MEDIUM:
255 V_I4(&zoomVariant) = 100;
256 break;
257 case wxWEB_VIEW_ZOOM_LARGE:
258 V_I4(&zoomVariant) = 130;
259 break;
260 case wxWEB_VIEW_ZOOM_LARGEST:
261 V_I4(&zoomVariant) = 160;
262 break;
263 default:
264 wxFAIL;
265 }
266
267 #if wxDEBUG_LEVEL
268 HRESULT result =
269 #endif
270 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
271 OLECMDEXECOPT_DODEFAULT,
272 &zoomVariant,
273 NULL);
274 wxASSERT(result == S_OK);
275 }
276
277 wxWebViewZoom wxWebViewIE::GetIEOpticalZoom() const
278 {
279 VARIANT zoomVariant;
280 VariantInit (&zoomVariant);
281 V_VT(&zoomVariant) = VT_I4;
282
283 #if wxDEBUG_LEVEL
284 HRESULT result =
285 #endif
286 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
287 OLECMDEXECOPT_DODEFAULT, NULL,
288 &zoomVariant);
289 wxASSERT(result == S_OK);
290
291 const int zoom = V_I4(&zoomVariant);
292
293 //We make a somewhat arbitray map here, taken from values used by webkit
294 if (zoom <= 65)
295 {
296 return wxWEB_VIEW_ZOOM_TINY;
297 }
298 else if (zoom > 65 && zoom <= 90)
299 {
300 return wxWEB_VIEW_ZOOM_SMALL;
301 }
302 else if (zoom > 90 && zoom <= 115)
303 {
304 return wxWEB_VIEW_ZOOM_MEDIUM;
305 }
306 else if (zoom > 115 && zoom <= 145)
307 {
308 return wxWEB_VIEW_ZOOM_LARGE;
309 }
310 else /*if (zoom > 145) */ //Using else removes a compiler warning
311 {
312 return wxWEB_VIEW_ZOOM_LARGEST;
313 }
314 }
315
316 void wxWebViewIE::SetZoomType(wxWebViewZoomType type)
317 {
318 m_zoomType = type;
319 }
320
321 wxWebViewZoomType wxWebViewIE::GetZoomType() const
322 {
323 return m_zoomType;
324 }
325
326 bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const
327 {
328 //IE 6 and below only support text zoom, so check the registry to see what
329 //version we actually have
330 wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer");
331 wxString value;
332 key.QueryValue("Version", value);
333
334 long version = wxAtoi(value.Left(1));
335 if(version <= 6 && type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
336 return false;
337 else
338 return true;
339 }
340
341 void wxWebViewIE::Print()
342 {
343 m_webBrowser->ExecWB(OLECMDID_PRINTPREVIEW,
344 OLECMDEXECOPT_DODEFAULT, NULL, NULL);
345 }
346
347 bool wxWebViewIE::CanGoBack() const
348 {
349 if(m_historyEnabled)
350 return m_historyPosition > 0;
351 else
352 return false;
353 }
354
355 bool wxWebViewIE::CanGoForward() const
356 {
357 if(m_historyEnabled)
358 return m_historyPosition != static_cast<int>(m_historyList.size()) - 1;
359 else
360 return false;
361 }
362
363 void wxWebViewIE::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
364 {
365 int pos = -1;
366 for(unsigned int i = 0; i < m_historyList.size(); i++)
367 {
368 //We compare the actual pointers to find the correct item
369 if(m_historyList[i].get() == item.get())
370 pos = i;
371 }
372 wxASSERT_MSG(pos != static_cast<int>(m_historyList.size()),
373 "invalid history item");
374 m_historyLoadingFromList = true;
375 LoadURL(item->GetUrl());
376 m_historyPosition = pos;
377 }
378
379 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetBackwardHistory()
380 {
381 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
382 //As we don't have std::copy or an iterator constructor in the wxwidgets
383 //native vector we construct it by hand
384 for(int i = 0; i < m_historyPosition; i++)
385 {
386 backhist.push_back(m_historyList[i]);
387 }
388 return backhist;
389 }
390
391 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetForwardHistory()
392 {
393 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
394 //As we don't have std::copy or an iterator constructor in the wxwidgets
395 //native vector we construct it by hand
396 for(int i = m_historyPosition + 1; i < static_cast<int>(m_historyList.size()); i++)
397 {
398 forwardhist.push_back(m_historyList[i]);
399 }
400 return forwardhist;
401 }
402
403 void wxWebViewIE::GoBack()
404 {
405 LoadHistoryItem(m_historyList[m_historyPosition - 1]);
406 }
407
408 void wxWebViewIE::GoForward()
409 {
410 LoadHistoryItem(m_historyList[m_historyPosition + 1]);
411 }
412
413 void wxWebViewIE::Stop()
414 {
415 m_ie.CallMethod("Stop");
416 }
417
418 void wxWebViewIE::ClearHistory()
419 {
420 m_historyList.clear();
421 m_historyPosition = -1;
422 }
423
424 void wxWebViewIE::EnableHistory(bool enable)
425 {
426 m_historyEnabled = enable;
427 m_historyList.clear();
428 m_historyPosition = -1;
429 }
430
431 void wxWebViewIE::Reload(wxWebViewReloadFlags flags)
432 {
433 VARIANTARG level;
434 VariantInit(&level);
435 V_VT(&level) = VT_I2;
436
437 switch(flags)
438 {
439 case wxWEB_VIEW_RELOAD_DEFAULT:
440 V_I2(&level) = REFRESH_NORMAL;
441 break;
442 case wxWEB_VIEW_RELOAD_NO_CACHE:
443 V_I2(&level) = REFRESH_COMPLETELY;
444 break;
445 default:
446 wxFAIL_MSG("Unexpected reload type");
447 }
448
449 m_webBrowser->Refresh2(&level);
450 }
451
452 bool wxWebViewIE::IsOfflineMode()
453 {
454 wxVariant out = m_ie.GetProperty("Offline");
455
456 wxASSERT(out.GetType() == "bool");
457
458 return out.GetBool();
459 }
460
461 void wxWebViewIE::SetOfflineMode(bool offline)
462 {
463 // FIXME: the wxWidgets docs do not really document what the return
464 // parameter of PutProperty is
465 #if wxDEBUG_LEVEL
466 const bool success =
467 #endif
468 m_ie.PutProperty("Offline", (offline ?
469 VARIANT_TRUE :
470 VARIANT_FALSE));
471 wxASSERT(success);
472 }
473
474 bool wxWebViewIE::IsBusy() const
475 {
476 if (m_isBusy) return true;
477
478 wxVariant out = m_ie.GetProperty("Busy");
479
480 wxASSERT(out.GetType() == "bool");
481
482 return out.GetBool();
483 }
484
485 wxString wxWebViewIE::GetCurrentURL() const
486 {
487 wxVariant out = m_ie.GetProperty("LocationURL");
488
489 wxASSERT(out.GetType() == "string");
490 return out.GetString();
491 }
492
493 wxString wxWebViewIE::GetCurrentTitle() const
494 {
495 IHTMLDocument2* document = GetDocument();
496 BSTR title;
497
498 document->get_nameProp(&title);
499 document->Release();
500 return wxString(title);
501 }
502
503 bool wxWebViewIE::CanCut() const
504 {
505 return CanExecCommand("Cut");
506 }
507
508 bool wxWebViewIE::CanCopy() const
509 {
510 return CanExecCommand("Copy");
511 }
512 bool wxWebViewIE::CanPaste() const
513 {
514 return CanExecCommand("Paste");
515 }
516
517 void wxWebViewIE::Cut()
518 {
519 ExecCommand("Cut");
520 }
521
522 void wxWebViewIE::Copy()
523 {
524 ExecCommand("Copy");
525 }
526
527 void wxWebViewIE::Paste()
528 {
529 ExecCommand("Paste");
530 }
531
532 bool wxWebViewIE::CanUndo() const
533 {
534 return CanExecCommand("Undo");
535 }
536 bool wxWebViewIE::CanRedo() const
537 {
538 return CanExecCommand("Redo");
539 }
540
541 void wxWebViewIE::Undo()
542 {
543 ExecCommand("Undo");
544 }
545
546 void wxWebViewIE::Redo()
547 {
548 ExecCommand("Redo");
549 }
550
551 void wxWebViewIE::SetEditable(bool enable)
552 {
553 IHTMLDocument2* document = GetDocument();
554 if( enable )
555 document->put_designMode(SysAllocString(L"On"));
556 else
557 document->put_designMode(SysAllocString(L"Off"));
558
559 document->Release();
560 }
561
562 bool wxWebViewIE::IsEditable() const
563 {
564 IHTMLDocument2* document = GetDocument();
565 BSTR mode;
566 document->get_designMode(&mode);
567 document->Release();
568 if(wxString(mode) == "On")
569 return true;
570 else
571 return false;
572 }
573
574 void wxWebViewIE::SelectAll()
575 {
576 ExecCommand("SelectAll");
577 }
578
579 bool wxWebViewIE::HasSelection() const
580 {
581 IHTMLDocument2* document = GetDocument();
582 IHTMLSelectionObject* selection;
583 wxString sel;
584 HRESULT hr = document->get_selection(&selection);
585 if(SUCCEEDED(hr))
586 {
587 BSTR type;
588 selection->get_type(&type);
589 sel = wxString(type);
590 selection->Release();
591 }
592 document->Release();
593 return sel != "None";
594 }
595
596 void wxWebViewIE::DeleteSelection()
597 {
598 ExecCommand("Delete");
599 }
600
601 wxString wxWebViewIE::GetSelectedText() const
602 {
603 IHTMLDocument2* document = GetDocument();
604 IHTMLSelectionObject* selection;
605 wxString selected;
606 HRESULT hr = document->get_selection(&selection);
607 if(SUCCEEDED(hr))
608 {
609 IDispatch* disrange;
610 hr = selection->createRange(&disrange);
611 if(SUCCEEDED(hr))
612 {
613 IHTMLTxtRange* range;
614 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
615 if(SUCCEEDED(hr))
616 {
617 BSTR text;
618 range->get_text(&text);
619 selected = wxString(text);
620 range->Release();
621 }
622 disrange->Release();
623 }
624 selection->Release();
625 }
626 document->Release();
627 return selected;
628 }
629
630 wxString wxWebViewIE::GetSelectedSource() const
631 {
632 IHTMLDocument2* document = GetDocument();
633 IHTMLSelectionObject* selection;
634 wxString selected;
635 HRESULT hr = document->get_selection(&selection);
636 if(SUCCEEDED(hr))
637 {
638 IDispatch* disrange;
639 hr = selection->createRange(&disrange);
640 if(SUCCEEDED(hr))
641 {
642 IHTMLTxtRange* range;
643 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
644 if(SUCCEEDED(hr))
645 {
646 BSTR text;
647 range->get_htmlText(&text);
648 selected = wxString(text);
649 range->Release();
650 }
651 disrange->Release();
652 }
653 selection->Release();
654 }
655 document->Release();
656 return selected;
657 }
658
659 void wxWebViewIE::ClearSelection()
660 {
661 IHTMLDocument2* document = GetDocument();
662 IHTMLSelectionObject* selection;
663 wxString selected;
664 HRESULT hr = document->get_selection(&selection);
665 if(SUCCEEDED(hr))
666 {
667 selection->empty();
668 selection->Release();
669 }
670 document->Release();
671 }
672
673 wxString wxWebViewIE::GetPageText() const
674 {
675 IHTMLDocument2* document = GetDocument();
676 wxString text;
677 IHTMLElement* body;
678 HRESULT hr = document->get_body(&body);
679 if(SUCCEEDED(hr))
680 {
681 BSTR out;
682 body->get_innerText(&out);
683 text = wxString(out);
684 body->Release();
685 }
686 document->Release();
687 return text;
688 }
689
690 void wxWebViewIE::RunScript(const wxString& javascript)
691 {
692 IHTMLDocument2* document = GetDocument();
693 IHTMLWindow2* window;
694 wxString language = "javascript";
695 HRESULT hr = document->get_parentWindow(&window);
696 if(SUCCEEDED(hr))
697 {
698 VARIANT level;
699 VariantInit(&level);
700 V_VT(&level) = VT_EMPTY;
701 window->execScript(SysAllocString(javascript), SysAllocString(language), &level);
702 }
703 document->Release();
704 }
705
706 void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
707 {
708 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
709 if(urlMon.HasSymbol(wxT("CoInternetGetSession")))
710 {
711 typedef HRESULT (WINAPI *CoInternetGetSession_t)(DWORD, wxIInternetSession**, DWORD);
712 wxDYNLIB_FUNCTION(CoInternetGetSession_t, CoInternetGetSession, urlMon);
713
714 ClassFactory* cf = new ClassFactory(handler);
715 wxIInternetSession* session;
716 HRESULT res = (*pfnCoInternetGetSession)(0, &session, 0);
717 if(FAILED(res))
718 {
719 wxFAIL_MSG("Could not retrive internet session");
720 }
721
722 HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol, handler->GetName(), 0, NULL, 0);
723 if(FAILED(hr))
724 {
725 wxFAIL_MSG("Could not register protocol");
726 }
727 m_factories.push_back(cf);
728 }
729 else
730 {
731 wxFAIL_MSG("urlmon does not contain CoInternetGetSession");
732 }
733 }
734
735 bool wxWebViewIE::CanExecCommand(wxString command) const
736 {
737 IHTMLDocument2* document = GetDocument();
738 VARIANT_BOOL enabled;
739
740 document->queryCommandEnabled(SysAllocString(command.wc_str()), &enabled);
741 document->Release();
742
743 return (enabled == VARIANT_TRUE);
744 }
745
746 void wxWebViewIE::ExecCommand(wxString command)
747 {
748 IHTMLDocument2* document = GetDocument();
749 document->execCommand(SysAllocString(command.wc_str()), VARIANT_FALSE, VARIANT(), NULL);
750 document->Release();
751 }
752
753 IHTMLDocument2* wxWebViewIE::GetDocument() const
754 {
755 wxVariant variant = m_ie.GetProperty("Document");
756 IHTMLDocument2* document = (IHTMLDocument2*)variant.GetVoidPtr();
757
758 wxASSERT(document);
759
760 return document;
761 }
762
763 void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
764 {
765 if (m_webBrowser == NULL) return;
766
767 switch (evt.GetDispatchId())
768 {
769 case DISPID_BEFORENAVIGATE2:
770 {
771 m_isBusy = true;
772
773 wxString url = evt[1].GetString();
774 wxString target = evt[3].GetString();
775
776 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
777 GetId(), url, target);
778
779 //skip empty javascript events.
780 if(url == "javascript:\"\"" && target.IsEmpty())
781 {
782 event.Veto();
783 }
784 else
785 {
786 event.SetEventObject(this);
787 HandleWindowEvent(event);
788 }
789
790 if (!event.IsAllowed())
791 {
792 wxActiveXEventNativeMSW* nativeParams =
793 evt.GetNativeParameters();
794 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[0]) = VARIANT_TRUE;
795 }
796
797 // at this point, either the navigation event has been cancelled
798 // and we're not busy, either it was accepted and IWebBrowser2's
799 // Busy property will be true; so we don't need our override
800 // flag anymore.
801 m_isBusy = false;
802
803 break;
804 }
805
806 case DISPID_NAVIGATECOMPLETE2:
807 {
808 wxString url = evt[1].GetString();
809 // TODO: set target parameter if possible
810 wxString target = wxEmptyString;
811 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
812 GetId(), url, target);
813 event.SetEventObject(this);
814 HandleWindowEvent(event);
815 break;
816 }
817
818 case DISPID_PROGRESSCHANGE:
819 {
820 // download progress
821 break;
822 }
823
824 case DISPID_DOCUMENTCOMPLETE:
825 {
826 //Only send a complete even if we are actually finished, this brings
827 //the event in to line with webkit
828 READYSTATE rs;
829 m_webBrowser->get_ReadyState( &rs );
830 if(rs != READYSTATE_COMPLETE)
831 break;
832
833 wxString url = evt[1].GetString();
834
835 //As we are complete we also add to the history list, but not if the
836 //page is not the main page, ie it is a subframe
837 //We also have to check if we are loading a file:// url, if so we
838 //need to change the comparison as ie passes back a different style
839 //of url
840 if(m_historyEnabled && !m_historyLoadingFromList &&
841 (url == GetCurrentURL() ||
842 (GetCurrentURL().substr(0, 4) == "file" &&
843 wxFileSystem::URLToFileName(GetCurrentURL()).GetFullPath() == url)))
844 {
845 //If we are not at the end of the list, then erase everything
846 //between us and the end before adding the new page
847 if(m_historyPosition != static_cast<int>(m_historyList.size()) - 1)
848 {
849 m_historyList.erase(m_historyList.begin() + m_historyPosition + 1,
850 m_historyList.end());
851 }
852 wxSharedPtr<wxWebViewHistoryItem> item(new wxWebViewHistoryItem(url, GetCurrentTitle()));
853 m_historyList.push_back(item);
854 m_historyPosition++;
855 }
856 //Reset as we are done now
857 m_historyLoadingFromList = false;
858 // TODO: set target parameter if possible
859 wxString target = wxEmptyString;
860 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(),
861 url, target);
862 event.SetEventObject(this);
863 HandleWindowEvent(event);
864 break;
865 }
866
867 case DISPID_STATUSTEXTCHANGE:
868 {
869 break;
870 }
871
872 case DISPID_TITLECHANGE:
873 {
874 wxString title = evt[0].GetString();
875
876 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED,
877 GetId(), GetCurrentURL(), "");
878 event.SetString(title);
879 event.SetEventObject(this);
880 HandleWindowEvent(event);
881 break;
882 }
883
884 case DISPID_NAVIGATEERROR:
885 {
886 wxWebViewNavigationError errorType = wxWEB_NAV_ERR_OTHER;
887 wxString errorCode = "?";
888 switch (evt[3].GetLong())
889 {
890 case INET_E_INVALID_URL: // (0x800C0002L or -2146697214)
891 errorCode = "INET_E_INVALID_URL";
892 errorType = wxWEB_NAV_ERR_REQUEST;
893 break;
894 case INET_E_NO_SESSION: // (0x800C0003L or -2146697213)
895 errorCode = "INET_E_NO_SESSION";
896 errorType = wxWEB_NAV_ERR_CONNECTION;
897 break;
898 case INET_E_CANNOT_CONNECT: // (0x800C0004L or -2146697212)
899 errorCode = "INET_E_CANNOT_CONNECT";
900 errorType = wxWEB_NAV_ERR_CONNECTION;
901 break;
902 case INET_E_RESOURCE_NOT_FOUND: // (0x800C0005L or -2146697211)
903 errorCode = "INET_E_RESOURCE_NOT_FOUND";
904 errorType = wxWEB_NAV_ERR_NOT_FOUND;
905 break;
906 case INET_E_OBJECT_NOT_FOUND: // (0x800C0006L or -2146697210)
907 errorCode = "INET_E_OBJECT_NOT_FOUND";
908 errorType = wxWEB_NAV_ERR_NOT_FOUND;
909 break;
910 case INET_E_DATA_NOT_AVAILABLE: // (0x800C0007L or -2146697209)
911 errorCode = "INET_E_DATA_NOT_AVAILABLE";
912 errorType = wxWEB_NAV_ERR_NOT_FOUND;
913 break;
914 case INET_E_DOWNLOAD_FAILURE: // (0x800C0008L or -2146697208)
915 errorCode = "INET_E_DOWNLOAD_FAILURE";
916 errorType = wxWEB_NAV_ERR_CONNECTION;
917 break;
918 case INET_E_AUTHENTICATION_REQUIRED: // (0x800C0009L or -2146697207)
919 errorCode = "INET_E_AUTHENTICATION_REQUIRED";
920 errorType = wxWEB_NAV_ERR_AUTH;
921 break;
922 case INET_E_NO_VALID_MEDIA: // (0x800C000AL or -2146697206)
923 errorCode = "INET_E_NO_VALID_MEDIA";
924 errorType = wxWEB_NAV_ERR_REQUEST;
925 break;
926 case INET_E_CONNECTION_TIMEOUT: // (0x800C000BL or -2146697205)
927 errorCode = "INET_E_CONNECTION_TIMEOUT";
928 errorType = wxWEB_NAV_ERR_CONNECTION;
929 break;
930 case INET_E_INVALID_REQUEST: // (0x800C000CL or -2146697204)
931 errorCode = "INET_E_INVALID_REQUEST";
932 errorType = wxWEB_NAV_ERR_REQUEST;
933 break;
934 case INET_E_UNKNOWN_PROTOCOL: // (0x800C000DL or -2146697203)
935 errorCode = "INET_E_UNKNOWN_PROTOCOL";
936 errorType = wxWEB_NAV_ERR_REQUEST;
937 break;
938 case INET_E_SECURITY_PROBLEM: // (0x800C000EL or -2146697202)
939 errorCode = "INET_E_SECURITY_PROBLEM";
940 errorType = wxWEB_NAV_ERR_SECURITY;
941 break;
942 case INET_E_CANNOT_LOAD_DATA: // (0x800C000FL or -2146697201)
943 errorCode = "INET_E_CANNOT_LOAD_DATA";
944 errorType = wxWEB_NAV_ERR_OTHER;
945 break;
946 case INET_E_CANNOT_INSTANTIATE_OBJECT:
947 // CoCreateInstance will return an error code if this happens,
948 // we'll handle this above.
949 return;
950 break;
951 case INET_E_REDIRECT_FAILED: // (0x800C0014L or -2146697196)
952 errorCode = "INET_E_REDIRECT_FAILED";
953 errorType = wxWEB_NAV_ERR_OTHER;
954 break;
955 case INET_E_REDIRECT_TO_DIR: // (0x800C0015L or -2146697195)
956 errorCode = "INET_E_REDIRECT_TO_DIR";
957 errorType = wxWEB_NAV_ERR_REQUEST;
958 break;
959 case INET_E_CANNOT_LOCK_REQUEST: // (0x800C0016L or -2146697194)
960 errorCode = "INET_E_CANNOT_LOCK_REQUEST";
961 errorType = wxWEB_NAV_ERR_OTHER;
962 break;
963 case INET_E_USE_EXTEND_BINDING: // (0x800C0017L or -2146697193)
964 errorCode = "INET_E_USE_EXTEND_BINDING";
965 errorType = wxWEB_NAV_ERR_OTHER;
966 break;
967 case INET_E_TERMINATED_BIND: // (0x800C0018L or -2146697192)
968 errorCode = "INET_E_TERMINATED_BIND";
969 errorType = wxWEB_NAV_ERR_OTHER;
970 break;
971 case INET_E_INVALID_CERTIFICATE: // (0x800C0019L or -2146697191)
972 errorCode = "INET_E_INVALID_CERTIFICATE";
973 errorType = wxWEB_NAV_ERR_CERTIFICATE;
974 break;
975 case INET_E_CODE_DOWNLOAD_DECLINED: // (0x800C0100L or -2146696960)
976 errorCode = "INET_E_CODE_DOWNLOAD_DECLINED";
977 errorType = wxWEB_NAV_ERR_USER_CANCELLED;
978 break;
979 case INET_E_RESULT_DISPATCHED: // (0x800C0200L or -2146696704)
980 // cancel request cancelled...
981 errorCode = "INET_E_RESULT_DISPATCHED";
982 errorType = wxWEB_NAV_ERR_OTHER;
983 break;
984 case INET_E_CANNOT_REPLACE_SFP_FILE: // (0x800C0300L or -2146696448)
985 errorCode = "INET_E_CANNOT_REPLACE_SFP_FILE";
986 errorType = wxWEB_NAV_ERR_SECURITY;
987 break;
988 case INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY:
989 errorCode = "INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY";
990 errorType = wxWEB_NAV_ERR_SECURITY;
991 break;
992 case INET_E_CODE_INSTALL_SUPPRESSED:
993 errorCode = "INET_E_CODE_INSTALL_SUPPRESSED";
994 errorType = wxWEB_NAV_ERR_SECURITY;
995 break;
996 }
997
998 wxString url = evt[1].GetString();
999 wxString target = evt[2].GetString();
1000 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(),
1001 url, target);
1002 event.SetEventObject(this);
1003 event.SetInt(errorType);
1004 event.SetString(errorCode);
1005 HandleWindowEvent(event);
1006 break;
1007 }
1008 case DISPID_NEWWINDOW3:
1009 {
1010 wxString url = evt[4].GetString();
1011
1012 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
1013 GetId(), url, wxEmptyString);
1014 event.SetEventObject(this);
1015 HandleWindowEvent(event);
1016
1017 //We always cancel this event otherwise an Internet Exporer window
1018 //is opened for the url
1019 wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters();
1020 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE;
1021 break;
1022 }
1023 }
1024
1025 evt.Skip();
1026 }
1027
1028 VirtualProtocol::VirtualProtocol(wxSharedPtr<wxWebViewHandler> handler)
1029 {
1030 m_refCount = 0;
1031 m_file = NULL;
1032 m_handler = handler;
1033 }
1034
1035 VirtualProtocol::~VirtualProtocol()
1036 {
1037 }
1038
1039 ULONG VirtualProtocol::AddRef()
1040 {
1041 m_refCount++;
1042 return m_refCount;
1043 }
1044
1045 HRESULT VirtualProtocol::QueryInterface(REFIID riid, void **ppvObject)
1046 {
1047 if(riid == IID_IUnknown || riid == wxIID_IInternetProtocolRoot ||
1048 riid == wxIID_IInternetProtocol)
1049 {
1050 *ppvObject = (wxIInternetProtocol*)this;
1051 AddRef();
1052 return S_OK;
1053 }
1054 else
1055 {
1056 *ppvObject = NULL;
1057 return E_POINTER;
1058 }
1059 }
1060
1061 ULONG VirtualProtocol::Release()
1062 {
1063 m_refCount--;
1064 if (m_refCount > 0)
1065 {
1066 return m_refCount;
1067 }
1068 else
1069 {
1070 delete this;
1071 return 0;
1072 }
1073 }
1074
1075 HRESULT VirtualProtocol::Start(LPCWSTR szUrl, wxIInternetProtocolSink *pOIProtSink,
1076 wxIInternetBindInfo *pOIBindInfo, DWORD grfPI,
1077 HANDLE_PTR dwReserved)
1078 {
1079 wxUnusedVar(szUrl);
1080 wxUnusedVar(pOIBindInfo);
1081 wxUnusedVar(grfPI);
1082 wxUnusedVar(dwReserved);
1083 m_protocolSink = pOIProtSink;
1084
1085 //We get the file itself from the protocol handler
1086 m_file = m_handler->GetFile(szUrl);
1087
1088
1089 if(!m_file)
1090 return INET_E_RESOURCE_NOT_FOUND;
1091
1092 //We return the stream length for current and total size as we can always
1093 //read the whole file from the stream
1094 wxFileOffset length = m_file->GetStream()->GetLength();
1095 m_protocolSink->ReportData(wxBSCF_FIRSTDATANOTIFICATION |
1096 wxBSCF_DATAFULLYAVAILABLE |
1097 wxBSCF_LASTDATANOTIFICATION,
1098 length, length);
1099 return S_OK;
1100 }
1101
1102 HRESULT VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
1103 {
1104 //If the file is null we return false to indicte it is finished
1105 if(!m_file)
1106 return S_FALSE;
1107
1108 wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
1109 *pcbRead = m_file->GetStream()->LastRead();
1110
1111 if(err == wxSTREAM_NO_ERROR)
1112 {
1113 if(*pcbRead < cb)
1114 {
1115 wxDELETE(m_file);
1116 m_protocolSink->ReportResult(S_OK, 0, NULL);
1117 }
1118 //As we are not eof there is more data
1119 return S_OK;
1120 }
1121 else if(err == wxSTREAM_EOF)
1122 {
1123 wxDELETE(m_file);
1124 m_protocolSink->ReportResult(S_OK, 0, NULL);
1125 //We are eof and so finished
1126 return S_OK;
1127 }
1128 else if(err == wxSTREAM_READ_ERROR)
1129 {
1130 wxDELETE(m_file);
1131 return INET_E_DOWNLOAD_FAILURE;
1132 }
1133 else
1134 {
1135 //Dummy return to surpress a compiler warning
1136 wxFAIL;
1137 return INET_E_DOWNLOAD_FAILURE;
1138 }
1139 }
1140
1141 HRESULT ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
1142 void ** ppvObject)
1143 {
1144 if (pUnkOuter)
1145 return CLASS_E_NOAGGREGATION;
1146 VirtualProtocol* vp = new VirtualProtocol(m_handler);
1147 vp->AddRef();
1148 HRESULT hr = vp->QueryInterface(riid, ppvObject);
1149 vp->Release();
1150 return hr;
1151
1152 }
1153
1154 STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
1155 {
1156 wxUnusedVar(fLock);
1157 return S_OK;
1158 }
1159
1160 ULONG ClassFactory::AddRef(void)
1161 {
1162 m_refCount++;
1163 return m_refCount;
1164 }
1165
1166 HRESULT ClassFactory::QueryInterface(REFIID riid, void **ppvObject)
1167 {
1168 if ((riid == IID_IUnknown) || (riid == IID_IClassFactory))
1169 {
1170 *ppvObject = this;
1171 AddRef();
1172 return S_OK;
1173 }
1174 else
1175 {
1176 *ppvObject = NULL;
1177 return E_POINTER;
1178 }
1179
1180 }
1181
1182 ULONG ClassFactory::Release(void)
1183 {
1184 m_refCount--;
1185 if (m_refCount > 0)
1186 {
1187 return m_refCount;
1188 }
1189 else
1190 {
1191 delete this;
1192 return 0;
1193 }
1194
1195 }
1196
1197 #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE