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