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