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