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