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