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