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