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