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