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