Add support for searching and highlighting a wxWebView.
[wxWidgets.git] / src / msw / webview_ie.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/webview_ie.cpp
3 // Purpose: wxMSW wxWebViewIE class implementation for web view component
4 // Author: Marianne Gagnon
5 // Id: $Id$
6 // Copyright: (c) 2010 Marianne Gagnon, 2011 Steven Lamerton
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
12
13 #if defined(__BORLANDC__)
14 #pragma hdrstop
15 #endif
16
17 #include "wx/msw/webview_ie.h"
18
19 #if wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE
20
21 #include <olectl.h>
22 #include <oleidl.h>
23 #include <exdispid.h>
24 #include <exdisp.h>
25 #include <mshtml.h>
26 #include "wx/msw/registry.h"
27 #include "wx/msw/missing.h"
28 #include "wx/filesys.h"
29 #include "wx/dynlib.h"
30 #include <initguid.h>
31
32 /* These GUID definitions are our own implementation to support interfaces
33 * normally in urlmon.h. See include/wx/msw/webview_ie.h
34 */
35
36 namespace {
37
38 DEFINE_GUID(wxIID_IInternetProtocolRoot,0x79eac9e3,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
39 DEFINE_GUID(wxIID_IInternetProtocol,0x79eac9e4,0xbaf9,0x11ce,0x8c,0x82,0,0xaa,0,0x4b,0xa9,0xb);
40 DEFINE_GUID(wxIID_IDocHostUIHandler, 0xbd3f23c0, 0xd43e, 0x11cf, 0x89, 0x3b, 0x00, 0xaa, 0x00, 0xbd, 0xce, 0x1a);
41
42 enum //Internal find flags
43 {
44 wxWEB_VIEW_FIND_ADD_POINTERS = 0x0001,
45 wxWEB_VIEW_FIND_REMOVE_HIGHLIGHT = 0x0002
46 };
47
48 }
49
50 wxIMPLEMENT_DYNAMIC_CLASS(wxWebViewIE, wxWebView);
51
52 BEGIN_EVENT_TABLE(wxWebViewIE, wxControl)
53 EVT_ACTIVEX(wxID_ANY, wxWebViewIE::onActiveXEvent)
54 EVT_ERASE_BACKGROUND(wxWebViewIE::onEraseBg)
55 END_EVENT_TABLE()
56
57 bool wxWebViewIE::Create(wxWindow* parent,
58 wxWindowID id,
59 const wxString& url,
60 const wxPoint& pos,
61 const wxSize& size,
62 long style,
63 const wxString& name)
64 {
65 if (!wxControl::Create(parent, id, pos, size, style,
66 wxDefaultValidator, name))
67 {
68 return false;
69 }
70
71 m_webBrowser = NULL;
72 m_isBusy = false;
73 m_historyLoadingFromList = false;
74 m_historyEnabled = true;
75 m_historyPosition = -1;
76 m_zoomType = wxWEB_VIEW_ZOOM_TYPE_TEXT;
77 FindClear();
78
79 if (::CoCreateInstance(CLSID_WebBrowser, NULL,
80 CLSCTX_INPROC_SERVER, // CLSCTX_INPROC,
81 IID_IWebBrowser2 , (void**)&m_webBrowser) != 0)
82 {
83 wxLogError("Failed to initialize IE, CoCreateInstance returned an error");
84 return false;
85 }
86
87 m_ie.SetDispatchPtr(m_webBrowser); // wxAutomationObject will release itself
88
89 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
90 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
91
92 m_uiHandler = new DocHostUIHandler;
93
94 m_container = new wxIEContainer(this, IID_IWebBrowser2, m_webBrowser, m_uiHandler);
95
96 EnableControlFeature(21 /* FEATURE_DISABLE_NAVIGATION_SOUNDS */);
97
98 LoadURL(url);
99 return true;
100 }
101
102 wxWebViewIE::~wxWebViewIE()
103 {
104 for(unsigned int i = 0; i < m_factories.size(); i++)
105 {
106 m_factories[i]->Release();
107 }
108 FindClear();
109 }
110
111 void wxWebViewIE::LoadURL(const wxString& url)
112 {
113 m_ie.CallMethod("Navigate", wxConvertStringToOle(url));
114 }
115
116 void wxWebViewIE::DoSetPage(const wxString& html, const wxString& baseUrl)
117 {
118 BSTR bstr = SysAllocString(OLESTR(""));
119 SAFEARRAY *psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
120 if (psaStrings != NULL)
121 {
122 VARIANT *param;
123 HRESULT hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
124 param->vt = VT_BSTR;
125 param->bstrVal = bstr;
126
127 hr = SafeArrayUnaccessData(psaStrings);
128
129 wxCOMPtr<IHTMLDocument2> document(GetDocument());
130
131 if(!document)
132 return;
133
134 document->write(psaStrings);
135 document->close();
136
137 SafeArrayDestroy(psaStrings);
138
139 bstr = SysAllocString(html.wc_str());
140
141 // Creates a new one-dimensional array
142 psaStrings = SafeArrayCreateVector(VT_VARIANT, 0, 1);
143 if (psaStrings != NULL)
144 {
145 hr = SafeArrayAccessData(psaStrings, (LPVOID*)&param);
146 param->vt = VT_BSTR;
147 param->bstrVal = bstr;
148 hr = SafeArrayUnaccessData(psaStrings);
149
150 document = GetDocument();
151
152 if(!document)
153 return;
154
155 document->write(psaStrings);
156
157 // SafeArrayDestroy calls SysFreeString for each BSTR
158 SafeArrayDestroy(psaStrings);
159
160 //We send the events when we are done to mimic webkit
161 //Navigated event
162 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
163 GetId(), baseUrl, "");
164 event.SetEventObject(this);
165 HandleWindowEvent(event);
166
167 //Document complete event
168 event.SetEventType(wxEVT_COMMAND_WEB_VIEW_LOADED);
169 event.SetEventObject(this);
170 HandleWindowEvent(event);
171 }
172 else
173 {
174 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL");
175 }
176 }
177 else
178 {
179 wxLogError("wxWebViewIE::SetPage() : psaStrings is NULL during clear");
180 }
181 }
182
183 wxString wxWebViewIE::GetPageSource() const
184 {
185 wxCOMPtr<IHTMLDocument2> document(GetDocument());
186
187 if(document)
188 {
189 wxCOMPtr<IHTMLElement> bodyTag;
190 wxCOMPtr<IHTMLElement> htmlTag;
191 wxString source;
192 HRESULT hr = document->get_body(&bodyTag);
193 if(SUCCEEDED(hr))
194 {
195 hr = bodyTag->get_parentElement(&htmlTag);
196 if(SUCCEEDED(hr))
197 {
198 BSTR bstr;
199 htmlTag->get_outerHTML(&bstr);
200 source = wxString(bstr);
201 }
202 }
203 return source;
204 }
205 else
206 {
207 return "";
208 }
209 }
210
211 wxWebViewZoom wxWebViewIE::GetZoom() const
212 {
213 switch( m_zoomType )
214 {
215 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
216 return GetIEOpticalZoom();
217 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
218 return GetIETextZoom();
219 default:
220 wxFAIL;
221 }
222
223 //Dummy return to stop compiler warnings
224 return wxWEB_VIEW_ZOOM_MEDIUM;
225
226 }
227
228 void wxWebViewIE::SetZoom(wxWebViewZoom zoom)
229 {
230 switch( m_zoomType )
231 {
232 case wxWEB_VIEW_ZOOM_TYPE_LAYOUT:
233 SetIEOpticalZoom(zoom);
234 break;
235 case wxWEB_VIEW_ZOOM_TYPE_TEXT:
236 SetIETextZoom(zoom);
237 break;
238 default:
239 wxFAIL;
240 }
241 }
242
243 void wxWebViewIE::SetIETextZoom(wxWebViewZoom level)
244 {
245 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
246 //is 0 to 4 so the check is unnecessary, these match exactly with the
247 //enum values
248 VARIANT zoomVariant;
249 VariantInit (&zoomVariant);
250 V_VT(&zoomVariant) = VT_I4;
251 V_I4(&zoomVariant) = level;
252
253 #if wxDEBUG_LEVEL
254 HRESULT result =
255 #endif
256 m_webBrowser->ExecWB(OLECMDID_ZOOM,
257 OLECMDEXECOPT_DONTPROMPTUSER,
258 &zoomVariant, NULL);
259 wxASSERT(result == S_OK);
260 }
261
262 wxWebViewZoom wxWebViewIE::GetIETextZoom() const
263 {
264 VARIANT zoomVariant;
265 VariantInit (&zoomVariant);
266 V_VT(&zoomVariant) = VT_I4;
267
268 #if wxDEBUG_LEVEL
269 HRESULT result =
270 #endif
271 m_webBrowser->ExecWB(OLECMDID_ZOOM,
272 OLECMDEXECOPT_DONTPROMPTUSER,
273 NULL, &zoomVariant);
274 wxASSERT(result == S_OK);
275
276 //We can safely cast here as we know that the range matches our enum
277 return static_cast<wxWebViewZoom>(V_I4(&zoomVariant));
278 }
279
280 void wxWebViewIE::SetIEOpticalZoom(wxWebViewZoom level)
281 {
282 //We do not use OLECMDID_OPTICAL_GETZOOMRANGE as the docs say the range
283 //is 10 to 1000 so the check is unnecessary
284 VARIANT zoomVariant;
285 VariantInit (&zoomVariant);
286 V_VT(&zoomVariant) = VT_I4;
287
288 //We make a somewhat arbitray map here, taken from values used by webkit
289 switch(level)
290 {
291 case wxWEB_VIEW_ZOOM_TINY:
292 V_I4(&zoomVariant) = 60;
293 break;
294 case wxWEB_VIEW_ZOOM_SMALL:
295 V_I4(&zoomVariant) = 80;
296 break;
297 case wxWEB_VIEW_ZOOM_MEDIUM:
298 V_I4(&zoomVariant) = 100;
299 break;
300 case wxWEB_VIEW_ZOOM_LARGE:
301 V_I4(&zoomVariant) = 130;
302 break;
303 case wxWEB_VIEW_ZOOM_LARGEST:
304 V_I4(&zoomVariant) = 160;
305 break;
306 default:
307 wxFAIL;
308 }
309
310 #if wxDEBUG_LEVEL
311 HRESULT result =
312 #endif
313 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
314 OLECMDEXECOPT_DODEFAULT,
315 &zoomVariant,
316 NULL);
317 wxASSERT(result == S_OK);
318 }
319
320 wxWebViewZoom wxWebViewIE::GetIEOpticalZoom() const
321 {
322 VARIANT zoomVariant;
323 VariantInit (&zoomVariant);
324 V_VT(&zoomVariant) = VT_I4;
325
326 #if wxDEBUG_LEVEL
327 HRESULT result =
328 #endif
329 m_webBrowser->ExecWB((OLECMDID)63 /*OLECMDID_OPTICAL_ZOOM*/,
330 OLECMDEXECOPT_DODEFAULT, NULL,
331 &zoomVariant);
332 wxASSERT(result == S_OK);
333
334 const int zoom = V_I4(&zoomVariant);
335
336 //We make a somewhat arbitray map here, taken from values used by webkit
337 if (zoom <= 65)
338 {
339 return wxWEB_VIEW_ZOOM_TINY;
340 }
341 else if (zoom > 65 && zoom <= 90)
342 {
343 return wxWEB_VIEW_ZOOM_SMALL;
344 }
345 else if (zoom > 90 && zoom <= 115)
346 {
347 return wxWEB_VIEW_ZOOM_MEDIUM;
348 }
349 else if (zoom > 115 && zoom <= 145)
350 {
351 return wxWEB_VIEW_ZOOM_LARGE;
352 }
353 else /*if (zoom > 145) */ //Using else removes a compiler warning
354 {
355 return wxWEB_VIEW_ZOOM_LARGEST;
356 }
357 }
358
359 void wxWebViewIE::SetZoomType(wxWebViewZoomType type)
360 {
361 m_zoomType = type;
362 }
363
364 wxWebViewZoomType wxWebViewIE::GetZoomType() const
365 {
366 return m_zoomType;
367 }
368
369 bool wxWebViewIE::CanSetZoomType(wxWebViewZoomType type) const
370 {
371 //IE 6 and below only support text zoom, so check the registry to see what
372 //version we actually have
373 wxRegKey key(wxRegKey::HKLM, "Software\\Microsoft\\Internet Explorer");
374 wxString value;
375 key.QueryValue("Version", value);
376
377 long version = wxAtoi(value.Left(1));
378 if(version <= 6 && type == wxWEB_VIEW_ZOOM_TYPE_LAYOUT)
379 return false;
380 else
381 return true;
382 }
383
384 void wxWebViewIE::Print()
385 {
386 m_webBrowser->ExecWB(OLECMDID_PRINTPREVIEW,
387 OLECMDEXECOPT_DODEFAULT, NULL, NULL);
388 }
389
390 bool wxWebViewIE::CanGoBack() const
391 {
392 if(m_historyEnabled)
393 return m_historyPosition > 0;
394 else
395 return false;
396 }
397
398 bool wxWebViewIE::CanGoForward() const
399 {
400 if(m_historyEnabled)
401 return m_historyPosition != static_cast<int>(m_historyList.size()) - 1;
402 else
403 return false;
404 }
405
406 void wxWebViewIE::LoadHistoryItem(wxSharedPtr<wxWebViewHistoryItem> item)
407 {
408 int pos = -1;
409 for(unsigned int i = 0; i < m_historyList.size(); i++)
410 {
411 //We compare the actual pointers to find the correct item
412 if(m_historyList[i].get() == item.get())
413 pos = i;
414 }
415 wxASSERT_MSG(pos != static_cast<int>(m_historyList.size()),
416 "invalid history item");
417 m_historyLoadingFromList = true;
418 LoadURL(item->GetUrl());
419 m_historyPosition = pos;
420 }
421
422 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetBackwardHistory()
423 {
424 wxVector<wxSharedPtr<wxWebViewHistoryItem> > backhist;
425 //As we don't have std::copy or an iterator constructor in the wxwidgets
426 //native vector we construct it by hand
427 for(int i = 0; i < m_historyPosition; i++)
428 {
429 backhist.push_back(m_historyList[i]);
430 }
431 return backhist;
432 }
433
434 wxVector<wxSharedPtr<wxWebViewHistoryItem> > wxWebViewIE::GetForwardHistory()
435 {
436 wxVector<wxSharedPtr<wxWebViewHistoryItem> > forwardhist;
437 //As we don't have std::copy or an iterator constructor in the wxwidgets
438 //native vector we construct it by hand
439 for(int i = m_historyPosition + 1; i < static_cast<int>(m_historyList.size()); i++)
440 {
441 forwardhist.push_back(m_historyList[i]);
442 }
443 return forwardhist;
444 }
445
446 void wxWebViewIE::GoBack()
447 {
448 LoadHistoryItem(m_historyList[m_historyPosition - 1]);
449 }
450
451 void wxWebViewIE::GoForward()
452 {
453 LoadHistoryItem(m_historyList[m_historyPosition + 1]);
454 }
455
456 void wxWebViewIE::Stop()
457 {
458 m_ie.CallMethod("Stop");
459 }
460
461 void wxWebViewIE::ClearHistory()
462 {
463 m_historyList.clear();
464 m_historyPosition = -1;
465 }
466
467 void wxWebViewIE::EnableHistory(bool enable)
468 {
469 m_historyEnabled = enable;
470 m_historyList.clear();
471 m_historyPosition = -1;
472 }
473
474 void wxWebViewIE::Reload(wxWebViewReloadFlags flags)
475 {
476 VARIANTARG level;
477 VariantInit(&level);
478 V_VT(&level) = VT_I2;
479
480 switch(flags)
481 {
482 case wxWEB_VIEW_RELOAD_DEFAULT:
483 V_I2(&level) = REFRESH_NORMAL;
484 break;
485 case wxWEB_VIEW_RELOAD_NO_CACHE:
486 V_I2(&level) = REFRESH_COMPLETELY;
487 break;
488 default:
489 wxFAIL_MSG("Unexpected reload type");
490 }
491
492 m_webBrowser->Refresh2(&level);
493 }
494
495 bool wxWebViewIE::IsOfflineMode()
496 {
497 wxVariant out = m_ie.GetProperty("Offline");
498
499 wxASSERT(out.GetType() == "bool");
500
501 return out.GetBool();
502 }
503
504 void wxWebViewIE::SetOfflineMode(bool offline)
505 {
506 // FIXME: the wxWidgets docs do not really document what the return
507 // parameter of PutProperty is
508 #if wxDEBUG_LEVEL
509 const bool success =
510 #endif
511 m_ie.PutProperty("Offline", (offline ?
512 VARIANT_TRUE :
513 VARIANT_FALSE));
514 wxASSERT(success);
515 }
516
517 bool wxWebViewIE::IsBusy() const
518 {
519 if (m_isBusy) return true;
520
521 wxVariant out = m_ie.GetProperty("Busy");
522
523 wxASSERT(out.GetType() == "bool");
524
525 return out.GetBool();
526 }
527
528 wxString wxWebViewIE::GetCurrentURL() const
529 {
530 wxVariant out = m_ie.GetProperty("LocationURL");
531
532 wxASSERT(out.GetType() == "string");
533 return out.GetString();
534 }
535
536 wxString wxWebViewIE::GetCurrentTitle() const
537 {
538 wxCOMPtr<IHTMLDocument2> document(GetDocument());
539
540 if(document)
541 {
542 BSTR title;
543 document->get_nameProp(&title);
544 return wxString(title);
545 }
546 else
547 {
548 return "";
549 }
550 }
551
552 bool wxWebViewIE::CanCut() const
553 {
554 return CanExecCommand("Cut");
555 }
556
557 bool wxWebViewIE::CanCopy() const
558 {
559 return CanExecCommand("Copy");
560 }
561
562 bool wxWebViewIE::CanPaste() const
563 {
564 return CanExecCommand("Paste");
565 }
566
567 void wxWebViewIE::Cut()
568 {
569 ExecCommand("Cut");
570 }
571
572 void wxWebViewIE::Copy()
573 {
574 ExecCommand("Copy");
575 }
576
577 void wxWebViewIE::Paste()
578 {
579 ExecCommand("Paste");
580 }
581
582 bool wxWebViewIE::CanUndo() const
583 {
584 return CanExecCommand("Undo");
585 }
586
587 bool wxWebViewIE::CanRedo() const
588 {
589 return CanExecCommand("Redo");
590 }
591
592 void wxWebViewIE::Undo()
593 {
594 ExecCommand("Undo");
595 }
596
597 void wxWebViewIE::Redo()
598 {
599 ExecCommand("Redo");
600 }
601
602 long wxWebViewIE::Find(const wxString& text, int flags)
603 {
604 //If the text is empty then we clear.
605 if(text.IsEmpty())
606 {
607 ClearSelection();
608 if(m_findFlags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT)
609 {
610 FindInternal(m_findText, (m_findFlags &~ wxWEB_VIEW_FIND_HIGHLIGHT_RESULT), wxWEB_VIEW_FIND_REMOVE_HIGHLIGHT);
611 }
612 FindClear();
613 return wxNOT_FOUND;
614 }
615 //Have we done this search before?
616 if(m_findText == text)
617 {
618 //Just do a highlight?
619 if((flags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT) != (m_findFlags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT))
620 {
621 m_findFlags = flags;
622 if(!m_findPointers.empty())
623 {
624 FindInternal(m_findText, m_findFlags, ((flags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT) == 0 ? wxWEB_VIEW_FIND_REMOVE_HIGHLIGHT : 0));
625 }
626 return m_findPosition;
627 }
628 else if(((m_findFlags & wxWEB_VIEW_FIND_ENTIRE_WORD) == (flags & wxWEB_VIEW_FIND_ENTIRE_WORD)) && ((m_findFlags & wxWEB_VIEW_FIND_MATCH_CASE) == (flags&wxWEB_VIEW_FIND_MATCH_CASE)))
629 {
630 m_findFlags = flags;
631 return FindNext(((flags & wxWEB_VIEW_FIND_BACKWARDS) ? -1 : 1));
632 }
633 }
634 //Remove old highlight if any.
635 if(m_findFlags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT)
636 {
637 FindInternal(m_findText, (m_findFlags &~ wxWEB_VIEW_FIND_HIGHLIGHT_RESULT), wxWEB_VIEW_FIND_REMOVE_HIGHLIGHT);
638 }
639 //Reset find variables.
640 FindClear();
641 ClearSelection();
642 m_findText = text;
643 m_findFlags = flags;
644 //find the text and return count.
645 FindInternal(text, flags, wxWEB_VIEW_FIND_ADD_POINTERS);
646 return m_findPointers.empty() ? wxNOT_FOUND : m_findPointers.size();
647 }
648
649 void wxWebViewIE::SetEditable(bool enable)
650 {
651 wxCOMPtr<IHTMLDocument2> document(GetDocument());
652
653 if(document)
654 {
655 if( enable )
656 document->put_designMode(SysAllocString(L"On"));
657 else
658 document->put_designMode(SysAllocString(L"Off"));
659
660 }
661 }
662
663 bool wxWebViewIE::IsEditable() const
664 {
665 wxCOMPtr<IHTMLDocument2> document(GetDocument());
666
667 if(document)
668 {
669 BSTR mode;
670 document->get_designMode(&mode);
671 if(wxString(mode) == "On")
672 return true;
673 else
674 return false;
675 }
676 else
677 {
678 return false;
679 }
680 }
681
682 void wxWebViewIE::SelectAll()
683 {
684 ExecCommand("SelectAll");
685 }
686
687 bool wxWebViewIE::HasSelection() const
688 {
689 wxCOMPtr<IHTMLDocument2> document(GetDocument());
690
691 if(document)
692 {
693 wxCOMPtr<IHTMLSelectionObject> selection;
694 wxString sel;
695 HRESULT hr = document->get_selection(&selection);
696 if(SUCCEEDED(hr))
697 {
698 BSTR type;
699 selection->get_type(&type);
700 sel = wxString(type);
701 }
702 return sel != "None";
703 }
704 else
705 {
706 return false;
707 }
708 }
709
710 void wxWebViewIE::DeleteSelection()
711 {
712 ExecCommand("Delete");
713 }
714
715 wxString wxWebViewIE::GetSelectedText() const
716 {
717 wxCOMPtr<IHTMLDocument2> document(GetDocument());
718
719 if(document)
720 {
721 wxCOMPtr<IHTMLSelectionObject> selection;
722 wxString selected;
723 HRESULT hr = document->get_selection(&selection);
724 if(SUCCEEDED(hr))
725 {
726 wxCOMPtr<IDispatch> disrange;
727 hr = selection->createRange(&disrange);
728 if(SUCCEEDED(hr))
729 {
730 wxCOMPtr<IHTMLTxtRange> range;
731 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
732 if(SUCCEEDED(hr))
733 {
734 BSTR text;
735 range->get_text(&text);
736 selected = wxString(text);
737 }
738 }
739 }
740 return selected;
741 }
742 else
743 {
744 return "";
745 }
746 }
747
748 wxString wxWebViewIE::GetSelectedSource() const
749 {
750 wxCOMPtr<IHTMLDocument2> document(GetDocument());
751
752 if(document)
753 {
754 wxCOMPtr<IHTMLSelectionObject> selection;
755 wxString selected;
756 HRESULT hr = document->get_selection(&selection);
757 if(SUCCEEDED(hr))
758 {
759 wxCOMPtr<IDispatch> disrange;
760 hr = selection->createRange(&disrange);
761 if(SUCCEEDED(hr))
762 {
763 wxCOMPtr<IHTMLTxtRange> range;
764 hr = disrange->QueryInterface(IID_IHTMLTxtRange, (void**)&range);
765 if(SUCCEEDED(hr))
766 {
767 BSTR text;
768 range->get_htmlText(&text);
769 selected = wxString(text);
770 }
771 }
772 }
773 return selected;
774 }
775 else
776 {
777 return "";
778 }
779 }
780
781 void wxWebViewIE::ClearSelection()
782 {
783 wxCOMPtr<IHTMLDocument2> document(GetDocument());
784
785 if(document)
786 {
787 wxCOMPtr<IHTMLSelectionObject> selection;
788 wxString selected;
789 HRESULT hr = document->get_selection(&selection);
790 if(SUCCEEDED(hr))
791 {
792 selection->empty();
793 }
794 }
795 }
796
797 wxString wxWebViewIE::GetPageText() const
798 {
799 wxCOMPtr<IHTMLDocument2> document(GetDocument());
800
801 if(document)
802 {
803 wxString text;
804 wxCOMPtr<IHTMLElement> body;
805 HRESULT hr = document->get_body(&body);
806 if(SUCCEEDED(hr))
807 {
808 BSTR out;
809 body->get_innerText(&out);
810 text = wxString(out);
811 }
812 return text;
813 }
814 else
815 {
816 return "";
817 }
818 }
819
820 void wxWebViewIE::RunScript(const wxString& javascript)
821 {
822 wxCOMPtr<IHTMLDocument2> document(GetDocument());
823
824 if(document)
825 {
826 wxCOMPtr<IHTMLWindow2> window;
827 wxString language = "javascript";
828 HRESULT hr = document->get_parentWindow(&window);
829 if(SUCCEEDED(hr))
830 {
831 VARIANT level;
832 VariantInit(&level);
833 V_VT(&level) = VT_EMPTY;
834 window->execScript(SysAllocString(javascript.wc_str()),
835 SysAllocString(language.wc_str()),
836 &level);
837 }
838 }
839 }
840
841 void wxWebViewIE::RegisterHandler(wxSharedPtr<wxWebViewHandler> handler)
842 {
843 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
844 if(urlMon.HasSymbol(wxT("CoInternetGetSession")))
845 {
846 typedef HRESULT (WINAPI *CoInternetGetSession_t)(DWORD, wxIInternetSession**, DWORD);
847 wxDYNLIB_FUNCTION(CoInternetGetSession_t, CoInternetGetSession, urlMon);
848
849 ClassFactory* cf = new ClassFactory(handler);
850 wxIInternetSession* session;
851 HRESULT res = (*pfnCoInternetGetSession)(0, &session, 0);
852 if(FAILED(res))
853 {
854 wxFAIL_MSG("Could not retrive internet session");
855 }
856
857 HRESULT hr = session->RegisterNameSpace(cf, CLSID_FileProtocol,
858 handler->GetName().wc_str(),
859 0, NULL, 0);
860 if(FAILED(hr))
861 {
862 wxFAIL_MSG("Could not register protocol");
863 }
864 m_factories.push_back(cf);
865 }
866 else
867 {
868 wxFAIL_MSG("urlmon does not contain CoInternetGetSession");
869 }
870 }
871
872 bool wxWebViewIE::CanExecCommand(wxString command) const
873 {
874 wxCOMPtr<IHTMLDocument2> document(GetDocument());
875
876 if(document)
877 {
878 VARIANT_BOOL enabled;
879
880 document->queryCommandEnabled(SysAllocString(command.wc_str()), &enabled);
881
882 return (enabled == VARIANT_TRUE);
883 }
884 else
885 {
886 return false;
887 }
888
889 }
890
891 void wxWebViewIE::ExecCommand(wxString command)
892 {
893 wxCOMPtr<IHTMLDocument2> document(GetDocument());
894
895 if(document)
896 {
897 document->execCommand(SysAllocString(command.wc_str()), VARIANT_FALSE, VARIANT(), NULL);
898 }
899 }
900
901 wxCOMPtr<IHTMLDocument2> wxWebViewIE::GetDocument() const
902 {
903 wxCOMPtr<IDispatch> dispatch;
904 wxCOMPtr<IHTMLDocument2> document;
905 HRESULT result = m_webBrowser->get_Document(&dispatch);
906 if(dispatch && SUCCEEDED(result))
907 {
908 //document is set to null automatically if the interface isn't supported
909 dispatch->QueryInterface(IID_IHTMLDocument2, (void**)&document);
910 }
911 return document;
912 }
913
914 bool wxWebViewIE::IsElementVisible(IHTMLElement* elm)
915 {
916 IHTMLCurrentStyle* style;
917 IHTMLElement *elm1 = elm;
918 IHTMLElement2 *elm2;
919 BSTR tmp_bstr;
920 bool is_visible = true;
921 //This method is not perfect but it does discover most of the hidden elements.
922 //so if a better solution is found, then please do improve.
923 while(elm1)
924 {
925 if(SUCCEEDED(elm1->QueryInterface(IID_IHTMLElement2, (void**) &elm2)))
926 {
927 if(SUCCEEDED(elm2->get_currentStyle(&style)))
928 {
929 //Check if the object has the style display:none.
930 if((style->get_display(&tmp_bstr) != S_OK) ||
931 (tmp_bstr != NULL && (_wcsicmp(tmp_bstr, L"none") == 0)))
932 {
933 is_visible = false;
934 }
935 //Check if the object has the style visibility:hidden.
936 if(is_visible && (style->get_visibility(&tmp_bstr) != S_OK) ||
937 (tmp_bstr != NULL && _wcsicmp(tmp_bstr, L"hidden") == 0))
938 {
939 is_visible = false;
940 }
941 style->Release();
942 }
943 elm2->Release();
944 }
945
946 //Lets check the object's parent element.
947 IHTMLElement* parent;
948 if(is_visible && SUCCEEDED(elm1->get_parentElement(&parent)))
949 {
950 elm1->Release();
951 elm1 = parent;
952 }
953 else
954 {
955 elm1->Release();
956 break;
957 }
958 }
959 return is_visible;
960 }
961
962 void wxWebViewIE::FindInternal(const wxString& text, int flags, int internal_flag)
963 {
964 IMarkupServices *pIMS;
965 IMarkupContainer *pIMC;
966 IMarkupPointer *ptrBegin, *ptrEnd;
967 IHTMLElement* elm;
968 long find_flag = 0;
969 IHTMLDocument2 *document = GetDocument();
970 //This function does the acutal work.
971 if(SUCCEEDED(document->QueryInterface(IID_IMarkupServices, (void **)&pIMS)))
972 {
973 if(SUCCEEDED(document->QueryInterface(IID_IMarkupContainer, (void **)&pIMC)))
974 {
975 BSTR attr_bstr = SysAllocString(L"style=\"background-color:#ffff00\"");
976 BSTR text_bstr = SysAllocString(text.wc_str());
977 pIMS->CreateMarkupPointer(&ptrBegin);
978 pIMS->CreateMarkupPointer(&ptrEnd);
979
980 ptrBegin->SetGravity(POINTER_GRAVITY_Right);
981 ptrBegin->MoveToContainer(pIMC, TRUE);
982 //Create the find flag from the wx one.
983 if(flags & wxWEB_VIEW_FIND_ENTIRE_WORD)
984 {
985 find_flag |= FINDTEXT_WHOLEWORD;
986 }
987 if(flags & wxWEB_VIEW_FIND_MATCH_CASE)
988 {
989 find_flag |= FINDTEXT_MATCHCASE;
990 }
991
992 //A little speed-up to avoid to re-alloc in the positions vector.
993 if(text.Len() < 3 && m_findPointers.capacity() < 500)
994 {
995 m_findPointers.reserve(text.Len() == 1 ? 1000 : 500);
996 }
997
998 while(ptrBegin->FindText(text_bstr, find_flag, ptrEnd, NULL) == S_OK)
999 {
1000 if(ptrBegin->CurrentScope(&elm) == S_OK)
1001 {
1002 if(IsElementVisible(elm))
1003 {
1004 //Highlight the word if the flag was set.
1005 if(flags & wxWEB_VIEW_FIND_HIGHLIGHT_RESULT)
1006 {
1007 IHTMLElement* pFontEl;
1008 pIMS->CreateElement(TAGID_FONT, attr_bstr, &pFontEl);
1009 pIMS->InsertElement(pFontEl, ptrBegin, ptrEnd);
1010 }
1011 if(internal_flag & wxWEB_VIEW_FIND_REMOVE_HIGHLIGHT)
1012 {
1013 IHTMLElement* pFontEl;
1014 ptrBegin->CurrentScope(&pFontEl);
1015 pIMS->RemoveElement(pFontEl);
1016 pFontEl->Release();
1017 }
1018 if(internal_flag & wxWEB_VIEW_FIND_ADD_POINTERS)
1019 {
1020 IMarkupPointer *cptrBegin, *cptrEnd;
1021 pIMS->CreateMarkupPointer(&cptrBegin);
1022 pIMS->CreateMarkupPointer(&cptrEnd);
1023 cptrBegin->MoveToPointer(ptrBegin);
1024 cptrEnd->MoveToPointer(ptrEnd);
1025 m_findPointers.push_back(wxFindPointers(cptrBegin,cptrEnd));
1026 }
1027 }
1028 elm->Release();
1029 }
1030 ptrBegin->MoveToPointer(ptrEnd);
1031 }
1032 //Clean up.
1033 SysFreeString(text_bstr);
1034 SysFreeString(attr_bstr);
1035 pIMC->Release();
1036 ptrBegin->Release();
1037 ptrEnd->Release();
1038 }
1039 pIMS->Release();
1040 }
1041 document->Release();
1042 }
1043
1044 long wxWebViewIE::FindNext(int direction)
1045 {
1046 //Don't bother if we have no pointers set.
1047 if(m_findPointers.empty())
1048 {
1049 return wxNOT_FOUND;
1050 }
1051 //Manage the find position and do some checks.
1052 if(direction > 0)
1053 {
1054 m_findPosition++;
1055 }
1056 else
1057 {
1058 m_findPosition--;
1059 }
1060
1061 if(m_findPosition >= (signed)m_findPointers.size())
1062 {
1063 if(m_findFlags & wxWEB_VIEW_FIND_WRAP)
1064 {
1065 m_findPosition = 0;
1066 }
1067 else
1068 {
1069 m_findPosition--;
1070 return wxNOT_FOUND;
1071 }
1072 }
1073 else if(m_findPosition < 0)
1074 {
1075 if(m_findFlags & wxWEB_VIEW_FIND_WRAP)
1076 {
1077 m_findPosition = m_findPointers.size()-1;
1078 }
1079 else
1080 {
1081 m_findPosition++;
1082 return wxNOT_FOUND;
1083 }
1084 }
1085 //some variables to use later on.
1086 IHTMLElement *body_element;
1087 IHTMLBodyElement *body;
1088 IHTMLTxtRange *range = NULL;
1089 IMarkupServices *pIMS;
1090 IHTMLDocument2 *document = GetDocument();
1091 long ret = -1;
1092 //Now try to create a range from the body.
1093 if(SUCCEEDED(document->get_body(&body_element)))
1094 {
1095 if(SUCCEEDED(body_element->QueryInterface(IID_IHTMLBodyElement,(void**)&body)))
1096 {
1097 if(SUCCEEDED(body->createTextRange(&range)))
1098 {
1099 //So far so good, now we try to position our find pointers.
1100 if(SUCCEEDED(document->QueryInterface(IID_IMarkupServices,(void **)&pIMS)))
1101 {
1102 IMarkupPointer *begin = m_findPointers[m_findPosition].begin, *end = m_findPointers[m_findPosition].end;
1103 if(pIMS->MoveRangeToPointers(begin,end,range) == S_OK && range->select() == S_OK)
1104 {
1105 ret = m_findPosition;
1106 }
1107 pIMS->Release();
1108 }
1109 range->Release();
1110 }
1111 body->Release();
1112 }
1113 body_element->Release();
1114 }
1115 document->Release();
1116 return ret;
1117 }
1118
1119 void wxWebViewIE::FindClear()
1120 {
1121 //Reset find variables.
1122 m_findText.Empty();
1123 m_findFlags = wxWEB_VIEW_FIND_DEFAULT;
1124 m_findPosition = -1;
1125
1126 //The m_findPointers contains pointers for the found text.
1127 //Since it uses ref counting we call release on the pointers first
1128 //before we remove them from the vector. In other words do not just
1129 //remove elements from m_findPointers without calling release first
1130 //or you will get a memory leak.
1131 size_t count = m_findPointers.size();
1132 for(size_t i = 0; i < count; i++)
1133 {
1134 m_findPointers[i].begin->Release();
1135 m_findPointers[i].end->Release();
1136 }
1137 m_findPointers.clear();
1138 }
1139
1140 bool wxWebViewIE::EnableControlFeature(long flag, bool enable)
1141 {
1142 #if wxUSE_DYNLIB_CLASS
1143
1144 wxDynamicLibrary urlMon(wxT("urlmon.dll"));
1145 if( urlMon.IsLoaded() &&
1146 urlMon.HasSymbol("CoInternetSetFeatureEnabled") &&
1147 urlMon.HasSymbol("CoInternetIsFeatureEnabled"))
1148 {
1149 typedef HRESULT (WINAPI *CoInternetSetFeatureEnabled_t)(DWORD, DWORD, BOOL);
1150 typedef HRESULT (WINAPI *CoInternetIsFeatureEnabled_t)(DWORD, DWORD);
1151
1152 wxDYNLIB_FUNCTION(CoInternetSetFeatureEnabled_t, CoInternetSetFeatureEnabled, urlMon);
1153 wxDYNLIB_FUNCTION(CoInternetIsFeatureEnabled_t, CoInternetIsFeatureEnabled, urlMon);
1154
1155 HRESULT hr = (*pfnCoInternetIsFeatureEnabled)(flag,
1156 0x2 /* SET_FEATURE_ON_PROCESS */);
1157 if((hr == S_OK && enable) || (hr == S_FALSE && !enable))
1158 return true;
1159
1160 hr = (*pfnCoInternetSetFeatureEnabled)(flag,
1161 0x2/* SET_FEATURE_ON_PROCESS */,
1162 (enable ? TRUE : FALSE));
1163 if ( FAILED(hr) )
1164 {
1165 wxLogApiError(wxT("CoInternetSetFeatureEnabled"), hr);
1166 return false;
1167 }
1168 return true;
1169 }
1170 return false;
1171 #else
1172 wxUnusedVar(flag);
1173 wxUnusedVar(enable);
1174 return false;
1175 #endif // wxUSE_DYNLIB_CLASS/!wxUSE_DYNLIB_CLASS
1176 }
1177
1178 void wxWebViewIE::onActiveXEvent(wxActiveXEvent& evt)
1179 {
1180 if (m_webBrowser == NULL) return;
1181
1182 switch (evt.GetDispatchId())
1183 {
1184 case DISPID_BEFORENAVIGATE2:
1185 {
1186 m_isBusy = true;
1187
1188 wxString url = evt[1].GetString();
1189 wxString target = evt[3].GetString();
1190
1191 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATING,
1192 GetId(), url, target);
1193
1194 //skip empty javascript events.
1195 if(url == "javascript:\"\"" && target.IsEmpty())
1196 {
1197 event.Veto();
1198 }
1199 else
1200 {
1201 event.SetEventObject(this);
1202 HandleWindowEvent(event);
1203 }
1204
1205 if (!event.IsAllowed())
1206 {
1207 wxActiveXEventNativeMSW* nativeParams =
1208 evt.GetNativeParameters();
1209 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[0]) = VARIANT_TRUE;
1210 }
1211
1212 // at this point, either the navigation event has been cancelled
1213 // and we're not busy, either it was accepted and IWebBrowser2's
1214 // Busy property will be true; so we don't need our override
1215 // flag anymore.
1216 m_isBusy = false;
1217
1218 break;
1219 }
1220
1221 case DISPID_NAVIGATECOMPLETE2:
1222 {
1223 wxString url = evt[1].GetString();
1224 // TODO: set target parameter if possible
1225 wxString target = wxEmptyString;
1226 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NAVIGATED,
1227 GetId(), url, target);
1228 event.SetEventObject(this);
1229 HandleWindowEvent(event);
1230 break;
1231 }
1232
1233 case DISPID_PROGRESSCHANGE:
1234 {
1235 // download progress
1236 break;
1237 }
1238
1239 case DISPID_DOCUMENTCOMPLETE:
1240 {
1241 //Only send a complete even if we are actually finished, this brings
1242 //the event in to line with webkit
1243 READYSTATE rs;
1244 m_webBrowser->get_ReadyState( &rs );
1245 if(rs != READYSTATE_COMPLETE)
1246 break;
1247
1248 wxString url = evt[1].GetString();
1249
1250 //As we are complete we also add to the history list, but not if the
1251 //page is not the main page, ie it is a subframe
1252 //We also have to check if we are loading a file:// url, if so we
1253 //need to change the comparison as ie passes back a different style
1254 //of url
1255 if(m_historyEnabled && !m_historyLoadingFromList &&
1256 (url == GetCurrentURL() ||
1257 (GetCurrentURL().substr(0, 4) == "file" &&
1258 wxFileSystem::URLToFileName(GetCurrentURL()).GetFullPath() == url)))
1259 {
1260 //If we are not at the end of the list, then erase everything
1261 //between us and the end before adding the new page
1262 if(m_historyPosition != static_cast<int>(m_historyList.size()) - 1)
1263 {
1264 m_historyList.erase(m_historyList.begin() + m_historyPosition + 1,
1265 m_historyList.end());
1266 }
1267 wxSharedPtr<wxWebViewHistoryItem> item(new wxWebViewHistoryItem(url, GetCurrentTitle()));
1268 m_historyList.push_back(item);
1269 m_historyPosition++;
1270 }
1271 //Reset as we are done now
1272 m_historyLoadingFromList = false;
1273 //Reset the find values.
1274 FindClear();
1275 // TODO: set target parameter if possible
1276 wxString target = wxEmptyString;
1277 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_LOADED, GetId(),
1278 url, target);
1279 event.SetEventObject(this);
1280 HandleWindowEvent(event);
1281 break;
1282 }
1283
1284 case DISPID_STATUSTEXTCHANGE:
1285 {
1286 break;
1287 }
1288
1289 case DISPID_TITLECHANGE:
1290 {
1291 wxString title = evt[0].GetString();
1292
1293 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_TITLE_CHANGED,
1294 GetId(), GetCurrentURL(), "");
1295 event.SetString(title);
1296 event.SetEventObject(this);
1297 HandleWindowEvent(event);
1298 break;
1299 }
1300
1301 case DISPID_NAVIGATEERROR:
1302 {
1303 wxWebViewNavigationError errorType = wxWEB_NAV_ERR_OTHER;
1304 wxString errorCode = "?";
1305 switch (evt[3].GetLong())
1306 {
1307 case INET_E_INVALID_URL: // (0x800C0002L or -2146697214)
1308 errorCode = "INET_E_INVALID_URL";
1309 errorType = wxWEB_NAV_ERR_REQUEST;
1310 break;
1311 case INET_E_NO_SESSION: // (0x800C0003L or -2146697213)
1312 errorCode = "INET_E_NO_SESSION";
1313 errorType = wxWEB_NAV_ERR_CONNECTION;
1314 break;
1315 case INET_E_CANNOT_CONNECT: // (0x800C0004L or -2146697212)
1316 errorCode = "INET_E_CANNOT_CONNECT";
1317 errorType = wxWEB_NAV_ERR_CONNECTION;
1318 break;
1319 case INET_E_RESOURCE_NOT_FOUND: // (0x800C0005L or -2146697211)
1320 errorCode = "INET_E_RESOURCE_NOT_FOUND";
1321 errorType = wxWEB_NAV_ERR_NOT_FOUND;
1322 break;
1323 case INET_E_OBJECT_NOT_FOUND: // (0x800C0006L or -2146697210)
1324 errorCode = "INET_E_OBJECT_NOT_FOUND";
1325 errorType = wxWEB_NAV_ERR_NOT_FOUND;
1326 break;
1327 case INET_E_DATA_NOT_AVAILABLE: // (0x800C0007L or -2146697209)
1328 errorCode = "INET_E_DATA_NOT_AVAILABLE";
1329 errorType = wxWEB_NAV_ERR_NOT_FOUND;
1330 break;
1331 case INET_E_DOWNLOAD_FAILURE: // (0x800C0008L or -2146697208)
1332 errorCode = "INET_E_DOWNLOAD_FAILURE";
1333 errorType = wxWEB_NAV_ERR_CONNECTION;
1334 break;
1335 case INET_E_AUTHENTICATION_REQUIRED: // (0x800C0009L or -2146697207)
1336 errorCode = "INET_E_AUTHENTICATION_REQUIRED";
1337 errorType = wxWEB_NAV_ERR_AUTH;
1338 break;
1339 case INET_E_NO_VALID_MEDIA: // (0x800C000AL or -2146697206)
1340 errorCode = "INET_E_NO_VALID_MEDIA";
1341 errorType = wxWEB_NAV_ERR_REQUEST;
1342 break;
1343 case INET_E_CONNECTION_TIMEOUT: // (0x800C000BL or -2146697205)
1344 errorCode = "INET_E_CONNECTION_TIMEOUT";
1345 errorType = wxWEB_NAV_ERR_CONNECTION;
1346 break;
1347 case INET_E_INVALID_REQUEST: // (0x800C000CL or -2146697204)
1348 errorCode = "INET_E_INVALID_REQUEST";
1349 errorType = wxWEB_NAV_ERR_REQUEST;
1350 break;
1351 case INET_E_UNKNOWN_PROTOCOL: // (0x800C000DL or -2146697203)
1352 errorCode = "INET_E_UNKNOWN_PROTOCOL";
1353 errorType = wxWEB_NAV_ERR_REQUEST;
1354 break;
1355 case INET_E_SECURITY_PROBLEM: // (0x800C000EL or -2146697202)
1356 errorCode = "INET_E_SECURITY_PROBLEM";
1357 errorType = wxWEB_NAV_ERR_SECURITY;
1358 break;
1359 case INET_E_CANNOT_LOAD_DATA: // (0x800C000FL or -2146697201)
1360 errorCode = "INET_E_CANNOT_LOAD_DATA";
1361 errorType = wxWEB_NAV_ERR_OTHER;
1362 break;
1363 case INET_E_CANNOT_INSTANTIATE_OBJECT:
1364 // CoCreateInstance will return an error code if this happens,
1365 // we'll handle this above.
1366 return;
1367 break;
1368 case INET_E_REDIRECT_FAILED: // (0x800C0014L or -2146697196)
1369 errorCode = "INET_E_REDIRECT_FAILED";
1370 errorType = wxWEB_NAV_ERR_OTHER;
1371 break;
1372 case INET_E_REDIRECT_TO_DIR: // (0x800C0015L or -2146697195)
1373 errorCode = "INET_E_REDIRECT_TO_DIR";
1374 errorType = wxWEB_NAV_ERR_REQUEST;
1375 break;
1376 case INET_E_CANNOT_LOCK_REQUEST: // (0x800C0016L or -2146697194)
1377 errorCode = "INET_E_CANNOT_LOCK_REQUEST";
1378 errorType = wxWEB_NAV_ERR_OTHER;
1379 break;
1380 case INET_E_USE_EXTEND_BINDING: // (0x800C0017L or -2146697193)
1381 errorCode = "INET_E_USE_EXTEND_BINDING";
1382 errorType = wxWEB_NAV_ERR_OTHER;
1383 break;
1384 case INET_E_TERMINATED_BIND: // (0x800C0018L or -2146697192)
1385 errorCode = "INET_E_TERMINATED_BIND";
1386 errorType = wxWEB_NAV_ERR_OTHER;
1387 break;
1388 case INET_E_INVALID_CERTIFICATE: // (0x800C0019L or -2146697191)
1389 errorCode = "INET_E_INVALID_CERTIFICATE";
1390 errorType = wxWEB_NAV_ERR_CERTIFICATE;
1391 break;
1392 case INET_E_CODE_DOWNLOAD_DECLINED: // (0x800C0100L or -2146696960)
1393 errorCode = "INET_E_CODE_DOWNLOAD_DECLINED";
1394 errorType = wxWEB_NAV_ERR_USER_CANCELLED;
1395 break;
1396 case INET_E_RESULT_DISPATCHED: // (0x800C0200L or -2146696704)
1397 // cancel request cancelled...
1398 errorCode = "INET_E_RESULT_DISPATCHED";
1399 errorType = wxWEB_NAV_ERR_OTHER;
1400 break;
1401 case INET_E_CANNOT_REPLACE_SFP_FILE: // (0x800C0300L or -2146696448)
1402 errorCode = "INET_E_CANNOT_REPLACE_SFP_FILE";
1403 errorType = wxWEB_NAV_ERR_SECURITY;
1404 break;
1405 case INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY:
1406 errorCode = "INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY";
1407 errorType = wxWEB_NAV_ERR_SECURITY;
1408 break;
1409 case INET_E_CODE_INSTALL_SUPPRESSED:
1410 errorCode = "INET_E_CODE_INSTALL_SUPPRESSED";
1411 errorType = wxWEB_NAV_ERR_SECURITY;
1412 break;
1413 }
1414
1415 wxString url = evt[1].GetString();
1416 wxString target = evt[2].GetString();
1417 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_ERROR, GetId(),
1418 url, target);
1419 event.SetEventObject(this);
1420 event.SetInt(errorType);
1421 event.SetString(errorCode);
1422 HandleWindowEvent(event);
1423 break;
1424 }
1425 case DISPID_NEWWINDOW3:
1426 {
1427 wxString url = evt[4].GetString();
1428
1429 wxWebViewEvent event(wxEVT_COMMAND_WEB_VIEW_NEWWINDOW,
1430 GetId(), url, wxEmptyString);
1431 event.SetEventObject(this);
1432 HandleWindowEvent(event);
1433
1434 //We always cancel this event otherwise an Internet Exporer window
1435 //is opened for the url
1436 wxActiveXEventNativeMSW* nativeParams = evt.GetNativeParameters();
1437 *V_BOOLREF(&nativeParams->pDispParams->rgvarg[3]) = VARIANT_TRUE;
1438 break;
1439 }
1440 }
1441
1442 evt.Skip();
1443 }
1444
1445 VirtualProtocol::VirtualProtocol(wxSharedPtr<wxWebViewHandler> handler)
1446 {
1447 m_file = NULL;
1448 m_handler = handler;
1449 }
1450
1451 BEGIN_IID_TABLE(VirtualProtocol)
1452 ADD_IID(Unknown)
1453 ADD_RAW_IID(wxIID_IInternetProtocolRoot)
1454 ADD_RAW_IID(wxIID_IInternetProtocol)
1455 END_IID_TABLE;
1456
1457 IMPLEMENT_IUNKNOWN_METHODS(VirtualProtocol)
1458
1459 HRESULT STDMETHODCALLTYPE VirtualProtocol::Start(LPCWSTR szUrl, wxIInternetProtocolSink *pOIProtSink,
1460 wxIInternetBindInfo *pOIBindInfo, DWORD grfPI,
1461 HANDLE_PTR dwReserved)
1462 {
1463 wxUnusedVar(szUrl);
1464 wxUnusedVar(pOIBindInfo);
1465 wxUnusedVar(grfPI);
1466 wxUnusedVar(dwReserved);
1467 m_protocolSink = pOIProtSink;
1468
1469 //We get the file itself from the protocol handler
1470 m_file = m_handler->GetFile(szUrl);
1471
1472
1473 if(!m_file)
1474 return INET_E_RESOURCE_NOT_FOUND;
1475
1476 //We return the stream length for current and total size as we can always
1477 //read the whole file from the stream
1478 wxFileOffset length = m_file->GetStream()->GetLength();
1479 m_protocolSink->ReportData(wxBSCF_FIRSTDATANOTIFICATION |
1480 wxBSCF_DATAFULLYAVAILABLE |
1481 wxBSCF_LASTDATANOTIFICATION,
1482 length, length);
1483 return S_OK;
1484 }
1485
1486 HRESULT STDMETHODCALLTYPE VirtualProtocol::Read(void *pv, ULONG cb, ULONG *pcbRead)
1487 {
1488 //If the file is null we return false to indicte it is finished
1489 if(!m_file)
1490 return S_FALSE;
1491
1492 wxStreamError err = m_file->GetStream()->Read(pv, cb).GetLastError();
1493 *pcbRead = m_file->GetStream()->LastRead();
1494
1495 if(err == wxSTREAM_NO_ERROR)
1496 {
1497 if(*pcbRead < cb)
1498 {
1499 wxDELETE(m_file);
1500 m_protocolSink->ReportResult(S_OK, 0, NULL);
1501 }
1502 //As we are not eof there is more data
1503 return S_OK;
1504 }
1505 else if(err == wxSTREAM_EOF)
1506 {
1507 wxDELETE(m_file);
1508 m_protocolSink->ReportResult(S_OK, 0, NULL);
1509 //We are eof and so finished
1510 return S_OK;
1511 }
1512 else if(err == wxSTREAM_READ_ERROR)
1513 {
1514 wxDELETE(m_file);
1515 return INET_E_DOWNLOAD_FAILURE;
1516 }
1517 else
1518 {
1519 //Dummy return to surpress a compiler warning
1520 wxFAIL;
1521 return INET_E_DOWNLOAD_FAILURE;
1522 }
1523 }
1524
1525 BEGIN_IID_TABLE(ClassFactory)
1526 ADD_IID(Unknown)
1527 ADD_IID(ClassFactory)
1528 END_IID_TABLE;
1529
1530 IMPLEMENT_IUNKNOWN_METHODS(ClassFactory)
1531
1532 HRESULT STDMETHODCALLTYPE ClassFactory::CreateInstance(IUnknown* pUnkOuter, REFIID riid,
1533 void ** ppvObject)
1534 {
1535 if (pUnkOuter)
1536 return CLASS_E_NOAGGREGATION;
1537 VirtualProtocol* vp = new VirtualProtocol(m_handler);
1538 vp->AddRef();
1539 HRESULT hr = vp->QueryInterface(riid, ppvObject);
1540 vp->Release();
1541 return hr;
1542
1543 }
1544
1545 STDMETHODIMP ClassFactory::LockServer(BOOL fLock)
1546 {
1547 wxUnusedVar(fLock);
1548 return S_OK;
1549 }
1550
1551 wxIEContainer::wxIEContainer(wxWindow *parent, REFIID iid, IUnknown *pUnk,
1552 DocHostUIHandler* uiHandler) :
1553 wxActiveXContainer(parent,iid,pUnk)
1554 {
1555 m_uiHandler = uiHandler;
1556 }
1557
1558 wxIEContainer::~wxIEContainer()
1559 {
1560 }
1561
1562 bool wxIEContainer::QueryClientSiteInterface(REFIID iid, void **_interface,
1563 const char *&desc)
1564 {
1565 if (m_uiHandler && IsEqualIID(iid, wxIID_IDocHostUIHandler))
1566 {
1567 *_interface = (IUnknown *) (wxIDocHostUIHandler *) m_uiHandler;
1568 desc = "IDocHostUIHandler";
1569 return true;
1570 }
1571 return false;
1572 }
1573
1574 HRESULT wxSTDCALL DocHostUIHandler::ShowContextMenu(DWORD dwID, POINT *ppt,
1575 IUnknown *pcmdtReserved,
1576 IDispatch *pdispReserved)
1577 {
1578 wxUnusedVar(dwID);
1579 wxUnusedVar(ppt);
1580 wxUnusedVar(pcmdtReserved);
1581 wxUnusedVar(pdispReserved);
1582 return E_NOTIMPL;
1583 }
1584
1585 HRESULT wxSTDCALL DocHostUIHandler::GetHostInfo(DOCHOSTUIINFO *pInfo)
1586 {
1587 //don't show 3d border and enable themes.
1588 pInfo->dwFlags = pInfo->dwFlags | DOCHOSTUIFLAG_NO3DBORDER | DOCHOSTUIFLAG_THEME;
1589 return S_OK;
1590 }
1591
1592 HRESULT wxSTDCALL DocHostUIHandler::ShowUI(DWORD dwID,
1593 IOleInPlaceActiveObject *pActiveObject,
1594 IOleCommandTarget *pCommandTarget,
1595 IOleInPlaceFrame *pFrame,
1596 IOleInPlaceUIWindow *pDoc)
1597 {
1598 wxUnusedVar(dwID);
1599 wxUnusedVar(pActiveObject);
1600 wxUnusedVar(pCommandTarget);
1601 wxUnusedVar(pFrame);
1602 wxUnusedVar(pDoc);
1603 return S_FALSE;
1604 }
1605
1606 HRESULT wxSTDCALL DocHostUIHandler::HideUI(void)
1607 {
1608 return E_NOTIMPL;
1609 }
1610
1611 HRESULT wxSTDCALL DocHostUIHandler::UpdateUI(void)
1612 {
1613 return E_NOTIMPL;
1614 }
1615
1616 HRESULT wxSTDCALL DocHostUIHandler::EnableModeless(BOOL fEnable)
1617 {
1618 wxUnusedVar(fEnable);
1619 return E_NOTIMPL;
1620 }
1621
1622 HRESULT wxSTDCALL DocHostUIHandler::OnDocWindowActivate(BOOL fActivate)
1623 {
1624 wxUnusedVar(fActivate);
1625 return E_NOTIMPL;
1626 }
1627
1628 HRESULT wxSTDCALL DocHostUIHandler::OnFrameWindowActivate(BOOL fActivate)
1629 {
1630 wxUnusedVar(fActivate);
1631 return E_NOTIMPL;
1632 }
1633
1634 HRESULT wxSTDCALL DocHostUIHandler::ResizeBorder(LPCRECT prcBorder,
1635 IOleInPlaceUIWindow *pUIWindow,
1636 BOOL fFrameWindow)
1637 {
1638 wxUnusedVar(prcBorder);
1639 wxUnusedVar(pUIWindow);
1640 wxUnusedVar(fFrameWindow);
1641 return E_NOTIMPL;
1642 }
1643
1644 HRESULT wxSTDCALL DocHostUIHandler::TranslateAccelerator(LPMSG lpMsg,
1645 const GUID *pguidCmdGroup,
1646 DWORD nCmdID)
1647 {
1648 if(lpMsg && lpMsg->message == WM_KEYDOWN)
1649 {
1650 //control is down?
1651 if((GetKeyState(VK_CONTROL) & 0x8000 ))
1652 {
1653 //skip the accelerators used by the control
1654 switch(lpMsg->wParam)
1655 {
1656 case 'F':
1657 case 'L':
1658 case 'N':
1659 case 'O':
1660 case 'P':
1661 return S_OK;
1662 }
1663 }
1664 //skip F5
1665 if(lpMsg->wParam == VK_F5)
1666 {
1667 return S_OK;
1668 }
1669 }
1670
1671 wxUnusedVar(pguidCmdGroup);
1672 wxUnusedVar(nCmdID);
1673 return E_NOTIMPL;
1674 }
1675
1676 HRESULT wxSTDCALL DocHostUIHandler::GetOptionKeyPath(LPOLESTR *pchKey,DWORD dw)
1677 {
1678 wxUnusedVar(pchKey);
1679 wxUnusedVar(dw);
1680 return E_NOTIMPL;
1681 }
1682
1683 HRESULT wxSTDCALL DocHostUIHandler::GetDropTarget(IDropTarget *pDropTarget,
1684 IDropTarget **ppDropTarget)
1685 {
1686 wxUnusedVar(pDropTarget);
1687 wxUnusedVar(ppDropTarget);
1688 return E_NOTIMPL;
1689 }
1690
1691 HRESULT wxSTDCALL DocHostUIHandler::GetExternal(IDispatch **ppDispatch)
1692 {
1693 wxUnusedVar(ppDispatch);
1694 return E_NOTIMPL;
1695 }
1696
1697 HRESULT wxSTDCALL DocHostUIHandler::TranslateUrl(DWORD dwTranslate,
1698 OLECHAR *pchURLIn,
1699 OLECHAR **ppchURLOut)
1700 {
1701 wxUnusedVar(dwTranslate);
1702 wxUnusedVar(pchURLIn);
1703 wxUnusedVar(ppchURLOut);
1704 return E_NOTIMPL;
1705 }
1706
1707 HRESULT wxSTDCALL DocHostUIHandler::FilterDataObject(IDataObject *pDO, IDataObject **ppDORet)
1708 {
1709 wxUnusedVar(pDO);
1710 wxUnusedVar(ppDORet);
1711 return E_NOTIMPL;
1712 }
1713
1714 BEGIN_IID_TABLE(DocHostUIHandler)
1715 ADD_IID(Unknown)
1716 ADD_RAW_IID(wxIID_IDocHostUIHandler)
1717 END_IID_TABLE;
1718
1719 IMPLEMENT_IUNKNOWN_METHODS(DocHostUIHandler)
1720
1721 #endif // wxUSE_WEBVIEW && wxUSE_WEBVIEW_IE